bump it bop it upgrade it (rn 79/expo 53) (#8281)
* basic bumps * more tweaking * fix rn patch * fix crop picker patch * fix media library patch * rm unnecessary patch * fix notifications patch * update bottomsheet * Update withAppDelegateReferrer.js * Delete withNoBundleCompression.js * rm withNoBundleCompression plugin * rm findLast shim * metro package exports is enabled by default * update react/react-dom/react-compiler * fix reanimated issue * vendor expo-ized emoji popup * fix types * hackfix view full thread * Update EmojiPickerModule.podspec * more upgrades * fix multiformats package version * add baseurl * bump mmkv * bumps * update react-keyed-flatten-children * bump locale packages * fix emoji picker dark mode * rn upgrades * Revert "bump locale packages" This reverts commit fc82f0f173032127dd7c18ed0316ae26f53db51d. * upgrade testing-library * rm test renderer * update patch name minors * rm findNodeHandle from tabbar * only do scrollview tag thing on ios * disable package exports * update expo notifications handler * memoize emoji picker styles * fix tests, mock multiformats * bump some dev deps with RC versions * completely rearchitect toasts * rm logs * layout animation config for composer footer * disable autolinking for patched libs * undo lingui changes * version bump from release candidate to 0.1 * update atproto deps * rm @did-plc/server * fix key issue (maybe) * move URL polyfill to the polyfill file * fix yarn lock * upgrade to 53.0.3 * reanimated layout anim bug patch * workletize a function that wasn't getting autoworkletized anymore (#8309) * bump to expo 53.0.4 * bump RN to 0.79.2 * fix yarn lock ci * Revert "completely rearchitect toasts" This reverts commit 2e2fcaeeed527580a6c485718544b85e8b4f52b9. * final upgrades * chore: cleanup yarn lock * prettier --------- Co-authored-by: Samuel Newman <mozzius@protonmail.com>
This commit is contained in:
parent
46ea3fdbee
commit
544f7befe0
3
__mocks__/multiformats/cid.js
Normal file
3
__mocks__/multiformats/cid.js
Normal file
@ -0,0 +1,3 @@
|
||||
export const CID = jest.fn().mockImplementation(() => {
|
||||
return {}
|
||||
})
|
7
__mocks__/multiformats/hashes/hasher.js
Normal file
7
__mocks__/multiformats/hashes/hasher.js
Normal file
@ -0,0 +1,7 @@
|
||||
export const from = jest.fn().mockImplementation(() => {
|
||||
return {
|
||||
digest: jest.fn().mockImplementation(() => {
|
||||
return Promise.resolve('')
|
||||
}),
|
||||
}
|
||||
})
|
@ -1,11 +1,11 @@
|
||||
import {RichText} from '@atproto/api'
|
||||
|
||||
import {parseEmbedPlayerFromUrl} from 'lib/strings/embed-player'
|
||||
import {parseEmbedPlayerFromUrl} from '#/lib/strings/embed-player'
|
||||
import {
|
||||
createStarterPackGooglePlayUri,
|
||||
createStarterPackLinkFromAndroidReferrer,
|
||||
parseStarterPackUri,
|
||||
} from 'lib/strings/starter-pack'
|
||||
} from '#/lib/strings/starter-pack'
|
||||
import {cleanError} from '../../src/lib/strings/errors'
|
||||
import {createFullHandle, makeValidHandle} from '../../src/lib/strings/handles'
|
||||
import {enforceLen} from '../../src/lib/strings/helpers'
|
||||
|
@ -193,6 +193,7 @@ module.exports = function (_config) {
|
||||
plugins: [
|
||||
'expo-video',
|
||||
'expo-localization',
|
||||
'expo-web-browser',
|
||||
[
|
||||
'react-native-edge-to-edge',
|
||||
{android: {enforceNavigationBarContrast: false}},
|
||||
@ -242,10 +243,8 @@ module.exports = function (_config) {
|
||||
'./plugins/withAndroidStylesAccentColorPlugin.js',
|
||||
'./plugins/withAndroidDayNightThemePlugin.js',
|
||||
'./plugins/withAndroidNoJitpackPlugin.js',
|
||||
'./plugins/withNoBundleCompression.js',
|
||||
'./plugins/shareExtension/withShareExtensions.js',
|
||||
'./plugins/notificationsExtension/withNotificationsExtension.js',
|
||||
'./plugins/withAppDelegateReferrer.js',
|
||||
[
|
||||
'expo-font',
|
||||
{
|
||||
|
@ -17,7 +17,7 @@ module.exports = function (api) {
|
||||
],
|
||||
plugins: [
|
||||
'macros',
|
||||
['babel-plugin-react-compiler', {target: '18'}],
|
||||
['babel-plugin-react-compiler', {target: '19'}],
|
||||
[
|
||||
'module:react-native-dotenv',
|
||||
{
|
||||
@ -37,10 +37,6 @@ module.exports = function (api) {
|
||||
alias: {
|
||||
// This needs to be mirrored in tsconfig.json
|
||||
'#': './src',
|
||||
lib: './src/lib',
|
||||
platform: './src/platform',
|
||||
state: './src/state',
|
||||
view: './src/view',
|
||||
crypto: './src/platform/crypto.ts',
|
||||
},
|
||||
},
|
||||
|
@ -15,7 +15,7 @@ This is NOT required when developing for web.
|
||||
|
||||
- Set up your environment [using the expo instructions](https://docs.expo.dev/guides/local-app-development/).
|
||||
- make sure that the JAVA_HOME points to the zulu-17 directory in your `.zshrc` or `.bashrc` file: `export JAVA_HOME=/Library/Java/JavaVirtualMachines/zulu-17.jdk/Contents/Home`. DO NOT use another JDK or you will encounter build errors.
|
||||
- If you're running macOS, make sure you are running the correct versions of Ruby and Cocoapods:-
|
||||
- If you're running macOS, make sure you are running the correct versions of Ruby and Cocoapods:-
|
||||
- If you are using Apple Silicon and this is the first time you are building for RN 0.74+, you may need to run:
|
||||
- `arch -arm64 brew install llvm`
|
||||
- `sudo gem install ffi`
|
||||
@ -33,7 +33,7 @@ This is NOT required when developing for web.
|
||||
- After initial setup:
|
||||
- Copy `google-services.json.example` to `google-services.json` or provide your own `google-services.json`. (A real firebase project is NOT required)
|
||||
- `npx expo prebuild` -> you will also need to run this anytime `app.json` or native `package.json` deps change
|
||||
|
||||
|
||||
### Running the Native App
|
||||
|
||||
- iOS: `yarn ios`
|
||||
@ -162,6 +162,9 @@ See [testing.md](./testing.md).
|
||||
`./platform/polyfills.*.ts` adds polyfills to the environment. Currently, this includes:
|
||||
|
||||
- TextEncoder / TextDecoder
|
||||
- react-native-url-polyfill
|
||||
- Array#findLast (on web)
|
||||
- atob (on native)
|
||||
|
||||
### Sentry sourcemaps
|
||||
|
||||
|
@ -16,22 +16,21 @@ if (process.env.BSKY_PROFILE) {
|
||||
|
||||
cfg.resolver.assetExts = [...cfg.resolver.assetExts, 'woff2']
|
||||
|
||||
// Enabled by default in RN 0.79+, but this breaks Lingui + others
|
||||
cfg.resolver.unstable_enablePackageExports = false
|
||||
|
||||
cfg.resolver.resolveRequest = (context, moduleName, platform) => {
|
||||
// HACK: manually resolve a few packages that use `exports` in `package.json`.
|
||||
// A proper solution is to enable `unstable_enablePackageExports` but this needs careful testing.
|
||||
if (moduleName.startsWith('multiformats/hashes/hasher')) {
|
||||
return context.resolveRequest(
|
||||
context,
|
||||
'multiformats/dist/src/hashes/hasher',
|
||||
'multiformats/cjs/src/hashes/hasher',
|
||||
platform,
|
||||
)
|
||||
}
|
||||
if (moduleName.startsWith('multiformats/cid')) {
|
||||
return context.resolveRequest(
|
||||
context,
|
||||
'multiformats/dist/src/cid',
|
||||
platform,
|
||||
)
|
||||
return context.resolveRequest(context, 'multiformats/cjs/src/cid', platform)
|
||||
}
|
||||
if (moduleName === '@ipld/dag-cbor') {
|
||||
return context.resolveRequest(context, '@ipld/dag-cbor/src', platform)
|
||||
|
@ -317,6 +317,9 @@ class BottomSheetView(
|
||||
// View overrides to pass to DialogRootViewGroup instead
|
||||
|
||||
override fun dispatchProvideStructure(structure: ViewStructure?) {
|
||||
if (structure == null) {
|
||||
return
|
||||
}
|
||||
dialogRootViewGroup.dispatchProvideStructure(structure)
|
||||
}
|
||||
|
||||
|
@ -139,19 +139,7 @@ class DialogRootViewGroup(
|
||||
return super.onHoverEvent(event)
|
||||
}
|
||||
|
||||
@Deprecated("Deprecated in Java")
|
||||
override fun onChildStartedNativeGesture(ev: MotionEvent?) {
|
||||
eventDispatcher?.let {
|
||||
if (ev != null) {
|
||||
jSTouchDispatcher.onChildStartedNativeGesture(ev, it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onChildStartedNativeGesture(
|
||||
childView: View,
|
||||
ev: MotionEvent,
|
||||
) {
|
||||
override fun onChildStartedNativeGesture(childView: View?, ev: MotionEvent) {
|
||||
eventDispatcher?.let { jSTouchDispatcher.onChildStartedNativeGesture(ev, it) }
|
||||
jSPointerDispatcher?.onChildStartedNativeGesture(childView, ev, eventDispatcher)
|
||||
}
|
||||
|
@ -10,7 +10,7 @@ Pod::Spec.new do |s|
|
||||
s.static_framework = true
|
||||
|
||||
s.dependency 'ExpoModulesCore'
|
||||
s.dependency 'SDWebImage', '~> 5.19.1'
|
||||
s.dependency 'SDWebImage', '~> 5.21.0'
|
||||
s.dependency 'SDWebImageWebPCoder', '~> 0.14.6'
|
||||
|
||||
# Swift/Objective-C compatibility
|
||||
|
9
modules/expo-emoji-picker/LICENSE
Normal file
9
modules/expo-emoji-picker/LICENSE
Normal file
@ -0,0 +1,9 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2025 Alan Hughes
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
3
modules/expo-emoji-picker/README.md
Normal file
3
modules/expo-emoji-picker/README.md
Normal file
@ -0,0 +1,3 @@
|
||||
# expo-emoji-picker
|
||||
|
||||
Based on [react-native-emoji-popup](https://github.com/okwasniewski/react-native-emoji-popup) and [expo-emoji-picker](https://github.com/alanjhughes/expo-emoji-picker)
|
46
modules/expo-emoji-picker/android/build.gradle
Normal file
46
modules/expo-emoji-picker/android/build.gradle
Normal file
@ -0,0 +1,46 @@
|
||||
apply plugin: 'com.android.library'
|
||||
|
||||
group = 'expo.community.modules.emojipicker'
|
||||
version = '0.1.0'
|
||||
|
||||
def expoModulesCorePlugin = new File(project(":expo-modules-core").projectDir.absolutePath, "ExpoModulesCorePlugin.gradle")
|
||||
apply from: expoModulesCorePlugin
|
||||
applyKotlinExpoModulesCorePlugin()
|
||||
useCoreDependencies()
|
||||
useExpoPublishing()
|
||||
|
||||
// If you want to use the managed Android SDK versions from expo-modules-core, set this to true.
|
||||
// The Android SDK versions will be bumped from time to time in SDK releases and may introduce breaking changes in your module code.
|
||||
// Most of the time, you may like to manage the Android SDK versions yourself.
|
||||
def useManagedAndroidSdkVersions = false
|
||||
if (useManagedAndroidSdkVersions) {
|
||||
useDefaultAndroidSdkVersions()
|
||||
} else {
|
||||
buildscript {
|
||||
// Simple helper that allows the root project to override versions declared by this library.
|
||||
ext.safeExtGet = { prop, fallback ->
|
||||
rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback
|
||||
}
|
||||
}
|
||||
project.android {
|
||||
compileSdkVersion safeExtGet("compileSdkVersion", 34)
|
||||
defaultConfig {
|
||||
minSdkVersion safeExtGet("minSdkVersion", 21)
|
||||
targetSdkVersion safeExtGet("targetSdkVersion", 34)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
android {
|
||||
namespace "expo.community.modules.emojipicker"
|
||||
defaultConfig {
|
||||
versionCode 1
|
||||
versionName "0.1.0"
|
||||
}
|
||||
lintOptions {
|
||||
abortOnError false
|
||||
}
|
||||
dependencies {
|
||||
implementation "androidx.emoji2:emoji2-emojipicker:1.5.0"
|
||||
}
|
||||
}
|
@ -0,0 +1,2 @@
|
||||
<manifest>
|
||||
</manifest>
|
@ -0,0 +1,15 @@
|
||||
package expo.community.modules.emojipicker
|
||||
|
||||
import expo.modules.kotlin.modules.Module
|
||||
import expo.modules.kotlin.modules.ModuleDefinition
|
||||
import java.net.URL
|
||||
|
||||
class EmojiPickerModule : Module() {
|
||||
override fun definition() = ModuleDefinition {
|
||||
Name("EmojiPicker")
|
||||
|
||||
View(EmojiPickerModuleView::class) {
|
||||
Events("onEmojiSelected")
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
package expo.community.modules.emojipicker
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.content.res.Configuration
|
||||
import androidx.emoji2.emojipicker.EmojiPickerView
|
||||
import expo.modules.kotlin.AppContext
|
||||
import expo.modules.kotlin.viewevent.EventDispatcher
|
||||
import expo.modules.kotlin.views.ExpoView
|
||||
|
||||
|
||||
@SuppressLint("ViewConstructor")
|
||||
class EmojiPickerModuleView(context: Context, appContext: AppContext) :
|
||||
ExpoView(context, appContext) {
|
||||
private var emojiView: EmojiPickerView = EmojiPickerView(context)
|
||||
private val onEmojiSelected by EventDispatcher()
|
||||
|
||||
init {
|
||||
setupView()
|
||||
}
|
||||
|
||||
private fun setupView() {
|
||||
addView(
|
||||
emojiView, LayoutParams(
|
||||
LayoutParams.MATCH_PARENT,
|
||||
LayoutParams.MATCH_PARENT
|
||||
)
|
||||
)
|
||||
|
||||
emojiView.setOnEmojiPickedListener { emoji ->
|
||||
onEmojiSelected(mapOf("emoji" to emoji.emoji))
|
||||
}
|
||||
}
|
||||
|
||||
override fun onConfigurationChanged(newConfig: Configuration?) {
|
||||
super.onConfigurationChanged(newConfig)
|
||||
removeView(emojiView)
|
||||
setupView()
|
||||
}
|
||||
}
|
9
modules/expo-emoji-picker/expo-module.config.json
Normal file
9
modules/expo-emoji-picker/expo-module.config.json
Normal file
@ -0,0 +1,9 @@
|
||||
{
|
||||
"platforms": ["apple", "android"],
|
||||
"apple": {
|
||||
"modules": ["EmojiPickerModule"]
|
||||
},
|
||||
"android": {
|
||||
"modules": ["expo.community.modules.emojipicker.EmojiPickerModule"]
|
||||
}
|
||||
}
|
3
modules/expo-emoji-picker/index.ts
Normal file
3
modules/expo-emoji-picker/index.ts
Normal file
@ -0,0 +1,3 @@
|
||||
export {default as EmojiPicker} from './src/EmojiPicker'
|
||||
export {default} from './src/EmojiPickerModule'
|
||||
export * from './src/EmojiPickerModule.types'
|
25
modules/expo-emoji-picker/ios/EmojiPickerModule.podspec
Normal file
25
modules/expo-emoji-picker/ios/EmojiPickerModule.podspec
Normal file
@ -0,0 +1,25 @@
|
||||
Pod::Spec.new do |s|
|
||||
s.name = 'EmojiPickerModule'
|
||||
s.version = '1.0.0'
|
||||
s.summary = 'An emoji picker for use in Bluesky'
|
||||
s.description = 'An emoji picker for use in Bluesky'
|
||||
s.author = 'alanjhughes'
|
||||
s.homepage = 'https://github.com/bluesky-social/social-app'
|
||||
s.platforms = {
|
||||
:ios => '15.1',
|
||||
:tvos => '15.1'
|
||||
}
|
||||
s.source = { git: '' }
|
||||
s.swift_version = '5.4'
|
||||
s.static_framework = true
|
||||
|
||||
s.dependency 'ExpoModulesCore'
|
||||
s.dependency 'MCEmojiPicker'
|
||||
|
||||
# Swift/Objective-C compatibility
|
||||
s.pod_target_xcconfig = {
|
||||
'DEFINES_MODULE' => 'YES',
|
||||
}
|
||||
|
||||
s.source_files = "**/*.{h,m,mm,swift,hpp,cpp}"
|
||||
end
|
11
modules/expo-emoji-picker/ios/EmojiPickerModule.swift
Normal file
11
modules/expo-emoji-picker/ios/EmojiPickerModule.swift
Normal file
@ -0,0 +1,11 @@
|
||||
import ExpoModulesCore
|
||||
|
||||
public class EmojiPickerModule: Module {
|
||||
public func definition() -> ModuleDefinition {
|
||||
Name("EmojiPicker")
|
||||
|
||||
View(EmojiPickerView.self) {
|
||||
Events("onEmojiSelected")
|
||||
}
|
||||
}
|
||||
}
|
30
modules/expo-emoji-picker/ios/EmojiPickerView.swift
Normal file
30
modules/expo-emoji-picker/ios/EmojiPickerView.swift
Normal file
@ -0,0 +1,30 @@
|
||||
import ExpoModulesCore
|
||||
import WebKit
|
||||
import MCEmojiPicker
|
||||
|
||||
class EmojiPickerView: ExpoView, MCEmojiPickerDelegate {
|
||||
let onEmojiSelected = EventDispatcher()
|
||||
|
||||
override func layoutSubviews() {
|
||||
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(handleTap(_:)))
|
||||
self.addGestureRecognizer(tapGesture)
|
||||
}
|
||||
|
||||
@objc func handleTap(_ gesture: UITapGestureRecognizer) {
|
||||
presentEmojiPicker()
|
||||
}
|
||||
|
||||
func presentEmojiPicker() {
|
||||
let emojiPicker = MCEmojiPickerViewController()
|
||||
let reactRootVC = reactViewController()
|
||||
emojiPicker.sourceView = self
|
||||
emojiPicker.delegate = self
|
||||
reactRootVC?.present(emojiPicker, animated: true)
|
||||
}
|
||||
|
||||
func didGetEmoji(emoji: String) {
|
||||
onEmojiSelected([
|
||||
"emoji": emoji
|
||||
])
|
||||
}
|
||||
}
|
28
modules/expo-emoji-picker/src/EmojiPicker.android.tsx
Normal file
28
modules/expo-emoji-picker/src/EmojiPicker.android.tsx
Normal file
@ -0,0 +1,28 @@
|
||||
import {useMemo} from 'react'
|
||||
import {useColorScheme} from 'react-native'
|
||||
|
||||
import {type EmojiPickerViewProps} from './EmojiPickerModule.types'
|
||||
import EmojiPickerNativeView from './EmojiPickerView'
|
||||
|
||||
const EmojiPicker = ({onEmojiSelected}: EmojiPickerViewProps) => {
|
||||
const scheme = useColorScheme()
|
||||
const styles = useMemo(
|
||||
() =>
|
||||
({
|
||||
flex: 1,
|
||||
width: '100%',
|
||||
backgroundColor: scheme === 'dark' ? '#000' : '#fff',
|
||||
} as const),
|
||||
[scheme],
|
||||
)
|
||||
|
||||
return (
|
||||
<EmojiPickerNativeView
|
||||
onEmojiSelected={emoji => {
|
||||
onEmojiSelected(emoji)
|
||||
}}
|
||||
style={styles}
|
||||
/>
|
||||
)
|
||||
}
|
||||
export default EmojiPicker
|
15
modules/expo-emoji-picker/src/EmojiPicker.tsx
Normal file
15
modules/expo-emoji-picker/src/EmojiPicker.tsx
Normal file
@ -0,0 +1,15 @@
|
||||
import {type EmojiPickerViewProps} from './EmojiPickerModule.types'
|
||||
import EmojiPickerNativeView from './EmojiPickerView'
|
||||
|
||||
const EmojiPicker = ({children, onEmojiSelected}: EmojiPickerViewProps) => {
|
||||
return (
|
||||
<EmojiPickerNativeView
|
||||
onEmojiSelected={emoji => {
|
||||
onEmojiSelected(emoji)
|
||||
}}>
|
||||
{children}
|
||||
</EmojiPickerNativeView>
|
||||
)
|
||||
}
|
||||
|
||||
export default EmojiPicker
|
5
modules/expo-emoji-picker/src/EmojiPickerModule.ts
Normal file
5
modules/expo-emoji-picker/src/EmojiPickerModule.ts
Normal file
@ -0,0 +1,5 @@
|
||||
import {NativeModule, requireNativeModule} from 'expo'
|
||||
|
||||
declare class EmojiPickerModule extends NativeModule {}
|
||||
|
||||
export default requireNativeModule<EmojiPickerModule>('EmojiPicker')
|
20
modules/expo-emoji-picker/src/EmojiPickerModule.types.ts
Normal file
20
modules/expo-emoji-picker/src/EmojiPickerModule.types.ts
Normal file
@ -0,0 +1,20 @@
|
||||
import {type ViewProps} from 'react-native'
|
||||
|
||||
export type EmojiSelectionListener = (event: {
|
||||
nativeEvent: SelectionEvent
|
||||
}) => void
|
||||
|
||||
export type SelectionEvent = {
|
||||
emoji: string
|
||||
}
|
||||
|
||||
export type EmojiPickerViewProps = ViewProps & {
|
||||
/*
|
||||
* Callback that will be called when an emoji is selected.
|
||||
*/
|
||||
onEmojiSelected: (emoji: string) => void
|
||||
}
|
||||
|
||||
export type EmojiPickerNativeViewProps = ViewProps & {
|
||||
onEmojiSelected: EmojiSelectionListener
|
||||
}
|
21
modules/expo-emoji-picker/src/EmojiPickerView.tsx
Normal file
21
modules/expo-emoji-picker/src/EmojiPickerView.tsx
Normal file
@ -0,0 +1,21 @@
|
||||
import {requireNativeView} from 'expo'
|
||||
import type * as React from 'react'
|
||||
|
||||
import {
|
||||
type EmojiPickerNativeViewProps,
|
||||
type EmojiPickerViewProps,
|
||||
} from './EmojiPickerModule.types'
|
||||
|
||||
const NativeView: React.ComponentType<EmojiPickerNativeViewProps> =
|
||||
requireNativeView('EmojiPicker')
|
||||
|
||||
export default function EmojiPicker(props: EmojiPickerViewProps) {
|
||||
return (
|
||||
<NativeView
|
||||
{...props}
|
||||
onEmojiSelected={({nativeEvent}) => {
|
||||
props.onEmojiSelected(nativeEvent.emoji)
|
||||
}}
|
||||
/>
|
||||
)
|
||||
}
|
@ -9,7 +9,7 @@ class ExpoScrollForwarderView: ExpoView, UIGestureRecognizerDelegate {
|
||||
}
|
||||
}
|
||||
|
||||
private var rctScrollView: RCTScrollView?
|
||||
private var scrollView: UIScrollView?
|
||||
private var rctRefreshCtrl: RCTRefreshControl?
|
||||
private var cancelGestureRecognizers: [UIGestureRecognizer]?
|
||||
private var animTimer: Timer?
|
||||
@ -68,7 +68,7 @@ class ExpoScrollForwarderView: ExpoView, UIGestureRecognizerDelegate {
|
||||
}
|
||||
|
||||
@IBAction func callOnPan(_ sender: UIPanGestureRecognizer) {
|
||||
guard let rctsv = self.rctScrollView, let sv = rctsv.scrollView else {
|
||||
guard let sv = self.scrollView else {
|
||||
return
|
||||
}
|
||||
|
||||
@ -113,7 +113,7 @@ class ExpoScrollForwarderView: ExpoView, UIGestureRecognizerDelegate {
|
||||
}
|
||||
|
||||
func startDecayAnimation(_ translation: CGFloat, _ velocity: CGFloat) {
|
||||
guard let sv = self.rctScrollView?.scrollView else {
|
||||
guard let sv = self.scrollView else {
|
||||
return
|
||||
}
|
||||
|
||||
@ -160,32 +160,49 @@ class ExpoScrollForwarderView: ExpoView, UIGestureRecognizerDelegate {
|
||||
|
||||
return offset
|
||||
}
|
||||
|
||||
private func findScrollView(in view: UIView, foundCount: Int) -> UIScrollView? {
|
||||
var foundCount = foundCount
|
||||
if let sv = view as? UIScrollView { return sv }
|
||||
for child in view.subviews {
|
||||
if let found = findScrollView(in: child, foundCount: foundCount) {
|
||||
if foundCount == 1 {
|
||||
print("found sv: \(found)")
|
||||
// return found
|
||||
} else {
|
||||
print("found sv: \(found)")
|
||||
foundCount += 1
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func tryFindScrollView() {
|
||||
guard let scrollViewTag = scrollViewTag else {
|
||||
return
|
||||
}
|
||||
|
||||
// Before we switch to a different scrollview, we always want to remove the cancel gesture recognizer.
|
||||
// Otherwise we might end up with duplicates when we switch back to that scrollview.
|
||||
self.removeCancelGestureRecognizers()
|
||||
|
||||
guard let sv = self.findScrollView(in: self.superview!.superview!.superview!, foundCount: 0) else {
|
||||
print("⚠️ ExpoScrollForwarder: couldn’t find UIScrollView under tag \(tag)")
|
||||
return
|
||||
}
|
||||
|
||||
self.rctScrollView = self.appContext?
|
||||
.findView(withTag: scrollViewTag, ofType: RCTScrollView.self)
|
||||
self.rctRefreshCtrl = self.rctScrollView?.scrollView.refreshControl as? RCTRefreshControl
|
||||
self.scrollView = sv
|
||||
self.rctRefreshCtrl = sv.refreshControl as? RCTRefreshControl
|
||||
|
||||
self.addCancelGestureRecognizers()
|
||||
}
|
||||
|
||||
func addCancelGestureRecognizers() {
|
||||
self.cancelGestureRecognizers?.forEach { r in
|
||||
self.rctScrollView?.scrollView?.addGestureRecognizer(r)
|
||||
self.scrollView?.addGestureRecognizer(r)
|
||||
}
|
||||
}
|
||||
|
||||
func removeCancelGestureRecognizers() {
|
||||
self.cancelGestureRecognizers?.forEach { r in
|
||||
self.rctScrollView?.scrollView?.removeGestureRecognizer(r)
|
||||
self.scrollView?.removeGestureRecognizer(r)
|
||||
}
|
||||
}
|
||||
|
||||
@ -202,7 +219,7 @@ class ExpoScrollForwarderView: ExpoView, UIGestureRecognizerDelegate {
|
||||
}
|
||||
|
||||
func scrollToOffset(_ offset: Int, animated: Bool = true) {
|
||||
self.rctScrollView?.scroll(toOffset: CGPoint(x: 0, y: offset), animated: animated)
|
||||
self.scrollView?.scrollRectToVisible(CGRect(x: 0, y: offset, width: 0, height: 0), animated: animated)
|
||||
}
|
||||
|
||||
func stopTimer() {
|
||||
|
@ -1,5 +1,3 @@
|
||||
import React from 'react'
|
||||
|
||||
export interface ExpoScrollForwarderViewProps {
|
||||
scrollViewTag: number | null
|
||||
children: React.ReactNode
|
||||
|
@ -1,7 +1,6 @@
|
||||
import * as React from 'react'
|
||||
import {requireNativeViewManager} from 'expo-modules-core'
|
||||
|
||||
import {ExpoScrollForwarderViewProps} from './ExpoScrollForwarder.types'
|
||||
import {type ExpoScrollForwarderViewProps} from './ExpoScrollForwarder.types'
|
||||
|
||||
const NativeView: React.ComponentType<ExpoScrollForwarderViewProps> =
|
||||
requireNativeViewManager('ExpoScrollForwarder')
|
||||
|
@ -1,6 +1,4 @@
|
||||
import React from 'react'
|
||||
|
||||
import {ExpoScrollForwarderViewProps} from './ExpoScrollForwarder.types'
|
||||
import {type ExpoScrollForwarderViewProps} from './ExpoScrollForwarder.types'
|
||||
|
||||
export function ExpoScrollForwarderView({
|
||||
children,
|
||||
|
156
package.json
156
package.json
@ -6,6 +6,17 @@
|
||||
"node": ">=20"
|
||||
},
|
||||
"packageManager": "yarn@1.22.22",
|
||||
"expo": {
|
||||
"autolinking": {
|
||||
"android": {
|
||||
"buildFromSource": [
|
||||
"expo-notifications",
|
||||
"expo-haptics",
|
||||
"expo-media-library"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"prepare": "is-ci || husky install",
|
||||
"postinstall": "patch-package && yarn intl:compile",
|
||||
@ -58,13 +69,13 @@
|
||||
"icons:optimize": "svgo -f ./assets/icons"
|
||||
},
|
||||
"dependencies": {
|
||||
"@atproto/api": "^0.15.3",
|
||||
"@atproto/api": "^0.15.5",
|
||||
"@bitdrift/react-native": "^0.6.8",
|
||||
"@braintree/sanitize-url": "^6.0.2",
|
||||
"@discord/bottom-sheet": "bluesky-social/react-native-bottom-sheet",
|
||||
"@emoji-mart/react": "^1.1.1",
|
||||
"@expo/html-elements": "^0.4.2",
|
||||
"@expo/webpack-config": "^19.0.0",
|
||||
"@expo/html-elements": "^0.12.4",
|
||||
"@expo/webpack-config": "^19.0.1",
|
||||
"@floating-ui/dom": "^1.6.3",
|
||||
"@floating-ui/react-dom": "^2.0.8",
|
||||
"@formatjs/intl-locale": "^4.2.8",
|
||||
@ -80,9 +91,9 @@
|
||||
"@mattermost/react-native-paste-input": "^0.7.1",
|
||||
"@miblanchard/react-native-slider": "^2.3.1",
|
||||
"@mozzius/expo-dynamic-app-icon": "^1.5.0",
|
||||
"@react-native-async-storage/async-storage": "1.23.1",
|
||||
"@react-native-menu/menu": "^1.1.7",
|
||||
"@react-native-picker/picker": "2.10.3",
|
||||
"@react-native-async-storage/async-storage": "2.1.2",
|
||||
"@react-native-menu/menu": "^1.2.3",
|
||||
"@react-native-picker/picker": "2.11.0",
|
||||
"@react-navigation/bottom-tabs": "^6.5.20",
|
||||
"@react-navigation/drawer": "^6.6.15",
|
||||
"@react-navigation/native": "^6.1.17",
|
||||
@ -119,33 +130,33 @@
|
||||
"emoji-mart": "^5.5.2",
|
||||
"emoji-regex": "^10.4.0",
|
||||
"eventemitter3": "^5.0.1",
|
||||
"expo": "~52.0.42",
|
||||
"expo-application": "~6.0.2",
|
||||
"expo-blur": "^14.0.3",
|
||||
"expo-build-properties": "~0.13.2",
|
||||
"expo-camera": "~16.0.18",
|
||||
"expo-clipboard": "~7.0.1",
|
||||
"expo-dev-client": "~5.0.19",
|
||||
"expo-device": "~7.0.3",
|
||||
"expo-file-system": "~18.0.12",
|
||||
"expo-font": "~13.0.4",
|
||||
"expo-haptics": "~14.0.1",
|
||||
"expo-image": "~2.0.7",
|
||||
"expo-image-manipulator": "~13.0.6",
|
||||
"expo-image-picker": "~16.0.6",
|
||||
"expo-linear-gradient": "~14.0.2",
|
||||
"expo-linking": "~7.0.5",
|
||||
"expo-localization": "~16.0.1",
|
||||
"expo-media-library": "~17.0.6",
|
||||
"expo-notifications": "~0.29.14",
|
||||
"expo-screen-orientation": "~8.0.4",
|
||||
"expo-sharing": "~13.0.1",
|
||||
"expo-splash-screen": "~0.29.22",
|
||||
"expo-system-ui": "~4.0.9",
|
||||
"expo-task-manager": "~12.0.6",
|
||||
"expo-updates": "~0.27.4",
|
||||
"expo-video": "~2.0.6",
|
||||
"expo-web-browser": "~14.0.2",
|
||||
"expo": "^53.0.5",
|
||||
"expo-application": "~6.1.4",
|
||||
"expo-blur": "~14.1.4",
|
||||
"expo-build-properties": "~0.14.6",
|
||||
"expo-camera": "~16.1.6",
|
||||
"expo-clipboard": "~7.1.4",
|
||||
"expo-dev-client": "~5.1.7",
|
||||
"expo-device": "~7.1.4",
|
||||
"expo-file-system": "~18.1.8",
|
||||
"expo-font": "~13.3.0",
|
||||
"expo-haptics": "~14.1.4",
|
||||
"expo-image": "~2.1.6",
|
||||
"expo-image-manipulator": "~13.1.5",
|
||||
"expo-image-picker": "~16.1.4",
|
||||
"expo-linear-gradient": "~14.1.4",
|
||||
"expo-linking": "~7.1.4",
|
||||
"expo-localization": "~16.1.5",
|
||||
"expo-media-library": "~17.1.6",
|
||||
"expo-notifications": "~0.31.1",
|
||||
"expo-screen-orientation": "~8.1.5",
|
||||
"expo-sharing": "~13.1.5",
|
||||
"expo-splash-screen": "~0.30.8",
|
||||
"expo-system-ui": "~5.0.7",
|
||||
"expo-task-manager": "~13.1.5",
|
||||
"expo-updates": "~0.28.12",
|
||||
"expo-video": "~2.1.8",
|
||||
"expo-web-browser": "~14.1.6",
|
||||
"fast-text-encoding": "^1.0.6",
|
||||
"history": "^5.3.0",
|
||||
"hls.js": "^1.5.11",
|
||||
@ -157,47 +168,47 @@
|
||||
"lodash.isequal": "^4.5.0",
|
||||
"lodash.shuffle": "^4.2.0",
|
||||
"lodash.throttle": "^4.1.1",
|
||||
"multiformats": "^13.1.0",
|
||||
"multiformats": "9.9.0",
|
||||
"nanoid": "^5.0.5",
|
||||
"normalize-url": "^8.0.0",
|
||||
"patch-package": "^6.5.1",
|
||||
"postinstall-postinstall": "^2.1.0",
|
||||
"psl": "^1.9.0",
|
||||
"radix-ui": "^1.2.0",
|
||||
"react": "18.3.1",
|
||||
"react-compiler-runtime": "19.0.0-beta-a7bf2bd-20241110",
|
||||
"react-dom": "18.3.1",
|
||||
"react": "19.0.0",
|
||||
"react-compiler-runtime": "^19.1.0-rc.1",
|
||||
"react-dom": "19.0.0",
|
||||
"react-image-crop": "^11.0.7",
|
||||
"react-keyed-flatten-children": "^3.0.0",
|
||||
"react-native": "0.76.9",
|
||||
"react-native-compressor": "1.10.3",
|
||||
"react-native-date-picker": "^5.0.7",
|
||||
"react-native-drawer-layout": "^4.1.1",
|
||||
"react-is": "19",
|
||||
"react-keyed-flatten-children": "^5.0.0",
|
||||
"react-native": "0.79.2",
|
||||
"react-native-compressor": "1.11.0",
|
||||
"react-native-date-picker": "^5.0.12",
|
||||
"react-native-drawer-layout": "^4.1.6",
|
||||
"react-native-edge-to-edge": "^1.6.0",
|
||||
"react-native-emoji-popup": "^0.1.2",
|
||||
"react-native-gesture-handler": "2.20.2",
|
||||
"react-native-gesture-handler": "2.25.0",
|
||||
"react-native-get-random-values": "~1.11.0",
|
||||
"react-native-image-crop-picker": "^0.41.6",
|
||||
"react-native-image-crop-picker": "^0.42.0",
|
||||
"react-native-ios-context-menu": "^1.15.3",
|
||||
"react-native-keyboard-controller": "^1.17.1",
|
||||
"react-native-mmkv": "^2.12.2",
|
||||
"react-native-pager-view": "6.5.1",
|
||||
"react-native-pager-view": "6.7.1",
|
||||
"react-native-picker-select": "^9.3.1",
|
||||
"react-native-progress": "bluesky-social/react-native-progress",
|
||||
"react-native-qrcode-styled": "^0.3.3",
|
||||
"react-native-reanimated": "~3.16.1",
|
||||
"react-native-reanimated": "~3.17.5",
|
||||
"react-native-root-siblings": "^4.1.1",
|
||||
"react-native-safe-area-context": "4.12.0",
|
||||
"react-native-screens": "~4.4.0",
|
||||
"react-native-svg": "15.8.0",
|
||||
"react-native-safe-area-context": "5.4.0",
|
||||
"react-native-screens": "~4.10.0",
|
||||
"react-native-svg": "15.11.2",
|
||||
"react-native-uitextview": "^1.4.0",
|
||||
"react-native-url-polyfill": "^1.3.0",
|
||||
"react-native-uuid": "^2.0.2",
|
||||
"react-native-uuid": "^2.0.3",
|
||||
"react-native-view-shot": "^4.0.3",
|
||||
"react-native-web": "~0.19.13",
|
||||
"react-native-web": "~0.20.0",
|
||||
"react-native-web-webview": "^1.0.2",
|
||||
"react-native-webview": "13.12.5",
|
||||
"react-remove-scroll-bar": "^2.3.6",
|
||||
"react-native-webview": "13.13.5",
|
||||
"react-remove-scroll-bar": "^2.3.8",
|
||||
"react-responsive": "^9.0.2",
|
||||
"react-textarea-autosize": "^8.5.3",
|
||||
"rn-fetch-blob": "^0.12.0",
|
||||
@ -209,77 +220,74 @@
|
||||
"zod": "^3.20.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@atproto/dev-env": "^0.3.87",
|
||||
"@atproto/dev-env": "^0.3.128",
|
||||
"@babel/core": "^7.26.0",
|
||||
"@babel/preset-env": "^7.26.0",
|
||||
"@babel/runtime": "^7.26.0",
|
||||
"@did-plc/server": "^0.0.1",
|
||||
"@expo/config-plugins": "9.0.10",
|
||||
"@expo/config-plugins": "~10.0.2",
|
||||
"@lingui/cli": "^4.14.1",
|
||||
"@lingui/macro": "^4.14.1",
|
||||
"@pmmmwh/react-refresh-webpack-plugin": "^0.5.15",
|
||||
"@react-native/eslint-config": "^0.76.9",
|
||||
"@react-native/typescript-config": "^0.76.9",
|
||||
"@react-native/eslint-config": "^0.79.2",
|
||||
"@react-native/typescript-config": "^0.79.2",
|
||||
"@sentry/webpack-plugin": "^3.2.2",
|
||||
"@testing-library/jest-native": "^5.4.3",
|
||||
"@testing-library/react-native": "^12.8.1",
|
||||
"@testing-library/react-native": "^13.2.0",
|
||||
"@types/jest": "^29.4.0",
|
||||
"@types/lodash.chunk": "^4.2.7",
|
||||
"@types/lodash.debounce": "^4.0.7",
|
||||
"@types/lodash.isequal": "^4.5.6",
|
||||
"@types/lodash.shuffle": "^4.2.7",
|
||||
"@types/psl": "^1.1.1",
|
||||
"@types/react-dom": "^18.3.1",
|
||||
"@types/react-dom": "^19.1.2",
|
||||
"@types/react-responsive": "^8.0.5",
|
||||
"@types/react-test-renderer": "^17.0.1",
|
||||
"@typescript-eslint/eslint-plugin": "^7.18.0",
|
||||
"@typescript-eslint/parser": "^7.18.0",
|
||||
"babel-jest": "^29.7.0",
|
||||
"babel-plugin-macros": "^3.1.0",
|
||||
"babel-plugin-module-resolver": "^5.0.2",
|
||||
"babel-plugin-react-compiler": "19.0.0-beta-a7bf2bd-20241110",
|
||||
"babel-preset-expo": "^12.0.2",
|
||||
"babel-plugin-react-compiler": "^19.1.0-rc.1",
|
||||
"babel-preset-expo": "~13.1.11",
|
||||
"eslint": "^8.19.0",
|
||||
"eslint-plugin-bsky-internal": "link:./eslint",
|
||||
"eslint-plugin-ft-flow": "^2.0.3",
|
||||
"eslint-plugin-import": "^2.31.0",
|
||||
"eslint-plugin-lingui": "^0.2.0",
|
||||
"eslint-plugin-react": "^7.33.2",
|
||||
"eslint-plugin-react-compiler": "19.0.0-beta-a7bf2bd-20241110",
|
||||
"eslint-plugin-react-compiler": "^19.1.0-rc.1",
|
||||
"eslint-plugin-react-native-a11y": "^3.3.0",
|
||||
"eslint-plugin-simple-import-sort": "^12.0.0",
|
||||
"file-loader": "6.2.0",
|
||||
"husky": "^8.0.3",
|
||||
"is-ci": "^3.0.1",
|
||||
"jest": "^29.7.0",
|
||||
"jest-expo": "~52.0.6",
|
||||
"jest-expo": "~53.0.3",
|
||||
"jest-junit": "^16.0.0",
|
||||
"lint-staged": "^13.2.3",
|
||||
"lockfile-lint": "^4.14.0",
|
||||
"metro-react-native-babel-preset": "^0.76.9",
|
||||
"metro-react-native-babel-preset": "^0.77.0",
|
||||
"prettier": "^2.8.3",
|
||||
"react-native-dotenv": "^3.4.11",
|
||||
"react-refresh": "^0.14.0",
|
||||
"react-test-renderer": "18.2.0",
|
||||
"svgo": "^3.3.2",
|
||||
"ts-node": "^10.9.1",
|
||||
"typescript": "^5.7.2",
|
||||
"typescript": "~5.8.3",
|
||||
"webpack-bundle-analyzer": "^4.10.1"
|
||||
},
|
||||
"resolutions": {
|
||||
"@expo/image-utils": "0.6.3",
|
||||
"@react-native/babel-preset": "0.76.9",
|
||||
"@react-native/normalize-colors": "0.76.1",
|
||||
"@react-native/babel-preset": "0.79.2",
|
||||
"@react-native/normalize-colors": "0.79.2",
|
||||
"@types/react": "^18",
|
||||
"**/expo-constants": "17.0.3",
|
||||
"**/expo-device": "7.0.1",
|
||||
"**/zod": "3.23.8"
|
||||
"**/zod": "3.23.8",
|
||||
"**/multiformats": "9.9.0"
|
||||
},
|
||||
"jest": {
|
||||
"preset": "jest-expo/ios",
|
||||
"setupFilesAfterEnv": [
|
||||
"./jest/jestSetup.js",
|
||||
"@testing-library/jest-native/extend-expect"
|
||||
"./jest/jestSetup.js"
|
||||
],
|
||||
"moduleFileExtensions": [
|
||||
"ts",
|
||||
|
@ -1,101 +0,0 @@
|
||||
diff --git a/node_modules/expo-image-manipulator/src/ImageManipulator.web.ts b/node_modules/expo-image-manipulator/src/ImageManipulator.web.ts
|
||||
new file mode 100644
|
||||
index 0000000..babbb3b
|
||||
--- /dev/null
|
||||
+++ b/node_modules/expo-image-manipulator/src/ImageManipulator.web.ts
|
||||
@@ -0,0 +1,60 @@
|
||||
+import { useReleasingSharedObject } from 'expo-modules-core';
|
||||
+import { SharedRef } from 'expo-modules-core/types';
|
||||
+
|
||||
+import { Action, ImageResult, SaveFormat, SaveOptions } from './ImageManipulator.types';
|
||||
+import { ImageManipulatorContext } from './ImageManipulatorContext';
|
||||
+import ExpoImageManipulator from './NativeImageManipulatorModule';
|
||||
+import { validateArguments } from './validators';
|
||||
+
|
||||
+// @needsAudit
|
||||
+/**
|
||||
+ * Manipulate the image provided via `uri`. Available modifications are rotating, flipping (mirroring),
|
||||
+ * resizing and cropping. Each invocation results in a new file. With one invocation you can provide
|
||||
+ * a set of actions to perform over the image. Overwriting the source file would not have an effect
|
||||
+ * in displaying the result as images are cached.
|
||||
+ * @param uri URI of the file to manipulate. Should be on the local file system or a base64 data URI.
|
||||
+ * @param actions An array of objects representing manipulation options. Each object should have
|
||||
+ * __only one__ of the keys that corresponds to specific transformation.
|
||||
+ * @param saveOptions A map defining how modified image should be saved.
|
||||
+ * @return Promise which fulfils with [`ImageResult`](#imageresult) object.
|
||||
+ * @deprecated It has been replaced by the new, contextual and object-oriented API.
|
||||
+ * Use [`ImageManipulator.manipulate`](#manipulateuri) or [`useImageManipulator`](#useimagemanipulatoruri) instead.
|
||||
+ */
|
||||
+export async function manipulateAsync(
|
||||
+ uri: string,
|
||||
+ actions: Action[] = [],
|
||||
+ saveOptions: SaveOptions = {}
|
||||
+): Promise<ImageResult> {
|
||||
+ validateArguments(uri, actions, saveOptions);
|
||||
+
|
||||
+ const { format = SaveFormat.JPEG, ...rest } = saveOptions;
|
||||
+ const context = ExpoImageManipulator.manipulate(uri);
|
||||
+
|
||||
+ for (const action of actions) {
|
||||
+ if ('resize' in action) {
|
||||
+ context.resize(action.resize);
|
||||
+ } else if ('rotate' in action) {
|
||||
+ context.rotate(action.rotate);
|
||||
+ } else if ('flip' in action) {
|
||||
+ context.flip(action.flip);
|
||||
+ } else if ('crop' in action) {
|
||||
+ context.crop(action.crop);
|
||||
+ } else if ('extent' in action && context.extent) {
|
||||
+ context.extent(action.extent);
|
||||
+ }
|
||||
+ }
|
||||
+ const image = await context.renderAsync(saveOptions.compress);
|
||||
+ const result = await image.saveAsync({ format, ...rest });
|
||||
+
|
||||
+ // These shared objects will not be used anymore, so free up some memory.
|
||||
+ context.release();
|
||||
+ image.release();
|
||||
+
|
||||
+ return result;
|
||||
+}
|
||||
+
|
||||
+export function useImageManipulator(source: string | SharedRef<'image'>): ImageManipulatorContext {
|
||||
+ return useReleasingSharedObject(() => ExpoImageManipulator.manipulate(source), [source]);
|
||||
+}
|
||||
+
|
||||
+export { ExpoImageManipulator as ImageManipulator };
|
||||
diff --git a/node_modules/expo-image-manipulator/src/ImageManipulatorContext.ts b/node_modules/expo-image-manipulator/src/ImageManipulatorContext.ts
|
||||
index 120d8d3..f8aa49c 100644
|
||||
--- a/node_modules/expo-image-manipulator/src/ImageManipulatorContext.ts
|
||||
+++ b/node_modules/expo-image-manipulator/src/ImageManipulatorContext.ts
|
||||
@@ -52,7 +52,7 @@ export declare class ImageManipulatorContext extends SharedObject {
|
||||
/**
|
||||
* Awaits for all manipulation tasks to finish and resolves with a reference to the resulted native image.
|
||||
*/
|
||||
- renderAsync(): Promise<ImageRef>;
|
||||
+ renderAsync(compress?: number): Promise<ImageRef>;
|
||||
}
|
||||
|
||||
export default ExpoImageManipulator.Context as typeof ImageManipulatorContext;
|
||||
diff --git a/node_modules/expo-image-manipulator/src/web/ImageManipulatorContext.web.ts b/node_modules/expo-image-manipulator/src/web/ImageManipulatorContext.web.ts
|
||||
index 428848c..363a57a 100644
|
||||
--- a/node_modules/expo-image-manipulator/src/web/ImageManipulatorContext.web.ts
|
||||
+++ b/node_modules/expo-image-manipulator/src/web/ImageManipulatorContext.web.ts
|
||||
@@ -41,7 +41,7 @@ export default class ImageManipulatorContext extends SharedObject {
|
||||
return this;
|
||||
}
|
||||
|
||||
- async renderAsync(): Promise<ImageManipulatorImageRef> {
|
||||
+ async renderAsync(compress?: number): Promise<ImageManipulatorImageRef> {
|
||||
const canvas = await this.currentTask;
|
||||
|
||||
return new Promise((resolve) => {
|
||||
@@ -49,7 +49,7 @@ export default class ImageManipulatorContext extends SharedObject {
|
||||
const url = blob ? URL.createObjectURL(blob) : canvas.toDataURL();
|
||||
|
||||
resolve(new ImageManipulatorImageRef(url, canvas.width, canvas.height));
|
||||
- });
|
||||
+ }, typeof compress === 'number' ? 'image/jpeg' : undefined, compress);
|
||||
});
|
||||
}
|
||||
|
@ -1,19 +1,19 @@
|
||||
diff --git a/node_modules/expo-media-library/android/src/main/java/expo/modules/medialibrary/MediaLibraryModule.kt b/node_modules/expo-media-library/android/src/main/java/expo/modules/medialibrary/MediaLibraryModule.kt
|
||||
index 64e6efe..e61485e 100644
|
||||
index f1255e8..a9b49e5 100644
|
||||
--- a/node_modules/expo-media-library/android/src/main/java/expo/modules/medialibrary/MediaLibraryModule.kt
|
||||
+++ b/node_modules/expo-media-library/android/src/main/java/expo/modules/medialibrary/MediaLibraryModule.kt
|
||||
@@ -111,12 +111,12 @@ class MediaLibraryModule : Module() {
|
||||
@@ -112,11 +112,9 @@ class MediaLibraryModule : Module() {
|
||||
}
|
||||
|
||||
AsyncFunction("createAssetAsync") { localUri: String, promise: Promise ->
|
||||
AsyncFunction("createAssetAsync") { localUri: String, albumId: String?, promise: Promise ->
|
||||
- throwUnlessPermissionsGranted {
|
||||
+ //throwUnlessPermissionsGranted {
|
||||
withModuleScope(promise) {
|
||||
CreateAsset(context, localUri, promise)
|
||||
.execute()
|
||||
}
|
||||
- }
|
||||
+ //}
|
||||
- withModuleScope(promise) {
|
||||
- CreateAssetWithAlbumId(context, localUri, promise, true, albumId)
|
||||
- .execute()
|
||||
- }
|
||||
+ withModuleScope(promise) {
|
||||
+ CreateAssetWithAlbumId(context, localUri, promise, true, albumId)
|
||||
+ .execute()
|
||||
}
|
||||
}
|
||||
|
||||
AsyncFunction("addAssetsToAlbumAsync") { assetsId: List<String>, albumId: String, copyToAlbum: Boolean, promise: Promise ->
|
@ -1,169 +0,0 @@
|
||||
diff --git a/node_modules/expo-notifications/android/build.gradle b/node_modules/expo-notifications/android/build.gradle
|
||||
index 13bffbb..5ebbede 100644
|
||||
--- a/node_modules/expo-notifications/android/build.gradle
|
||||
+++ b/node_modules/expo-notifications/android/build.gradle
|
||||
@@ -46,6 +46,7 @@ dependencies {
|
||||
implementation 'com.google.firebase:firebase-messaging:24.0.1'
|
||||
|
||||
implementation 'me.leolin:ShortcutBadger:1.1.22@aar'
|
||||
+ implementation project(':expo-background-notification-handler')
|
||||
|
||||
if (project.findProject(':expo-modules-test-core')) {
|
||||
testImplementation project(':expo-modules-test-core')
|
||||
diff --git a/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/interfaces/INotificationContent.kt b/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/interfaces/INotificationContent.kt
|
||||
index 7b99e6c..45a450d 100644
|
||||
--- a/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/interfaces/INotificationContent.kt
|
||||
+++ b/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/interfaces/INotificationContent.kt
|
||||
@@ -15,6 +15,7 @@ import org.json.JSONObject
|
||||
* This interface exists to provide a common API for both classes.
|
||||
* */
|
||||
interface INotificationContent : Parcelable {
|
||||
+ val channelId: String?
|
||||
val title: String?
|
||||
val text: String?
|
||||
val subText: String?
|
||||
diff --git a/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/model/NotificationContent.java b/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/model/NotificationContent.java
|
||||
index 191b64e..fe8b3c5 100644
|
||||
--- a/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/model/NotificationContent.java
|
||||
+++ b/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/model/NotificationContent.java
|
||||
@@ -35,6 +35,7 @@ import kotlin.coroutines.Continuation;
|
||||
* Refactoring this class may require a migration strategy for the data stored in SharedPreferences.
|
||||
*/
|
||||
public class NotificationContent implements Parcelable, Serializable, INotificationContent {
|
||||
+ private String mChannelId;
|
||||
private String mTitle;
|
||||
private String mText;
|
||||
private String mSubtitle;
|
||||
@@ -65,6 +66,11 @@ public class NotificationContent implements Parcelable, Serializable, INotificat
|
||||
}
|
||||
};
|
||||
|
||||
+ @Nullable
|
||||
+ public String getChannelId() {
|
||||
+ return mChannelId;
|
||||
+ }
|
||||
+
|
||||
@Nullable
|
||||
public String getTitle() {
|
||||
return mTitle;
|
||||
@@ -158,6 +164,7 @@ public class NotificationContent implements Parcelable, Serializable, INotificat
|
||||
}
|
||||
|
||||
protected NotificationContent(Parcel in) {
|
||||
+ mChannelId = in.readString();
|
||||
mTitle = in.readString();
|
||||
mText = in.readString();
|
||||
mSubtitle = in.readString();
|
||||
@@ -183,6 +190,7 @@ public class NotificationContent implements Parcelable, Serializable, INotificat
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
+ dest.writeString(mChannelId);
|
||||
dest.writeString(mTitle);
|
||||
dest.writeString(mText);
|
||||
dest.writeString(mSubtitle);
|
||||
@@ -203,6 +211,7 @@ public class NotificationContent implements Parcelable, Serializable, INotificat
|
||||
private static final long serialVersionUID = 397666843266836802L;
|
||||
|
||||
private void writeObject(java.io.ObjectOutputStream out) throws IOException {
|
||||
+ out.writeObject(mChannelId);
|
||||
out.writeObject(mTitle);
|
||||
out.writeObject(mText);
|
||||
out.writeObject(mSubtitle);
|
||||
@@ -285,6 +294,11 @@ public class NotificationContent implements Parcelable, Serializable, INotificat
|
||||
useDefaultVibrationPattern();
|
||||
}
|
||||
|
||||
+ public Builder setChannelId(String channelId) {
|
||||
+ content.mChannelId = channelId;
|
||||
+ return this;
|
||||
+ }
|
||||
+
|
||||
public Builder setTitle(String title) {
|
||||
content.mTitle = title;
|
||||
return this;
|
||||
diff --git a/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/model/NotificationData.kt b/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/model/NotificationData.kt
|
||||
index 39b5aad..e50797d 100644
|
||||
--- a/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/model/NotificationData.kt
|
||||
+++ b/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/model/NotificationData.kt
|
||||
@@ -11,6 +11,9 @@ import org.json.JSONObject
|
||||
* */
|
||||
@JvmInline
|
||||
value class NotificationData(private val data: Map<String, String>) {
|
||||
+ val channelId: String?
|
||||
+ get() = data["channelId"]
|
||||
+
|
||||
val title: String?
|
||||
get() = data["title"]
|
||||
|
||||
diff --git a/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/model/RemoteNotificationContent.kt b/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/model/RemoteNotificationContent.kt
|
||||
index d2cc6cf..6a48ff2 100644
|
||||
--- a/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/model/RemoteNotificationContent.kt
|
||||
+++ b/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/model/RemoteNotificationContent.kt
|
||||
@@ -31,6 +31,8 @@ class RemoteNotificationContent(private val remoteMessage: RemoteMessage) : INot
|
||||
return remoteMessage.notification?.imageUrl != null
|
||||
}
|
||||
|
||||
+ override val channelId = remoteMessage.notification?.channelId ?: notificationData.channelId
|
||||
+
|
||||
override val title = remoteMessage.notification?.title ?: notificationData.title
|
||||
|
||||
override val text = remoteMessage.notification?.body ?: notificationData.message
|
||||
diff --git a/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/presentation/builders/ExpoNotificationBuilder.kt b/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/presentation/builders/ExpoNotificationBuilder.kt
|
||||
index 8ca6ec5..57c3599 100644
|
||||
--- a/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/presentation/builders/ExpoNotificationBuilder.kt
|
||||
+++ b/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/presentation/builders/ExpoNotificationBuilder.kt
|
||||
@@ -101,6 +101,9 @@ open class ExpoNotificationBuilder(
|
||||
builder.setOngoing(content.isSticky)
|
||||
|
||||
// see "Notification anatomy" https://developer.android.com/develop/ui/views/notifications#Templates
|
||||
+ content.channelId?.let {
|
||||
+ builder.setChannelId(it)
|
||||
+ }
|
||||
builder.setContentTitle(content.title)
|
||||
builder.setContentText(content.text)
|
||||
builder.setSubText(content.subText)
|
||||
diff --git a/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/service/delegates/FirebaseMessagingDelegate.kt b/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/service/delegates/FirebaseMessagingDelegate.kt
|
||||
index 9f22441..5f92f80 100644
|
||||
--- a/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/service/delegates/FirebaseMessagingDelegate.kt
|
||||
+++ b/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/service/delegates/FirebaseMessagingDelegate.kt
|
||||
@@ -2,6 +2,9 @@ package expo.modules.notifications.service.delegates
|
||||
|
||||
import android.content.Context
|
||||
import com.google.firebase.messaging.RemoteMessage
|
||||
+import expo.modules.backgroundnotificationhandler.BackgroundNotificationHandler
|
||||
+import expo.modules.backgroundnotificationhandler.BackgroundNotificationHandlerInterface
|
||||
+import expo.modules.backgroundnotificationhandler.ExpoBackgroundNotificationHandlerModule
|
||||
import expo.modules.interfaces.taskManager.TaskServiceProviderHelper
|
||||
import expo.modules.notifications.notifications.RemoteMessageSerializer
|
||||
import expo.modules.notifications.notifications.background.BackgroundRemoteNotificationTaskConsumer
|
||||
@@ -17,7 +20,8 @@ import expo.modules.notifications.tokens.interfaces.FirebaseTokenListener
|
||||
import java.lang.ref.WeakReference
|
||||
import java.util.*
|
||||
|
||||
-open class FirebaseMessagingDelegate(protected val context: Context) : FirebaseMessagingDelegate {
|
||||
+open class FirebaseMessagingDelegate(protected val context: Context) : FirebaseMessagingDelegate,
|
||||
+ BackgroundNotificationHandlerInterface {
|
||||
companion object {
|
||||
// Unfortunately we cannot save state between instances of a service other way
|
||||
// than by static properties. Fortunately, using weak references we can
|
||||
@@ -94,8 +98,17 @@ open class FirebaseMessagingDelegate(protected val context: Context) : FirebaseM
|
||||
DebugLogging.logRemoteMessage("FirebaseMessagingDelegate.onMessageReceived: message", remoteMessage)
|
||||
val notification = createNotification(remoteMessage)
|
||||
DebugLogging.logNotification("FirebaseMessagingDelegate.onMessageReceived: notification", notification)
|
||||
- NotificationsService.receive(context, notification)
|
||||
- runTaskManagerTasks(remoteMessage)
|
||||
+
|
||||
+ if (!ExpoBackgroundNotificationHandlerModule.isForegrounded) {
|
||||
+ BackgroundNotificationHandler(context, this).handleMessage(remoteMessage)
|
||||
+ } else {
|
||||
+ showMessage(remoteMessage)
|
||||
+ runTaskManagerTasks(remoteMessage)
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ override fun showMessage(remoteMessage: RemoteMessage) {
|
||||
+ NotificationsService.receive(context, createNotification(remoteMessage))
|
||||
}
|
||||
|
||||
private fun runTaskManagerTasks(remoteMessage: RemoteMessage) {
|
992
patches/expo-notifications+0.31.1.patch
Normal file
992
patches/expo-notifications+0.31.1.patch
Normal file
@ -0,0 +1,992 @@
|
||||
diff --git a/node_modules/expo-notifications/android/.gradle/8.10/checksums/checksums.lock b/node_modules/expo-notifications/android/.gradle/8.10/checksums/checksums.lock
|
||||
new file mode 100644
|
||||
index 0000000..883ef6a
|
||||
Binary files /dev/null and b/node_modules/expo-notifications/android/.gradle/8.10/checksums/checksums.lock differ
|
||||
diff --git a/node_modules/expo-notifications/android/.gradle/8.10/dependencies-accessors/gc.properties b/node_modules/expo-notifications/android/.gradle/8.10/dependencies-accessors/gc.properties
|
||||
new file mode 100644
|
||||
index 0000000..e69de29
|
||||
diff --git a/node_modules/expo-notifications/android/.gradle/8.10/fileChanges/last-build.bin b/node_modules/expo-notifications/android/.gradle/8.10/fileChanges/last-build.bin
|
||||
new file mode 100644
|
||||
index 0000000..f76dd23
|
||||
Binary files /dev/null and b/node_modules/expo-notifications/android/.gradle/8.10/fileChanges/last-build.bin differ
|
||||
diff --git a/node_modules/expo-notifications/android/.gradle/8.10/fileHashes/fileHashes.lock b/node_modules/expo-notifications/android/.gradle/8.10/fileHashes/fileHashes.lock
|
||||
new file mode 100644
|
||||
index 0000000..774caf7
|
||||
Binary files /dev/null and b/node_modules/expo-notifications/android/.gradle/8.10/fileHashes/fileHashes.lock differ
|
||||
diff --git a/node_modules/expo-notifications/android/.gradle/8.10/gc.properties b/node_modules/expo-notifications/android/.gradle/8.10/gc.properties
|
||||
new file mode 100644
|
||||
index 0000000..e69de29
|
||||
diff --git a/node_modules/expo-notifications/android/.gradle/buildOutputCleanup/buildOutputCleanup.lock b/node_modules/expo-notifications/android/.gradle/buildOutputCleanup/buildOutputCleanup.lock
|
||||
new file mode 100644
|
||||
index 0000000..a3c1514
|
||||
Binary files /dev/null and b/node_modules/expo-notifications/android/.gradle/buildOutputCleanup/buildOutputCleanup.lock differ
|
||||
diff --git a/node_modules/expo-notifications/android/.gradle/buildOutputCleanup/cache.properties b/node_modules/expo-notifications/android/.gradle/buildOutputCleanup/cache.properties
|
||||
new file mode 100644
|
||||
index 0000000..0e5b4da
|
||||
--- /dev/null
|
||||
+++ b/node_modules/expo-notifications/android/.gradle/buildOutputCleanup/cache.properties
|
||||
@@ -0,0 +1,2 @@
|
||||
+#Thu Apr 24 20:44:36 PDT 2025
|
||||
+gradle.version=8.10
|
||||
diff --git a/node_modules/expo-notifications/android/.gradle/config.properties b/node_modules/expo-notifications/android/.gradle/config.properties
|
||||
new file mode 100644
|
||||
index 0000000..0bd71c6
|
||||
--- /dev/null
|
||||
+++ b/node_modules/expo-notifications/android/.gradle/config.properties
|
||||
@@ -0,0 +1,2 @@
|
||||
+#Thu Apr 24 20:44:32 PDT 2025
|
||||
+java.home=/Applications/Android Studio.app/Contents/jbr/Contents/Home
|
||||
diff --git a/node_modules/expo-notifications/android/.gradle/vcs-1/gc.properties b/node_modules/expo-notifications/android/.gradle/vcs-1/gc.properties
|
||||
new file mode 100644
|
||||
index 0000000..e69de29
|
||||
diff --git a/node_modules/expo-notifications/android/.idea/.gitignore b/node_modules/expo-notifications/android/.idea/.gitignore
|
||||
new file mode 100644
|
||||
index 0000000..26d3352
|
||||
--- /dev/null
|
||||
+++ b/node_modules/expo-notifications/android/.idea/.gitignore
|
||||
@@ -0,0 +1,3 @@
|
||||
+# Default ignored files
|
||||
+/shelf/
|
||||
+/workspace.xml
|
||||
diff --git a/node_modules/expo-notifications/android/.idea/AndroidProjectSystem.xml b/node_modules/expo-notifications/android/.idea/AndroidProjectSystem.xml
|
||||
new file mode 100644
|
||||
index 0000000..4a53bee
|
||||
--- /dev/null
|
||||
+++ b/node_modules/expo-notifications/android/.idea/AndroidProjectSystem.xml
|
||||
@@ -0,0 +1,6 @@
|
||||
+<?xml version="1.0" encoding="UTF-8"?>
|
||||
+<project version="4">
|
||||
+ <component name="AndroidProjectSystem">
|
||||
+ <option name="providerId" value="com.android.tools.idea.GradleProjectSystem" />
|
||||
+ </component>
|
||||
+</project>
|
||||
\ No newline at end of file
|
||||
diff --git a/node_modules/expo-notifications/android/.idea/caches/deviceStreaming.xml b/node_modules/expo-notifications/android/.idea/caches/deviceStreaming.xml
|
||||
new file mode 100644
|
||||
index 0000000..9e9ba09
|
||||
--- /dev/null
|
||||
+++ b/node_modules/expo-notifications/android/.idea/caches/deviceStreaming.xml
|
||||
@@ -0,0 +1,607 @@
|
||||
+<?xml version="1.0" encoding="UTF-8"?>
|
||||
+<project version="4">
|
||||
+ <component name="DeviceStreaming">
|
||||
+ <option name="deviceSelectionList">
|
||||
+ <list>
|
||||
+ <PersistentDeviceSelectionData>
|
||||
+ <option name="api" value="27" />
|
||||
+ <option name="brand" value="DOCOMO" />
|
||||
+ <option name="codename" value="F01L" />
|
||||
+ <option name="id" value="F01L" />
|
||||
+ <option name="labId" value="google" />
|
||||
+ <option name="manufacturer" value="FUJITSU" />
|
||||
+ <option name="name" value="F-01L" />
|
||||
+ <option name="screenDensity" value="360" />
|
||||
+ <option name="screenX" value="720" />
|
||||
+ <option name="screenY" value="1280" />
|
||||
+ </PersistentDeviceSelectionData>
|
||||
+ <PersistentDeviceSelectionData>
|
||||
+ <option name="api" value="34" />
|
||||
+ <option name="brand" value="OnePlus" />
|
||||
+ <option name="codename" value="OP5552L1" />
|
||||
+ <option name="id" value="OP5552L1" />
|
||||
+ <option name="labId" value="google" />
|
||||
+ <option name="manufacturer" value="OnePlus" />
|
||||
+ <option name="name" value="CPH2415" />
|
||||
+ <option name="screenDensity" value="480" />
|
||||
+ <option name="screenX" value="1080" />
|
||||
+ <option name="screenY" value="2412" />
|
||||
+ </PersistentDeviceSelectionData>
|
||||
+ <PersistentDeviceSelectionData>
|
||||
+ <option name="api" value="34" />
|
||||
+ <option name="brand" value="OPPO" />
|
||||
+ <option name="codename" value="OP573DL1" />
|
||||
+ <option name="id" value="OP573DL1" />
|
||||
+ <option name="labId" value="google" />
|
||||
+ <option name="manufacturer" value="OPPO" />
|
||||
+ <option name="name" value="CPH2557" />
|
||||
+ <option name="screenDensity" value="480" />
|
||||
+ <option name="screenX" value="1080" />
|
||||
+ <option name="screenY" value="2400" />
|
||||
+ </PersistentDeviceSelectionData>
|
||||
+ <PersistentDeviceSelectionData>
|
||||
+ <option name="api" value="28" />
|
||||
+ <option name="brand" value="DOCOMO" />
|
||||
+ <option name="codename" value="SH-01L" />
|
||||
+ <option name="id" value="SH-01L" />
|
||||
+ <option name="labId" value="google" />
|
||||
+ <option name="manufacturer" value="SHARP" />
|
||||
+ <option name="name" value="AQUOS sense2 SH-01L" />
|
||||
+ <option name="screenDensity" value="480" />
|
||||
+ <option name="screenX" value="1080" />
|
||||
+ <option name="screenY" value="2160" />
|
||||
+ </PersistentDeviceSelectionData>
|
||||
+ <PersistentDeviceSelectionData>
|
||||
+ <option name="api" value="34" />
|
||||
+ <option name="brand" value="Lenovo" />
|
||||
+ <option name="codename" value="TB370FU" />
|
||||
+ <option name="formFactor" value="Tablet" />
|
||||
+ <option name="id" value="TB370FU" />
|
||||
+ <option name="labId" value="google" />
|
||||
+ <option name="manufacturer" value="Lenovo" />
|
||||
+ <option name="name" value="Tab P12" />
|
||||
+ <option name="screenDensity" value="340" />
|
||||
+ <option name="screenX" value="1840" />
|
||||
+ <option name="screenY" value="2944" />
|
||||
+ </PersistentDeviceSelectionData>
|
||||
+ <PersistentDeviceSelectionData>
|
||||
+ <option name="api" value="34" />
|
||||
+ <option name="brand" value="samsung" />
|
||||
+ <option name="codename" value="a15" />
|
||||
+ <option name="id" value="a15" />
|
||||
+ <option name="labId" value="google" />
|
||||
+ <option name="manufacturer" value="Samsung" />
|
||||
+ <option name="name" value="A15" />
|
||||
+ <option name="screenDensity" value="450" />
|
||||
+ <option name="screenX" value="1080" />
|
||||
+ <option name="screenY" value="2340" />
|
||||
+ </PersistentDeviceSelectionData>
|
||||
+ <PersistentDeviceSelectionData>
|
||||
+ <option name="api" value="34" />
|
||||
+ <option name="brand" value="samsung" />
|
||||
+ <option name="codename" value="a35x" />
|
||||
+ <option name="id" value="a35x" />
|
||||
+ <option name="labId" value="google" />
|
||||
+ <option name="manufacturer" value="Samsung" />
|
||||
+ <option name="name" value="A35" />
|
||||
+ <option name="screenDensity" value="450" />
|
||||
+ <option name="screenX" value="1080" />
|
||||
+ <option name="screenY" value="2340" />
|
||||
+ </PersistentDeviceSelectionData>
|
||||
+ <PersistentDeviceSelectionData>
|
||||
+ <option name="api" value="31" />
|
||||
+ <option name="brand" value="samsung" />
|
||||
+ <option name="codename" value="a51" />
|
||||
+ <option name="id" value="a51" />
|
||||
+ <option name="labId" value="google" />
|
||||
+ <option name="manufacturer" value="Samsung" />
|
||||
+ <option name="name" value="Galaxy A51" />
|
||||
+ <option name="screenDensity" value="420" />
|
||||
+ <option name="screenX" value="1080" />
|
||||
+ <option name="screenY" value="2400" />
|
||||
+ </PersistentDeviceSelectionData>
|
||||
+ <PersistentDeviceSelectionData>
|
||||
+ <option name="api" value="34" />
|
||||
+ <option name="brand" value="google" />
|
||||
+ <option name="codename" value="akita" />
|
||||
+ <option name="id" value="akita" />
|
||||
+ <option name="labId" value="google" />
|
||||
+ <option name="manufacturer" value="Google" />
|
||||
+ <option name="name" value="Pixel 8a" />
|
||||
+ <option name="screenDensity" value="420" />
|
||||
+ <option name="screenX" value="1080" />
|
||||
+ <option name="screenY" value="2400" />
|
||||
+ </PersistentDeviceSelectionData>
|
||||
+ <PersistentDeviceSelectionData>
|
||||
+ <option name="api" value="34" />
|
||||
+ <option name="brand" value="motorola" />
|
||||
+ <option name="codename" value="arcfox" />
|
||||
+ <option name="id" value="arcfox" />
|
||||
+ <option name="labId" value="google" />
|
||||
+ <option name="manufacturer" value="Motorola" />
|
||||
+ <option name="name" value="razr plus 2024" />
|
||||
+ <option name="screenDensity" value="360" />
|
||||
+ <option name="screenX" value="1080" />
|
||||
+ <option name="screenY" value="1272" />
|
||||
+ </PersistentDeviceSelectionData>
|
||||
+ <PersistentDeviceSelectionData>
|
||||
+ <option name="api" value="33" />
|
||||
+ <option name="brand" value="motorola" />
|
||||
+ <option name="codename" value="austin" />
|
||||
+ <option name="id" value="austin" />
|
||||
+ <option name="labId" value="google" />
|
||||
+ <option name="manufacturer" value="Motorola" />
|
||||
+ <option name="name" value="moto g 5G (2022)" />
|
||||
+ <option name="screenDensity" value="280" />
|
||||
+ <option name="screenX" value="720" />
|
||||
+ <option name="screenY" value="1600" />
|
||||
+ </PersistentDeviceSelectionData>
|
||||
+ <PersistentDeviceSelectionData>
|
||||
+ <option name="api" value="33" />
|
||||
+ <option name="brand" value="samsung" />
|
||||
+ <option name="codename" value="b0q" />
|
||||
+ <option name="id" value="b0q" />
|
||||
+ <option name="labId" value="google" />
|
||||
+ <option name="manufacturer" value="Samsung" />
|
||||
+ <option name="name" value="Galaxy S22 Ultra" />
|
||||
+ <option name="screenDensity" value="600" />
|
||||
+ <option name="screenX" value="1440" />
|
||||
+ <option name="screenY" value="3088" />
|
||||
+ </PersistentDeviceSelectionData>
|
||||
+ <PersistentDeviceSelectionData>
|
||||
+ <option name="api" value="32" />
|
||||
+ <option name="brand" value="google" />
|
||||
+ <option name="codename" value="bluejay" />
|
||||
+ <option name="id" value="bluejay" />
|
||||
+ <option name="labId" value="google" />
|
||||
+ <option name="manufacturer" value="Google" />
|
||||
+ <option name="name" value="Pixel 6a" />
|
||||
+ <option name="screenDensity" value="420" />
|
||||
+ <option name="screenX" value="1080" />
|
||||
+ <option name="screenY" value="2400" />
|
||||
+ </PersistentDeviceSelectionData>
|
||||
+ <PersistentDeviceSelectionData>
|
||||
+ <option name="api" value="34" />
|
||||
+ <option name="brand" value="google" />
|
||||
+ <option name="codename" value="caiman" />
|
||||
+ <option name="id" value="caiman" />
|
||||
+ <option name="labId" value="google" />
|
||||
+ <option name="manufacturer" value="Google" />
|
||||
+ <option name="name" value="Pixel 9 Pro" />
|
||||
+ <option name="screenDensity" value="360" />
|
||||
+ <option name="screenX" value="960" />
|
||||
+ <option name="screenY" value="2142" />
|
||||
+ </PersistentDeviceSelectionData>
|
||||
+ <PersistentDeviceSelectionData>
|
||||
+ <option name="api" value="34" />
|
||||
+ <option name="brand" value="google" />
|
||||
+ <option name="codename" value="comet" />
|
||||
+ <option name="default" value="true" />
|
||||
+ <option name="id" value="comet" />
|
||||
+ <option name="labId" value="google" />
|
||||
+ <option name="manufacturer" value="Google" />
|
||||
+ <option name="name" value="Pixel 9 Pro Fold" />
|
||||
+ <option name="screenDensity" value="390" />
|
||||
+ <option name="screenX" value="2076" />
|
||||
+ <option name="screenY" value="2152" />
|
||||
+ </PersistentDeviceSelectionData>
|
||||
+ <PersistentDeviceSelectionData>
|
||||
+ <option name="api" value="29" />
|
||||
+ <option name="brand" value="samsung" />
|
||||
+ <option name="codename" value="crownqlteue" />
|
||||
+ <option name="id" value="crownqlteue" />
|
||||
+ <option name="labId" value="google" />
|
||||
+ <option name="manufacturer" value="Samsung" />
|
||||
+ <option name="name" value="Galaxy Note9" />
|
||||
+ <option name="screenDensity" value="420" />
|
||||
+ <option name="screenX" value="2220" />
|
||||
+ <option name="screenY" value="1080" />
|
||||
+ </PersistentDeviceSelectionData>
|
||||
+ <PersistentDeviceSelectionData>
|
||||
+ <option name="api" value="34" />
|
||||
+ <option name="brand" value="samsung" />
|
||||
+ <option name="codename" value="dm2q" />
|
||||
+ <option name="id" value="dm2q" />
|
||||
+ <option name="labId" value="google" />
|
||||
+ <option name="manufacturer" value="Samsung" />
|
||||
+ <option name="name" value="S23 Plus" />
|
||||
+ <option name="screenDensity" value="450" />
|
||||
+ <option name="screenX" value="1080" />
|
||||
+ <option name="screenY" value="2340" />
|
||||
+ </PersistentDeviceSelectionData>
|
||||
+ <PersistentDeviceSelectionData>
|
||||
+ <option name="api" value="34" />
|
||||
+ <option name="brand" value="samsung" />
|
||||
+ <option name="codename" value="dm3q" />
|
||||
+ <option name="id" value="dm3q" />
|
||||
+ <option name="labId" value="google" />
|
||||
+ <option name="manufacturer" value="Samsung" />
|
||||
+ <option name="name" value="Galaxy S23 Ultra" />
|
||||
+ <option name="screenDensity" value="600" />
|
||||
+ <option name="screenX" value="1440" />
|
||||
+ <option name="screenY" value="3088" />
|
||||
+ </PersistentDeviceSelectionData>
|
||||
+ <PersistentDeviceSelectionData>
|
||||
+ <option name="api" value="34" />
|
||||
+ <option name="brand" value="samsung" />
|
||||
+ <option name="codename" value="e1q" />
|
||||
+ <option name="default" value="true" />
|
||||
+ <option name="id" value="e1q" />
|
||||
+ <option name="labId" value="google" />
|
||||
+ <option name="manufacturer" value="Samsung" />
|
||||
+ <option name="name" value="Galaxy S24" />
|
||||
+ <option name="screenDensity" value="480" />
|
||||
+ <option name="screenX" value="1080" />
|
||||
+ <option name="screenY" value="2340" />
|
||||
+ </PersistentDeviceSelectionData>
|
||||
+ <PersistentDeviceSelectionData>
|
||||
+ <option name="api" value="34" />
|
||||
+ <option name="brand" value="samsung" />
|
||||
+ <option name="codename" value="e3q" />
|
||||
+ <option name="id" value="e3q" />
|
||||
+ <option name="labId" value="google" />
|
||||
+ <option name="manufacturer" value="Samsung" />
|
||||
+ <option name="name" value="Galaxy S24 Ultra" />
|
||||
+ <option name="screenDensity" value="450" />
|
||||
+ <option name="screenX" value="1440" />
|
||||
+ <option name="screenY" value="3120" />
|
||||
+ </PersistentDeviceSelectionData>
|
||||
+ <PersistentDeviceSelectionData>
|
||||
+ <option name="api" value="33" />
|
||||
+ <option name="brand" value="google" />
|
||||
+ <option name="codename" value="eos" />
|
||||
+ <option name="id" value="eos" />
|
||||
+ <option name="labId" value="google" />
|
||||
+ <option name="manufacturer" value="Google" />
|
||||
+ <option name="name" value="Eos" />
|
||||
+ <option name="screenDensity" value="320" />
|
||||
+ <option name="screenX" value="384" />
|
||||
+ <option name="screenY" value="384" />
|
||||
+ </PersistentDeviceSelectionData>
|
||||
+ <PersistentDeviceSelectionData>
|
||||
+ <option name="api" value="33" />
|
||||
+ <option name="brand" value="google" />
|
||||
+ <option name="codename" value="felix" />
|
||||
+ <option name="id" value="felix" />
|
||||
+ <option name="labId" value="google" />
|
||||
+ <option name="manufacturer" value="Google" />
|
||||
+ <option name="name" value="Pixel Fold" />
|
||||
+ <option name="screenDensity" value="420" />
|
||||
+ <option name="screenX" value="2208" />
|
||||
+ <option name="screenY" value="1840" />
|
||||
+ </PersistentDeviceSelectionData>
|
||||
+ <PersistentDeviceSelectionData>
|
||||
+ <option name="api" value="34" />
|
||||
+ <option name="brand" value="google" />
|
||||
+ <option name="codename" value="felix" />
|
||||
+ <option name="id" value="felix" />
|
||||
+ <option name="labId" value="google" />
|
||||
+ <option name="manufacturer" value="Google" />
|
||||
+ <option name="name" value="Pixel Fold" />
|
||||
+ <option name="screenDensity" value="420" />
|
||||
+ <option name="screenX" value="2208" />
|
||||
+ <option name="screenY" value="1840" />
|
||||
+ </PersistentDeviceSelectionData>
|
||||
+ <PersistentDeviceSelectionData>
|
||||
+ <option name="api" value="33" />
|
||||
+ <option name="brand" value="google" />
|
||||
+ <option name="codename" value="felix_camera" />
|
||||
+ <option name="id" value="felix_camera" />
|
||||
+ <option name="labId" value="google" />
|
||||
+ <option name="manufacturer" value="Google" />
|
||||
+ <option name="name" value="Pixel Fold (Camera-enabled)" />
|
||||
+ <option name="screenDensity" value="420" />
|
||||
+ <option name="screenX" value="2208" />
|
||||
+ <option name="screenY" value="1840" />
|
||||
+ </PersistentDeviceSelectionData>
|
||||
+ <PersistentDeviceSelectionData>
|
||||
+ <option name="api" value="34" />
|
||||
+ <option name="brand" value="motorola" />
|
||||
+ <option name="codename" value="fogona" />
|
||||
+ <option name="id" value="fogona" />
|
||||
+ <option name="labId" value="google" />
|
||||
+ <option name="manufacturer" value="Motorola" />
|
||||
+ <option name="name" value="moto g play - 2024" />
|
||||
+ <option name="screenDensity" value="280" />
|
||||
+ <option name="screenX" value="720" />
|
||||
+ <option name="screenY" value="1600" />
|
||||
+ </PersistentDeviceSelectionData>
|
||||
+ <PersistentDeviceSelectionData>
|
||||
+ <option name="api" value="34" />
|
||||
+ <option name="brand" value="samsung" />
|
||||
+ <option name="codename" value="g0q" />
|
||||
+ <option name="id" value="g0q" />
|
||||
+ <option name="labId" value="google" />
|
||||
+ <option name="manufacturer" value="Samsung" />
|
||||
+ <option name="name" value="SM-S906U1" />
|
||||
+ <option name="screenDensity" value="450" />
|
||||
+ <option name="screenX" value="1080" />
|
||||
+ <option name="screenY" value="2340" />
|
||||
+ </PersistentDeviceSelectionData>
|
||||
+ <PersistentDeviceSelectionData>
|
||||
+ <option name="api" value="34" />
|
||||
+ <option name="brand" value="samsung" />
|
||||
+ <option name="codename" value="gta9pwifi" />
|
||||
+ <option name="id" value="gta9pwifi" />
|
||||
+ <option name="labId" value="google" />
|
||||
+ <option name="manufacturer" value="Samsung" />
|
||||
+ <option name="name" value="SM-X210" />
|
||||
+ <option name="screenDensity" value="240" />
|
||||
+ <option name="screenX" value="1200" />
|
||||
+ <option name="screenY" value="1920" />
|
||||
+ </PersistentDeviceSelectionData>
|
||||
+ <PersistentDeviceSelectionData>
|
||||
+ <option name="api" value="34" />
|
||||
+ <option name="brand" value="samsung" />
|
||||
+ <option name="codename" value="gts7xllite" />
|
||||
+ <option name="id" value="gts7xllite" />
|
||||
+ <option name="labId" value="google" />
|
||||
+ <option name="manufacturer" value="Samsung" />
|
||||
+ <option name="name" value="SM-T738U" />
|
||||
+ <option name="screenDensity" value="340" />
|
||||
+ <option name="screenX" value="1600" />
|
||||
+ <option name="screenY" value="2560" />
|
||||
+ </PersistentDeviceSelectionData>
|
||||
+ <PersistentDeviceSelectionData>
|
||||
+ <option name="api" value="33" />
|
||||
+ <option name="brand" value="samsung" />
|
||||
+ <option name="codename" value="gts8uwifi" />
|
||||
+ <option name="formFactor" value="Tablet" />
|
||||
+ <option name="id" value="gts8uwifi" />
|
||||
+ <option name="labId" value="google" />
|
||||
+ <option name="manufacturer" value="Samsung" />
|
||||
+ <option name="name" value="Galaxy Tab S8 Ultra" />
|
||||
+ <option name="screenDensity" value="320" />
|
||||
+ <option name="screenX" value="1848" />
|
||||
+ <option name="screenY" value="2960" />
|
||||
+ </PersistentDeviceSelectionData>
|
||||
+ <PersistentDeviceSelectionData>
|
||||
+ <option name="api" value="34" />
|
||||
+ <option name="brand" value="samsung" />
|
||||
+ <option name="codename" value="gts8wifi" />
|
||||
+ <option name="formFactor" value="Tablet" />
|
||||
+ <option name="id" value="gts8wifi" />
|
||||
+ <option name="labId" value="google" />
|
||||
+ <option name="manufacturer" value="Samsung" />
|
||||
+ <option name="name" value="Galaxy Tab S8" />
|
||||
+ <option name="screenDensity" value="274" />
|
||||
+ <option name="screenX" value="1600" />
|
||||
+ <option name="screenY" value="2560" />
|
||||
+ </PersistentDeviceSelectionData>
|
||||
+ <PersistentDeviceSelectionData>
|
||||
+ <option name="api" value="34" />
|
||||
+ <option name="brand" value="samsung" />
|
||||
+ <option name="codename" value="gts9fe" />
|
||||
+ <option name="id" value="gts9fe" />
|
||||
+ <option name="labId" value="google" />
|
||||
+ <option name="manufacturer" value="Samsung" />
|
||||
+ <option name="name" value="Galaxy Tab S9 FE 5G" />
|
||||
+ <option name="screenDensity" value="280" />
|
||||
+ <option name="screenX" value="1440" />
|
||||
+ <option name="screenY" value="2304" />
|
||||
+ </PersistentDeviceSelectionData>
|
||||
+ <PersistentDeviceSelectionData>
|
||||
+ <option name="api" value="34" />
|
||||
+ <option name="brand" value="google" />
|
||||
+ <option name="codename" value="husky" />
|
||||
+ <option name="id" value="husky" />
|
||||
+ <option name="labId" value="google" />
|
||||
+ <option name="manufacturer" value="Google" />
|
||||
+ <option name="name" value="Pixel 8 Pro" />
|
||||
+ <option name="screenDensity" value="390" />
|
||||
+ <option name="screenX" value="1008" />
|
||||
+ <option name="screenY" value="2244" />
|
||||
+ </PersistentDeviceSelectionData>
|
||||
+ <PersistentDeviceSelectionData>
|
||||
+ <option name="api" value="30" />
|
||||
+ <option name="brand" value="motorola" />
|
||||
+ <option name="codename" value="java" />
|
||||
+ <option name="id" value="java" />
|
||||
+ <option name="labId" value="google" />
|
||||
+ <option name="manufacturer" value="Motorola" />
|
||||
+ <option name="name" value="G20" />
|
||||
+ <option name="screenDensity" value="280" />
|
||||
+ <option name="screenX" value="720" />
|
||||
+ <option name="screenY" value="1600" />
|
||||
+ </PersistentDeviceSelectionData>
|
||||
+ <PersistentDeviceSelectionData>
|
||||
+ <option name="api" value="34" />
|
||||
+ <option name="brand" value="google" />
|
||||
+ <option name="codename" value="komodo" />
|
||||
+ <option name="id" value="komodo" />
|
||||
+ <option name="labId" value="google" />
|
||||
+ <option name="manufacturer" value="Google" />
|
||||
+ <option name="name" value="Pixel 9 Pro XL" />
|
||||
+ <option name="screenDensity" value="360" />
|
||||
+ <option name="screenX" value="1008" />
|
||||
+ <option name="screenY" value="2244" />
|
||||
+ </PersistentDeviceSelectionData>
|
||||
+ <PersistentDeviceSelectionData>
|
||||
+ <option name="api" value="33" />
|
||||
+ <option name="brand" value="google" />
|
||||
+ <option name="codename" value="lynx" />
|
||||
+ <option name="id" value="lynx" />
|
||||
+ <option name="labId" value="google" />
|
||||
+ <option name="manufacturer" value="Google" />
|
||||
+ <option name="name" value="Pixel 7a" />
|
||||
+ <option name="screenDensity" value="420" />
|
||||
+ <option name="screenX" value="1080" />
|
||||
+ <option name="screenY" value="2400" />
|
||||
+ </PersistentDeviceSelectionData>
|
||||
+ <PersistentDeviceSelectionData>
|
||||
+ <option name="api" value="33" />
|
||||
+ <option name="brand" value="motorola" />
|
||||
+ <option name="codename" value="maui" />
|
||||
+ <option name="id" value="maui" />
|
||||
+ <option name="labId" value="google" />
|
||||
+ <option name="manufacturer" value="Motorola" />
|
||||
+ <option name="name" value="moto g play - 2023" />
|
||||
+ <option name="screenDensity" value="280" />
|
||||
+ <option name="screenX" value="720" />
|
||||
+ <option name="screenY" value="1600" />
|
||||
+ </PersistentDeviceSelectionData>
|
||||
+ <PersistentDeviceSelectionData>
|
||||
+ <option name="api" value="34" />
|
||||
+ <option name="brand" value="samsung" />
|
||||
+ <option name="codename" value="o1q" />
|
||||
+ <option name="id" value="o1q" />
|
||||
+ <option name="labId" value="google" />
|
||||
+ <option name="manufacturer" value="Samsung" />
|
||||
+ <option name="name" value="Galaxy S21" />
|
||||
+ <option name="screenDensity" value="421" />
|
||||
+ <option name="screenX" value="1080" />
|
||||
+ <option name="screenY" value="2400" />
|
||||
+ </PersistentDeviceSelectionData>
|
||||
+ <PersistentDeviceSelectionData>
|
||||
+ <option name="api" value="31" />
|
||||
+ <option name="brand" value="google" />
|
||||
+ <option name="codename" value="oriole" />
|
||||
+ <option name="id" value="oriole" />
|
||||
+ <option name="labId" value="google" />
|
||||
+ <option name="manufacturer" value="Google" />
|
||||
+ <option name="name" value="Pixel 6" />
|
||||
+ <option name="screenDensity" value="420" />
|
||||
+ <option name="screenX" value="1080" />
|
||||
+ <option name="screenY" value="2400" />
|
||||
+ </PersistentDeviceSelectionData>
|
||||
+ <PersistentDeviceSelectionData>
|
||||
+ <option name="api" value="33" />
|
||||
+ <option name="brand" value="google" />
|
||||
+ <option name="codename" value="panther" />
|
||||
+ <option name="id" value="panther" />
|
||||
+ <option name="labId" value="google" />
|
||||
+ <option name="manufacturer" value="Google" />
|
||||
+ <option name="name" value="Pixel 7" />
|
||||
+ <option name="screenDensity" value="420" />
|
||||
+ <option name="screenX" value="1080" />
|
||||
+ <option name="screenY" value="2400" />
|
||||
+ </PersistentDeviceSelectionData>
|
||||
+ <PersistentDeviceSelectionData>
|
||||
+ <option name="api" value="34" />
|
||||
+ <option name="brand" value="samsung" />
|
||||
+ <option name="codename" value="q5q" />
|
||||
+ <option name="id" value="q5q" />
|
||||
+ <option name="labId" value="google" />
|
||||
+ <option name="manufacturer" value="Samsung" />
|
||||
+ <option name="name" value="Galaxy Z Fold5" />
|
||||
+ <option name="screenDensity" value="420" />
|
||||
+ <option name="screenX" value="1812" />
|
||||
+ <option name="screenY" value="2176" />
|
||||
+ </PersistentDeviceSelectionData>
|
||||
+ <PersistentDeviceSelectionData>
|
||||
+ <option name="api" value="34" />
|
||||
+ <option name="brand" value="samsung" />
|
||||
+ <option name="codename" value="q6q" />
|
||||
+ <option name="id" value="q6q" />
|
||||
+ <option name="labId" value="google" />
|
||||
+ <option name="manufacturer" value="Samsung" />
|
||||
+ <option name="name" value="Galaxy Z Fold6" />
|
||||
+ <option name="screenDensity" value="420" />
|
||||
+ <option name="screenX" value="1856" />
|
||||
+ <option name="screenY" value="2160" />
|
||||
+ </PersistentDeviceSelectionData>
|
||||
+ <PersistentDeviceSelectionData>
|
||||
+ <option name="api" value="30" />
|
||||
+ <option name="brand" value="google" />
|
||||
+ <option name="codename" value="r11" />
|
||||
+ <option name="formFactor" value="Wear OS" />
|
||||
+ <option name="id" value="r11" />
|
||||
+ <option name="labId" value="google" />
|
||||
+ <option name="manufacturer" value="Google" />
|
||||
+ <option name="name" value="Pixel Watch" />
|
||||
+ <option name="screenDensity" value="320" />
|
||||
+ <option name="screenX" value="384" />
|
||||
+ <option name="screenY" value="384" />
|
||||
+ <option name="type" value="WEAR_OS" />
|
||||
+ </PersistentDeviceSelectionData>
|
||||
+ <PersistentDeviceSelectionData>
|
||||
+ <option name="api" value="34" />
|
||||
+ <option name="brand" value="samsung" />
|
||||
+ <option name="codename" value="r11q" />
|
||||
+ <option name="id" value="r11q" />
|
||||
+ <option name="labId" value="google" />
|
||||
+ <option name="manufacturer" value="Samsung" />
|
||||
+ <option name="name" value="SM-S711U" />
|
||||
+ <option name="screenDensity" value="450" />
|
||||
+ <option name="screenX" value="1080" />
|
||||
+ <option name="screenY" value="2340" />
|
||||
+ </PersistentDeviceSelectionData>
|
||||
+ <PersistentDeviceSelectionData>
|
||||
+ <option name="api" value="30" />
|
||||
+ <option name="brand" value="google" />
|
||||
+ <option name="codename" value="redfin" />
|
||||
+ <option name="id" value="redfin" />
|
||||
+ <option name="labId" value="google" />
|
||||
+ <option name="manufacturer" value="Google" />
|
||||
+ <option name="name" value="Pixel 5" />
|
||||
+ <option name="screenDensity" value="440" />
|
||||
+ <option name="screenX" value="1080" />
|
||||
+ <option name="screenY" value="2340" />
|
||||
+ </PersistentDeviceSelectionData>
|
||||
+ <PersistentDeviceSelectionData>
|
||||
+ <option name="api" value="34" />
|
||||
+ <option name="brand" value="google" />
|
||||
+ <option name="codename" value="shiba" />
|
||||
+ <option name="id" value="shiba" />
|
||||
+ <option name="labId" value="google" />
|
||||
+ <option name="manufacturer" value="Google" />
|
||||
+ <option name="name" value="Pixel 8" />
|
||||
+ <option name="screenDensity" value="420" />
|
||||
+ <option name="screenX" value="1080" />
|
||||
+ <option name="screenY" value="2400" />
|
||||
+ </PersistentDeviceSelectionData>
|
||||
+ <PersistentDeviceSelectionData>
|
||||
+ <option name="api" value="34" />
|
||||
+ <option name="brand" value="samsung" />
|
||||
+ <option name="codename" value="t2q" />
|
||||
+ <option name="id" value="t2q" />
|
||||
+ <option name="labId" value="google" />
|
||||
+ <option name="manufacturer" value="Samsung" />
|
||||
+ <option name="name" value="Galaxy S21 Plus" />
|
||||
+ <option name="screenDensity" value="394" />
|
||||
+ <option name="screenX" value="1080" />
|
||||
+ <option name="screenY" value="2400" />
|
||||
+ </PersistentDeviceSelectionData>
|
||||
+ <PersistentDeviceSelectionData>
|
||||
+ <option name="api" value="33" />
|
||||
+ <option name="brand" value="google" />
|
||||
+ <option name="codename" value="tangorpro" />
|
||||
+ <option name="formFactor" value="Tablet" />
|
||||
+ <option name="id" value="tangorpro" />
|
||||
+ <option name="labId" value="google" />
|
||||
+ <option name="manufacturer" value="Google" />
|
||||
+ <option name="name" value="Pixel Tablet" />
|
||||
+ <option name="screenDensity" value="320" />
|
||||
+ <option name="screenX" value="1600" />
|
||||
+ <option name="screenY" value="2560" />
|
||||
+ </PersistentDeviceSelectionData>
|
||||
+ <PersistentDeviceSelectionData>
|
||||
+ <option name="api" value="34" />
|
||||
+ <option name="brand" value="google" />
|
||||
+ <option name="codename" value="tokay" />
|
||||
+ <option name="default" value="true" />
|
||||
+ <option name="id" value="tokay" />
|
||||
+ <option name="labId" value="google" />
|
||||
+ <option name="manufacturer" value="Google" />
|
||||
+ <option name="name" value="Pixel 9" />
|
||||
+ <option name="screenDensity" value="420" />
|
||||
+ <option name="screenX" value="1080" />
|
||||
+ <option name="screenY" value="2424" />
|
||||
+ </PersistentDeviceSelectionData>
|
||||
+ <PersistentDeviceSelectionData>
|
||||
+ <option name="api" value="35" />
|
||||
+ <option name="brand" value="google" />
|
||||
+ <option name="codename" value="tokay" />
|
||||
+ <option name="default" value="true" />
|
||||
+ <option name="id" value="tokay" />
|
||||
+ <option name="labId" value="google" />
|
||||
+ <option name="manufacturer" value="Google" />
|
||||
+ <option name="name" value="Pixel 9" />
|
||||
+ <option name="screenDensity" value="420" />
|
||||
+ <option name="screenX" value="1080" />
|
||||
+ <option name="screenY" value="2424" />
|
||||
+ </PersistentDeviceSelectionData>
|
||||
+ </list>
|
||||
+ </option>
|
||||
+ </component>
|
||||
+</project>
|
||||
\ No newline at end of file
|
||||
diff --git a/node_modules/expo-notifications/android/.idea/gradle.xml b/node_modules/expo-notifications/android/.idea/gradle.xml
|
||||
new file mode 100644
|
||||
index 0000000..b838237
|
||||
--- /dev/null
|
||||
+++ b/node_modules/expo-notifications/android/.idea/gradle.xml
|
||||
@@ -0,0 +1,12 @@
|
||||
+<?xml version="1.0" encoding="UTF-8"?>
|
||||
+<project version="4">
|
||||
+ <component name="GradleSettings">
|
||||
+ <option name="linkedExternalProjectsSettings">
|
||||
+ <GradleProjectSettings>
|
||||
+ <option name="testRunner" value="CHOOSE_PER_TEST" />
|
||||
+ <option name="externalProjectPath" value="$PROJECT_DIR$" />
|
||||
+ <option name="gradleJvm" value="#GRADLE_LOCAL_JAVA_HOME" />
|
||||
+ </GradleProjectSettings>
|
||||
+ </option>
|
||||
+ </component>
|
||||
+</project>
|
||||
\ No newline at end of file
|
||||
diff --git a/node_modules/expo-notifications/android/.idea/migrations.xml b/node_modules/expo-notifications/android/.idea/migrations.xml
|
||||
new file mode 100644
|
||||
index 0000000..f8051a6
|
||||
--- /dev/null
|
||||
+++ b/node_modules/expo-notifications/android/.idea/migrations.xml
|
||||
@@ -0,0 +1,10 @@
|
||||
+<?xml version="1.0" encoding="UTF-8"?>
|
||||
+<project version="4">
|
||||
+ <component name="ProjectMigrations">
|
||||
+ <option name="MigrateToGradleLocalJavaHome">
|
||||
+ <set>
|
||||
+ <option value="$PROJECT_DIR$" />
|
||||
+ </set>
|
||||
+ </option>
|
||||
+ </component>
|
||||
+</project>
|
||||
\ No newline at end of file
|
||||
diff --git a/node_modules/expo-notifications/android/.idea/misc.xml b/node_modules/expo-notifications/android/.idea/misc.xml
|
||||
new file mode 100644
|
||||
index 0000000..3040d03
|
||||
--- /dev/null
|
||||
+++ b/node_modules/expo-notifications/android/.idea/misc.xml
|
||||
@@ -0,0 +1,10 @@
|
||||
+<?xml version="1.0" encoding="UTF-8"?>
|
||||
+<project version="4">
|
||||
+ <component name="ExternalStorageConfigurationManager" enabled="true" />
|
||||
+ <component name="ProjectRootManager">
|
||||
+ <output url="file://$PROJECT_DIR$/build/classes" />
|
||||
+ </component>
|
||||
+ <component name="ProjectType">
|
||||
+ <option name="id" value="Android" />
|
||||
+ </component>
|
||||
+</project>
|
||||
\ No newline at end of file
|
||||
diff --git a/node_modules/expo-notifications/android/.idea/runConfigurations.xml b/node_modules/expo-notifications/android/.idea/runConfigurations.xml
|
||||
new file mode 100644
|
||||
index 0000000..16660f1
|
||||
--- /dev/null
|
||||
+++ b/node_modules/expo-notifications/android/.idea/runConfigurations.xml
|
||||
@@ -0,0 +1,17 @@
|
||||
+<?xml version="1.0" encoding="UTF-8"?>
|
||||
+<project version="4">
|
||||
+ <component name="RunConfigurationProducerService">
|
||||
+ <option name="ignoredProducers">
|
||||
+ <set>
|
||||
+ <option value="com.intellij.execution.junit.AbstractAllInDirectoryConfigurationProducer" />
|
||||
+ <option value="com.intellij.execution.junit.AllInPackageConfigurationProducer" />
|
||||
+ <option value="com.intellij.execution.junit.PatternConfigurationProducer" />
|
||||
+ <option value="com.intellij.execution.junit.TestInClassConfigurationProducer" />
|
||||
+ <option value="com.intellij.execution.junit.UniqueIdConfigurationProducer" />
|
||||
+ <option value="com.intellij.execution.junit.testDiscovery.JUnitTestDiscoveryConfigurationProducer" />
|
||||
+ <option value="org.jetbrains.kotlin.idea.junit.KotlinJUnitRunConfigurationProducer" />
|
||||
+ <option value="org.jetbrains.kotlin.idea.junit.KotlinPatternConfigurationProducer" />
|
||||
+ </set>
|
||||
+ </option>
|
||||
+ </component>
|
||||
+</project>
|
||||
\ No newline at end of file
|
||||
diff --git a/node_modules/expo-notifications/android/.idea/workspace.xml b/node_modules/expo-notifications/android/.idea/workspace.xml
|
||||
new file mode 100644
|
||||
index 0000000..df26928
|
||||
--- /dev/null
|
||||
+++ b/node_modules/expo-notifications/android/.idea/workspace.xml
|
||||
@@ -0,0 +1,47 @@
|
||||
+<?xml version="1.0" encoding="UTF-8"?>
|
||||
+<project version="4">
|
||||
+ <component name="AutoImportSettings">
|
||||
+ <option name="autoReloadType" value="NONE" />
|
||||
+ </component>
|
||||
+ <component name="ChangeListManager">
|
||||
+ <list default="true" id="fed6a9c0-2e93-4b6e-953a-d1cd1e93b59f" name="Changes" comment="" />
|
||||
+ <option name="SHOW_DIALOG" value="false" />
|
||||
+ <option name="HIGHLIGHT_CONFLICTS" value="true" />
|
||||
+ <option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
|
||||
+ <option name="LAST_RESOLUTION" value="IGNORE" />
|
||||
+ </component>
|
||||
+ <component name="ClangdSettings">
|
||||
+ <option name="formatViaClangd" value="false" />
|
||||
+ </component>
|
||||
+ <component name="ProjectColorInfo"><![CDATA[{
|
||||
+ "associatedIndex": 4
|
||||
+}]]></component>
|
||||
+ <component name="ProjectId" id="2wCjuanPzVGKP91vdmftQVgUlaM" />
|
||||
+ <component name="ProjectViewState">
|
||||
+ <option name="hideEmptyMiddlePackages" value="true" />
|
||||
+ <option name="showLibraryContents" value="true" />
|
||||
+ </component>
|
||||
+ <component name="PropertiesComponent"><![CDATA[{
|
||||
+ "keyToString": {
|
||||
+ "RunOnceActivity.ShowReadmeOnStart": "true",
|
||||
+ "RunOnceActivity.cidr.known.project.marker": "true",
|
||||
+ "RunOnceActivity.readMode.enableVisualFormatting": "true",
|
||||
+ "android.gradle.sync.needed": "true",
|
||||
+ "cf.first.check.clang-format": "false",
|
||||
+ "cidr.known.project.marker": "true",
|
||||
+ "kotlin-language-version-configured": "true",
|
||||
+ "last_opened_file_path": "/Users/hailey/bsky/social-app/node_modules/expo-notifications/android"
|
||||
+ }
|
||||
+}]]></component>
|
||||
+ <component name="SpellCheckerSettings" RuntimeDictionaries="0" Folders="0" CustomDictionaries="0" DefaultDictionary="application-level" UseSingleDictionary="true" transferred="true" />
|
||||
+ <component name="TaskManager">
|
||||
+ <task active="true" id="Default" summary="Default task">
|
||||
+ <changelist id="fed6a9c0-2e93-4b6e-953a-d1cd1e93b59f" name="Changes" comment="" />
|
||||
+ <created>1745552672693</created>
|
||||
+ <option name="number" value="Default" />
|
||||
+ <option name="presentableId" value="Default" />
|
||||
+ <updated>1745552672693</updated>
|
||||
+ </task>
|
||||
+ <servers />
|
||||
+ </component>
|
||||
+</project>
|
||||
\ No newline at end of file
|
||||
diff --git a/node_modules/expo-notifications/android/build.gradle b/node_modules/expo-notifications/android/build.gradle
|
||||
index bc479ee..1ebfa00 100644
|
||||
--- a/node_modules/expo-notifications/android/build.gradle
|
||||
+++ b/node_modules/expo-notifications/android/build.gradle
|
||||
@@ -42,6 +42,7 @@ dependencies {
|
||||
implementation 'com.google.firebase:firebase-messaging:24.0.1'
|
||||
|
||||
implementation 'me.leolin:ShortcutBadger:1.1.22@aar'
|
||||
+ implementation project(':expo-background-notification-handler')
|
||||
|
||||
if (project.findProject(':expo-modules-test-core')) {
|
||||
testImplementation project(':expo-modules-test-core')
|
||||
diff --git a/node_modules/expo-notifications/android/local.properties b/node_modules/expo-notifications/android/local.properties
|
||||
new file mode 100644
|
||||
index 0000000..ab4c86d
|
||||
--- /dev/null
|
||||
+++ b/node_modules/expo-notifications/android/local.properties
|
||||
@@ -0,0 +1,8 @@
|
||||
+## This file must *NOT* be checked into Version Control Systems,
|
||||
+# as it contains information specific to your local configuration.
|
||||
+#
|
||||
+# Location of the SDK. This is only used by Gradle.
|
||||
+# For customization when using a Version Control System, please read the
|
||||
+# header note.
|
||||
+#Thu Apr 24 20:44:32 PDT 2025
|
||||
+sdk.dir=/Users/hailey/Library/Android/sdk
|
||||
diff --git a/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/interfaces/INotificationContent.kt b/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/interfaces/INotificationContent.kt
|
||||
index 7b99e6c..45a450d 100644
|
||||
--- a/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/interfaces/INotificationContent.kt
|
||||
+++ b/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/interfaces/INotificationContent.kt
|
||||
@@ -15,6 +15,7 @@ import org.json.JSONObject
|
||||
* This interface exists to provide a common API for both classes.
|
||||
* */
|
||||
interface INotificationContent : Parcelable {
|
||||
+ val channelId: String?
|
||||
val title: String?
|
||||
val text: String?
|
||||
val subText: String?
|
||||
diff --git a/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/model/NotificationContent.java b/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/model/NotificationContent.java
|
||||
index 191b64e..fe8b3c5 100644
|
||||
--- a/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/model/NotificationContent.java
|
||||
+++ b/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/model/NotificationContent.java
|
||||
@@ -35,6 +35,7 @@ import kotlin.coroutines.Continuation;
|
||||
* Refactoring this class may require a migration strategy for the data stored in SharedPreferences.
|
||||
*/
|
||||
public class NotificationContent implements Parcelable, Serializable, INotificationContent {
|
||||
+ private String mChannelId;
|
||||
private String mTitle;
|
||||
private String mText;
|
||||
private String mSubtitle;
|
||||
@@ -65,6 +66,11 @@ public class NotificationContent implements Parcelable, Serializable, INotificat
|
||||
}
|
||||
};
|
||||
|
||||
+ @Nullable
|
||||
+ public String getChannelId() {
|
||||
+ return mChannelId;
|
||||
+ }
|
||||
+
|
||||
@Nullable
|
||||
public String getTitle() {
|
||||
return mTitle;
|
||||
@@ -158,6 +164,7 @@ public class NotificationContent implements Parcelable, Serializable, INotificat
|
||||
}
|
||||
|
||||
protected NotificationContent(Parcel in) {
|
||||
+ mChannelId = in.readString();
|
||||
mTitle = in.readString();
|
||||
mText = in.readString();
|
||||
mSubtitle = in.readString();
|
||||
@@ -183,6 +190,7 @@ public class NotificationContent implements Parcelable, Serializable, INotificat
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
+ dest.writeString(mChannelId);
|
||||
dest.writeString(mTitle);
|
||||
dest.writeString(mText);
|
||||
dest.writeString(mSubtitle);
|
||||
@@ -203,6 +211,7 @@ public class NotificationContent implements Parcelable, Serializable, INotificat
|
||||
private static final long serialVersionUID = 397666843266836802L;
|
||||
|
||||
private void writeObject(java.io.ObjectOutputStream out) throws IOException {
|
||||
+ out.writeObject(mChannelId);
|
||||
out.writeObject(mTitle);
|
||||
out.writeObject(mText);
|
||||
out.writeObject(mSubtitle);
|
||||
@@ -285,6 +294,11 @@ public class NotificationContent implements Parcelable, Serializable, INotificat
|
||||
useDefaultVibrationPattern();
|
||||
}
|
||||
|
||||
+ public Builder setChannelId(String channelId) {
|
||||
+ content.mChannelId = channelId;
|
||||
+ return this;
|
||||
+ }
|
||||
+
|
||||
public Builder setTitle(String title) {
|
||||
content.mTitle = title;
|
||||
return this;
|
||||
diff --git a/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/model/NotificationData.kt b/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/model/NotificationData.kt
|
||||
index 3af254c..3c77e9d 100644
|
||||
--- a/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/model/NotificationData.kt
|
||||
+++ b/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/model/NotificationData.kt
|
||||
@@ -11,6 +11,9 @@ import org.json.JSONObject
|
||||
* */
|
||||
@JvmInline
|
||||
value class NotificationData(private val data: Map<String, String>) {
|
||||
+ val channelId: String?
|
||||
+ get() = data["channelId"]
|
||||
+
|
||||
val title: String?
|
||||
get() = data["title"]
|
||||
|
||||
diff --git a/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/model/RemoteNotificationContent.kt b/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/model/RemoteNotificationContent.kt
|
||||
index d2cc6cf..6a48ff2 100644
|
||||
--- a/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/model/RemoteNotificationContent.kt
|
||||
+++ b/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/model/RemoteNotificationContent.kt
|
||||
@@ -31,6 +31,8 @@ class RemoteNotificationContent(private val remoteMessage: RemoteMessage) : INot
|
||||
return remoteMessage.notification?.imageUrl != null
|
||||
}
|
||||
|
||||
+ override val channelId = remoteMessage.notification?.channelId ?: notificationData.channelId
|
||||
+
|
||||
override val title = remoteMessage.notification?.title ?: notificationData.title
|
||||
|
||||
override val text = remoteMessage.notification?.body ?: notificationData.message
|
||||
diff --git a/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/presentation/builders/ExpoNotificationBuilder.kt b/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/presentation/builders/ExpoNotificationBuilder.kt
|
||||
index 98f003f..2f745e8 100644
|
||||
--- a/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/presentation/builders/ExpoNotificationBuilder.kt
|
||||
+++ b/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/notifications/presentation/builders/ExpoNotificationBuilder.kt
|
||||
@@ -101,6 +101,9 @@ open class ExpoNotificationBuilder(
|
||||
builder.setOngoing(content.isSticky)
|
||||
|
||||
// see "Notification anatomy" https://developer.android.com/develop/ui/views/notifications#Templates
|
||||
+ content.channelId?.let {
|
||||
+ builder.setChannelId(it)
|
||||
+ }
|
||||
builder.setContentTitle(content.title)
|
||||
builder.setContentText(content.text)
|
||||
builder.setSubText(content.subText)
|
||||
diff --git a/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/service/delegates/FirebaseMessagingDelegate.kt b/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/service/delegates/FirebaseMessagingDelegate.kt
|
||||
index 90ca4ff..9d4cb09 100644
|
||||
--- a/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/service/delegates/FirebaseMessagingDelegate.kt
|
||||
+++ b/node_modules/expo-notifications/android/src/main/java/expo/modules/notifications/service/delegates/FirebaseMessagingDelegate.kt
|
||||
@@ -3,6 +3,9 @@ package expo.modules.notifications.service.delegates
|
||||
import android.content.Context
|
||||
import android.os.Bundle
|
||||
import com.google.firebase.messaging.RemoteMessage
|
||||
+import expo.modules.backgroundnotificationhandler.BackgroundNotificationHandler
|
||||
+import expo.modules.backgroundnotificationhandler.BackgroundNotificationHandlerInterface
|
||||
+import expo.modules.backgroundnotificationhandler.ExpoBackgroundNotificationHandlerModule
|
||||
import expo.modules.interfaces.taskManager.TaskServiceProviderHelper
|
||||
import expo.modules.notifications.notifications.RemoteMessageSerializer
|
||||
import expo.modules.notifications.notifications.background.BackgroundRemoteNotificationTaskConsumer
|
||||
@@ -18,7 +21,7 @@ import expo.modules.notifications.tokens.interfaces.FirebaseTokenListener
|
||||
import java.lang.ref.WeakReference
|
||||
import java.util.*
|
||||
|
||||
-open class FirebaseMessagingDelegate(protected val context: Context) : FirebaseMessagingDelegate {
|
||||
+open class FirebaseMessagingDelegate(protected val context: Context) : FirebaseMessagingDelegate, BackgroundNotificationHandlerInterface{
|
||||
companion object {
|
||||
// Unfortunately we cannot save state between instances of a service other way
|
||||
// than by static properties. Fortunately, using weak references we can
|
||||
@@ -105,8 +108,19 @@ open class FirebaseMessagingDelegate(protected val context: Context) : FirebaseM
|
||||
DebugLogging.logRemoteMessage("FirebaseMessagingDelegate.onMessageReceived: message", remoteMessage)
|
||||
val notification = createNotification(remoteMessage)
|
||||
DebugLogging.logNotification("FirebaseMessagingDelegate.onMessageReceived: notification", notification)
|
||||
- NotificationsService.receive(context, notification)
|
||||
- runTaskManagerTasks(context.applicationContext, RemoteMessageSerializer.toBundle(remoteMessage))
|
||||
+ if (!ExpoBackgroundNotificationHandlerModule.isForegrounded) {
|
||||
+ BackgroundNotificationHandler(context, this).handleMessage(remoteMessage)
|
||||
+ } else {
|
||||
+ NotificationsService.receive(context, notification)
|
||||
+ runTaskManagerTasks(
|
||||
+ context.applicationContext,
|
||||
+ RemoteMessageSerializer.toBundle(remoteMessage)
|
||||
+ )
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ override fun showMessage(remoteMessage: RemoteMessage) {
|
||||
+ NotificationsService.receive(context, createNotification(remoteMessage))
|
||||
}
|
||||
|
||||
protected fun createNotification(remoteMessage: RemoteMessage): Notification {
|
@ -1,366 +0,0 @@
|
||||
diff --git a/node_modules/react-native/Libraries/StyleSheet/StyleSheetTypes.d.ts b/node_modules/react-native/Libraries/StyleSheet/StyleSheetTypes.d.ts
|
||||
index 62f52a7..ca30165 100644
|
||||
--- a/node_modules/react-native/Libraries/StyleSheet/StyleSheetTypes.d.ts
|
||||
+++ b/node_modules/react-native/Libraries/StyleSheet/StyleSheetTypes.d.ts
|
||||
@@ -426,9 +426,10 @@ export interface ViewStyle extends FlexStyle, ShadowStyleIOS, TransformsStyle {
|
||||
*/
|
||||
pointerEvents?: 'box-none' | 'none' | 'box-only' | 'auto' | undefined;
|
||||
isolation?: 'auto' | 'isolate' | undefined;
|
||||
- cursor?: CursorValue | undefined;
|
||||
+ cursor?: CursorValue | string | undefined;
|
||||
boxShadow?: ReadonlyArray<BoxShadowValue> | string | undefined;
|
||||
filter?: ReadonlyArray<FilterFunction> | string | undefined;
|
||||
+ transformOrigin?: string | (string | number)[] | undefined;
|
||||
}
|
||||
|
||||
export type FontVariant =
|
||||
@@ -536,7 +537,11 @@ export interface TextStyle extends TextStyleIOS, TextStyleAndroid, ViewStyle {
|
||||
textShadowOffset?: {width: number; height: number} | undefined;
|
||||
textShadowRadius?: number | undefined;
|
||||
textTransform?: 'none' | 'capitalize' | 'uppercase' | 'lowercase' | undefined;
|
||||
- userSelect?: 'auto' | 'none' | 'text' | 'contain' | 'all' | undefined;
|
||||
+ userSelect?: 'auto' | 'none' | 'text' | 'contain' | 'all' | string | undefined;
|
||||
+ cursor?: CursorValue | string | undefined;
|
||||
+ boxShadow?: ReadonlyArray<BoxShadowValue> | string | undefined;
|
||||
+ filter?: ReadonlyArray<FilterFunction> | string | undefined;
|
||||
+ transformOrigin?: string | (string | number)[] | undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -558,5 +563,8 @@ export interface ImageStyle extends FlexStyle, ShadowStyleIOS, TransformsStyle {
|
||||
tintColor?: ColorValue | undefined;
|
||||
opacity?: AnimatableNumericValue | undefined;
|
||||
objectFit?: 'cover' | 'contain' | 'fill' | 'scale-down' | undefined;
|
||||
- cursor?: CursorValue | undefined;
|
||||
+ cursor?: CursorValue | string | undefined;
|
||||
+ boxShadow?: ReadonlyArray<BoxShadowValue> | string | undefined;
|
||||
+ filter?: ReadonlyArray<FilterFunction> | string | undefined;
|
||||
+ transformOrigin?: string | (string | number)[] | undefined;
|
||||
}
|
||||
diff --git a/node_modules/react-native/React/Fabric/Mounting/ComponentViews/ScrollView/RCTEnhancedScrollView.mm b/node_modules/react-native/React/Fabric/Mounting/ComponentViews/ScrollView/RCTEnhancedScrollView.mm
|
||||
index 93af874..106f8ec 100644
|
||||
--- a/node_modules/react-native/React/Fabric/Mounting/ComponentViews/ScrollView/RCTEnhancedScrollView.mm
|
||||
+++ b/node_modules/react-native/React/Fabric/Mounting/ComponentViews/ScrollView/RCTEnhancedScrollView.mm
|
||||
@@ -66,28 +66,51 @@
|
||||
* ScrollView, we force it to be centered, but when you zoom or the content otherwise
|
||||
* becomes larger than the ScrollView, there is no padding around the content but it
|
||||
* can still fill the whole view.
|
||||
+ * This implementation is based on https://petersteinberger.com/blog/2013/how-to-center-uiscrollview/.
|
||||
*/
|
||||
-- (void)setContentOffset:(CGPoint)contentOffset
|
||||
+-(void)centerContentIfNeeded
|
||||
{
|
||||
- if (_isSetContentOffsetDisabled) {
|
||||
+ if (!_centerContent) {
|
||||
return;
|
||||
}
|
||||
|
||||
- if (_centerContent && !CGSizeEqualToSize(self.contentSize, CGSizeZero)) {
|
||||
- CGSize scrollViewSize = self.bounds.size;
|
||||
- if (self.contentSize.width <= scrollViewSize.width) {
|
||||
- contentOffset.x = -(scrollViewSize.width - self.contentSize.width) / 2.0;
|
||||
- }
|
||||
- if (self.contentSize.height <= scrollViewSize.height) {
|
||||
- contentOffset.y = -(scrollViewSize.height - self.contentSize.height) / 2.0;
|
||||
- }
|
||||
+ CGSize contentSize = self.contentSize;
|
||||
+ CGSize boundsSize = self.bounds.size;
|
||||
+ if (CGSizeEqualToSize(contentSize, CGSizeZero) ||
|
||||
+ CGSizeEqualToSize(boundsSize, CGSizeZero)) {
|
||||
+ return;
|
||||
}
|
||||
|
||||
+ CGFloat top = 0, left = 0;
|
||||
+ if (contentSize.width < boundsSize.width) {
|
||||
+ left = (boundsSize.width - contentSize.width) * 0.5f;
|
||||
+ }
|
||||
+ if (contentSize.height < boundsSize.height) {
|
||||
+ top = (boundsSize.height - contentSize.height) * 0.5f;
|
||||
+ }
|
||||
+ self.contentInset = UIEdgeInsetsMake(top, left, top, left);
|
||||
+}
|
||||
+
|
||||
+- (void)setContentOffset:(CGPoint)contentOffset
|
||||
+{
|
||||
+ if (_isSetContentOffsetDisabled) {
|
||||
+ return;
|
||||
+ }
|
||||
super.contentOffset = CGPointMake(
|
||||
RCTSanitizeNaNValue(contentOffset.x, @"scrollView.contentOffset.x"),
|
||||
RCTSanitizeNaNValue(contentOffset.y, @"scrollView.contentOffset.y"));
|
||||
}
|
||||
|
||||
+- (void)setFrame:(CGRect)frame {
|
||||
+ [super setFrame:frame];
|
||||
+ [self centerContentIfNeeded];
|
||||
+}
|
||||
+
|
||||
+- (void)didAddSubview:(UIView *)subview {
|
||||
+ [super didAddSubview:subview];
|
||||
+ [self centerContentIfNeeded];
|
||||
+}
|
||||
+
|
||||
- (BOOL)touchesShouldCancelInContentView:(UIView *)view
|
||||
{
|
||||
if ([_overridingDelegate respondsToSelector:@selector(touchesShouldCancelInContentView:)]) {
|
||||
@@ -257,6 +280,10 @@
|
||||
}
|
||||
}
|
||||
|
||||
+- (void)scrollViewDidZoom:(__unused UIScrollView *)scrollView {
|
||||
+ [self centerContentIfNeeded];
|
||||
+}
|
||||
+
|
||||
#pragma mark -
|
||||
|
||||
- (BOOL)isHorizontal:(UIScrollView *)scrollView
|
||||
diff --git a/node_modules/react-native/React/Views/RefreshControl/RCTRefreshControl.h b/node_modules/react-native/React/Views/RefreshControl/RCTRefreshControl.h
|
||||
index e9b330f..ec5f58c 100644
|
||||
--- a/node_modules/react-native/React/Views/RefreshControl/RCTRefreshControl.h
|
||||
+++ b/node_modules/react-native/React/Views/RefreshControl/RCTRefreshControl.h
|
||||
@@ -15,5 +15,8 @@
|
||||
@property (nonatomic, copy) NSString *title;
|
||||
@property (nonatomic, copy) RCTDirectEventBlock onRefresh;
|
||||
@property (nonatomic, weak) UIScrollView *scrollView;
|
||||
+@property (nonatomic, copy) UIColor *customTintColor;
|
||||
+
|
||||
+- (void)forwarderBeginRefreshing;
|
||||
|
||||
@end
|
||||
diff --git a/node_modules/react-native/React/Views/RefreshControl/RCTRefreshControl.m b/node_modules/react-native/React/Views/RefreshControl/RCTRefreshControl.m
|
||||
index 53bfd04..ff1b1ed 100644
|
||||
--- a/node_modules/react-native/React/Views/RefreshControl/RCTRefreshControl.m
|
||||
+++ b/node_modules/react-native/React/Views/RefreshControl/RCTRefreshControl.m
|
||||
@@ -23,6 +23,7 @@
|
||||
UIColor *_titleColor;
|
||||
CGFloat _progressViewOffset;
|
||||
BOOL _hasMovedToWindow;
|
||||
+ UIColor *_customTintColor;
|
||||
}
|
||||
|
||||
- (instancetype)init
|
||||
@@ -58,6 +59,12 @@ RCT_NOT_IMPLEMENTED(-(instancetype)initWithCoder : (NSCoder *)aDecoder)
|
||||
_isInitialRender = false;
|
||||
}
|
||||
|
||||
+- (void)didMoveToSuperview
|
||||
+{
|
||||
+ [super didMoveToSuperview];
|
||||
+ [self setTintColor:_customTintColor];
|
||||
+}
|
||||
+
|
||||
- (void)didMoveToWindow
|
||||
{
|
||||
[super didMoveToWindow];
|
||||
@@ -221,4 +228,50 @@ RCT_NOT_IMPLEMENTED(-(instancetype)initWithCoder : (NSCoder *)aDecoder)
|
||||
}
|
||||
}
|
||||
|
||||
+// Fix for https://github.com/facebook/react-native/issues/43388
|
||||
+// A bug in iOS 17.4 causes the haptic to not play when refreshing if the tintColor
|
||||
+// is set before the refresh control gets added to the scrollview. We'll call this
|
||||
+// function whenever the superview changes. We'll also call it if the value of customTintColor
|
||||
+// changes.
|
||||
+- (void)setTintColor:(UIColor *)tintColor
|
||||
+{
|
||||
+ if ([self.superview isKindOfClass:[UIScrollView class]] && self.tintColor != tintColor) {
|
||||
+ [super setTintColor:tintColor];
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+// This method is used by Bluesky's ExpoScrollForwarder. This allows other React Native
|
||||
+// libraries to perform a refresh of a scrollview and access the refresh control's onRefresh
|
||||
+// function.
|
||||
+- (void)forwarderBeginRefreshing
|
||||
+{
|
||||
+ _refreshingProgrammatically = NO;
|
||||
+
|
||||
+ [self sizeToFit];
|
||||
+
|
||||
+ if (!self.scrollView) {
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ UIScrollView *scrollView = (UIScrollView *)self.scrollView;
|
||||
+
|
||||
+ [UIView animateWithDuration:0.3
|
||||
+ delay:0
|
||||
+ options:UIViewAnimationOptionBeginFromCurrentState
|
||||
+ animations:^(void) {
|
||||
+ // Whenever we call this method, the scrollview will always be at a position of
|
||||
+ // -130 or less. Scrolling back to -65 simulates the default behavior of RCTRefreshControl
|
||||
+ [scrollView setContentOffset:CGPointMake(0, -65)];
|
||||
+ }
|
||||
+ completion:^(__unused BOOL finished) {
|
||||
+ [super beginRefreshing];
|
||||
+ [self setCurrentRefreshingState:super.refreshing];
|
||||
+
|
||||
+ if (self->_onRefresh) {
|
||||
+ self->_onRefresh(nil);
|
||||
+ }
|
||||
+ }
|
||||
+ ];
|
||||
+}
|
||||
+
|
||||
@end
|
||||
diff --git a/node_modules/react-native/React/Views/RefreshControl/RCTRefreshControlManager.m b/node_modules/react-native/React/Views/RefreshControl/RCTRefreshControlManager.m
|
||||
index 40aaf9c..1c60164 100644
|
||||
--- a/node_modules/react-native/React/Views/RefreshControl/RCTRefreshControlManager.m
|
||||
+++ b/node_modules/react-native/React/Views/RefreshControl/RCTRefreshControlManager.m
|
||||
@@ -22,11 +22,12 @@ RCT_EXPORT_MODULE()
|
||||
|
||||
RCT_EXPORT_VIEW_PROPERTY(onRefresh, RCTDirectEventBlock)
|
||||
RCT_EXPORT_VIEW_PROPERTY(refreshing, BOOL)
|
||||
-RCT_EXPORT_VIEW_PROPERTY(tintColor, UIColor)
|
||||
RCT_EXPORT_VIEW_PROPERTY(title, NSString)
|
||||
RCT_EXPORT_VIEW_PROPERTY(titleColor, UIColor)
|
||||
RCT_EXPORT_VIEW_PROPERTY(progressViewOffset, CGFloat)
|
||||
|
||||
+RCT_REMAP_VIEW_PROPERTY(tintColor, customTintColor, UIColor)
|
||||
+
|
||||
RCT_EXPORT_METHOD(setNativeRefreshing : (nonnull NSNumber *)viewTag toRefreshing : (BOOL)refreshing)
|
||||
{
|
||||
[self.bridge.uiManager addUIBlock:^(RCTUIManager *uiManager, NSDictionary<NSNumber *, UIView *> *viewRegistry) {
|
||||
diff --git a/node_modules/react-native/React/Views/ScrollView/RCTScrollView.m b/node_modules/react-native/React/Views/ScrollView/RCTScrollView.m
|
||||
index 6f41b5c..9b4f77f 100644
|
||||
--- a/node_modules/react-native/React/Views/ScrollView/RCTScrollView.m
|
||||
+++ b/node_modules/react-native/React/Views/ScrollView/RCTScrollView.m
|
||||
@@ -159,26 +159,8 @@
|
||||
return !shouldDisableScrollInteraction;
|
||||
}
|
||||
|
||||
-/*
|
||||
- * Automatically centers the content such that if the content is smaller than the
|
||||
- * ScrollView, we force it to be centered, but when you zoom or the content otherwise
|
||||
- * becomes larger than the ScrollView, there is no padding around the content but it
|
||||
- * can still fill the whole view.
|
||||
- */
|
||||
- (void)setContentOffset:(CGPoint)contentOffset
|
||||
{
|
||||
- UIView *contentView = [self contentView];
|
||||
- if (contentView && _centerContent && !CGSizeEqualToSize(contentView.frame.size, CGSizeZero)) {
|
||||
- CGSize subviewSize = contentView.frame.size;
|
||||
- CGSize scrollViewSize = self.bounds.size;
|
||||
- if (subviewSize.width <= scrollViewSize.width) {
|
||||
- contentOffset.x = -(scrollViewSize.width - subviewSize.width) / 2.0;
|
||||
- }
|
||||
- if (subviewSize.height <= scrollViewSize.height) {
|
||||
- contentOffset.y = -(scrollViewSize.height - subviewSize.height) / 2.0;
|
||||
- }
|
||||
- }
|
||||
-
|
||||
super.contentOffset = CGPointMake(
|
||||
RCTSanitizeNaNValue(contentOffset.x, @"scrollView.contentOffset.x"),
|
||||
RCTSanitizeNaNValue(contentOffset.y, @"scrollView.contentOffset.y"));
|
||||
@@ -433,6 +415,11 @@ static inline void RCTApplyTransformationAccordingLayoutDirection(
|
||||
// Does nothing
|
||||
}
|
||||
|
||||
+- (void)setFrame:(CGRect)frame {
|
||||
+ [super setFrame:frame];
|
||||
+ [self centerContentIfNeeded];
|
||||
+}
|
||||
+
|
||||
- (void)insertReactSubview:(UIView *)view atIndex:(NSInteger)atIndex
|
||||
{
|
||||
[super insertReactSubview:view atIndex:atIndex];
|
||||
@@ -449,6 +436,8 @@ static inline void RCTApplyTransformationAccordingLayoutDirection(
|
||||
_contentView = view;
|
||||
RCTApplyTransformationAccordingLayoutDirection(_contentView, self.reactLayoutDirection);
|
||||
[_scrollView addSubview:view];
|
||||
+
|
||||
+ [self centerContentIfNeeded];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -658,9 +647,46 @@ static inline void RCTApplyTransformationAccordingLayoutDirection(
|
||||
}
|
||||
|
||||
RCT_SCROLL_EVENT_HANDLER(scrollViewWillBeginDecelerating, onMomentumScrollBegin)
|
||||
-RCT_SCROLL_EVENT_HANDLER(scrollViewDidZoom, onScroll)
|
||||
RCT_SCROLL_EVENT_HANDLER(scrollViewDidScrollToTop, onScrollToTop)
|
||||
|
||||
+-(void)scrollViewDidZoom : (UIScrollView *)scrollView
|
||||
+{
|
||||
+ [self centerContentIfNeeded];
|
||||
+
|
||||
+ RCT_SEND_SCROLL_EVENT(onScroll, nil);
|
||||
+ RCT_FORWARD_SCROLL_EVENT(scrollViewDidZoom : scrollView);
|
||||
+}
|
||||
+
|
||||
+/*
|
||||
+ * Automatically centers the content such that if the content is smaller than the
|
||||
+ * ScrollView, we force it to be centered, but when you zoom or the content otherwise
|
||||
+ * becomes larger than the ScrollView, there is no padding around the content but it
|
||||
+ * can still fill the whole view.
|
||||
+ * This implementation is based on https://petersteinberger.com/blog/2013/how-to-center-uiscrollview/.
|
||||
+ */
|
||||
+-(void)centerContentIfNeeded
|
||||
+{
|
||||
+ if (!_scrollView.centerContent) {
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ CGSize contentSize = self.contentSize;
|
||||
+ CGSize boundsSize = self.bounds.size;
|
||||
+ if (CGSizeEqualToSize(contentSize, CGSizeZero) ||
|
||||
+ CGSizeEqualToSize(boundsSize, CGSizeZero)) {
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ CGFloat top = 0, left = 0;
|
||||
+ if (contentSize.width < boundsSize.width) {
|
||||
+ left = (boundsSize.width - contentSize.width) * 0.5f;
|
||||
+ }
|
||||
+ if (contentSize.height < boundsSize.height) {
|
||||
+ top = (boundsSize.height - contentSize.height) * 0.5f;
|
||||
+ }
|
||||
+ _scrollView.contentInset = UIEdgeInsetsMake(top, left, top, left);
|
||||
+}
|
||||
+
|
||||
- (void)addScrollListener:(NSObject<UIScrollViewDelegate> *)scrollListener
|
||||
{
|
||||
[_scrollListeners addObject:scrollListener];
|
||||
@@ -939,6 +965,7 @@ RCT_SCROLL_EVENT_HANDLER(scrollViewDidScrollToTop, onScrollToTop)
|
||||
CGSize contentSize = self.contentSize;
|
||||
if (!CGSizeEqualToSize(_scrollView.contentSize, contentSize)) {
|
||||
_scrollView.contentSize = contentSize;
|
||||
+ [self centerContentIfNeeded];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1061,6 +1088,22 @@ RCT_SET_AND_PRESERVE_OFFSET(setShowsHorizontalScrollIndicator, showsHorizontalSc
|
||||
RCT_SET_AND_PRESERVE_OFFSET(setShowsVerticalScrollIndicator, showsVerticalScrollIndicator, BOOL)
|
||||
RCT_SET_AND_PRESERVE_OFFSET(setZoomScale, zoomScale, CGFloat);
|
||||
|
||||
+- (void)setScrollIndicatorInsets:(UIEdgeInsets)value
|
||||
+{
|
||||
+ [_scrollView setScrollIndicatorInsets:value];
|
||||
+}
|
||||
+
|
||||
+- (UIEdgeInsets)scrollIndicatorInsets
|
||||
+{
|
||||
+ UIEdgeInsets verticalScrollIndicatorInsets = [_scrollView verticalScrollIndicatorInsets];
|
||||
+ UIEdgeInsets horizontalScrollIndicatorInsets = [_scrollView horizontalScrollIndicatorInsets];
|
||||
+ return UIEdgeInsetsMake(
|
||||
+ verticalScrollIndicatorInsets.top,
|
||||
+ horizontalScrollIndicatorInsets.left,
|
||||
+ verticalScrollIndicatorInsets.bottom,
|
||||
+ horizontalScrollIndicatorInsets.right);
|
||||
+}
|
||||
+
|
||||
- (void)setAutomaticallyAdjustsScrollIndicatorInsets:(BOOL)automaticallyAdjusts API_AVAILABLE(ios(13.0))
|
||||
{
|
||||
// `automaticallyAdjustsScrollIndicatorInsets` is available since iOS 13.
|
||||
diff --git a/node_modules/react-native/React/Views/ScrollView/RCTScrollViewManager.m b/node_modules/react-native/React/Views/ScrollView/RCTScrollViewManager.m
|
||||
index cd1e7eb..c1d0172 100644
|
||||
--- a/node_modules/react-native/React/Views/ScrollView/RCTScrollViewManager.m
|
||||
+++ b/node_modules/react-native/React/Views/ScrollView/RCTScrollViewManager.m
|
||||
@@ -83,6 +83,7 @@ RCT_EXPORT_VIEW_PROPERTY(showsVerticalScrollIndicator, BOOL)
|
||||
RCT_EXPORT_VIEW_PROPERTY(scrollEventThrottle, NSTimeInterval)
|
||||
RCT_EXPORT_VIEW_PROPERTY(zoomScale, CGFloat)
|
||||
RCT_EXPORT_VIEW_PROPERTY(contentInset, UIEdgeInsets)
|
||||
+RCT_EXPORT_VIEW_PROPERTY(scrollIndicatorInsets, UIEdgeInsets)
|
||||
RCT_EXPORT_VIEW_PROPERTY(verticalScrollIndicatorInsets, UIEdgeInsets)
|
||||
RCT_EXPORT_VIEW_PROPERTY(scrollToOverflowEnabled, BOOL)
|
||||
RCT_EXPORT_VIEW_PROPERTY(snapToInterval, int)
|
119
patches/react-native+0.79.2.patch
Normal file
119
patches/react-native+0.79.2.patch
Normal file
@ -0,0 +1,119 @@
|
||||
diff --git a/node_modules/react-native/React/Views/RefreshControl/RCTRefreshControl.h b/node_modules/react-native/React/Views/RefreshControl/RCTRefreshControl.h
|
||||
index e9b330f..ec5f58c 100644
|
||||
--- a/node_modules/react-native/React/Views/RefreshControl/RCTRefreshControl.h
|
||||
+++ b/node_modules/react-native/React/Views/RefreshControl/RCTRefreshControl.h
|
||||
@@ -15,5 +15,8 @@
|
||||
@property (nonatomic, copy) NSString *title;
|
||||
@property (nonatomic, copy) RCTDirectEventBlock onRefresh;
|
||||
@property (nonatomic, weak) UIScrollView *scrollView;
|
||||
+@property (nonatomic, copy) UIColor *customTintColor;
|
||||
+
|
||||
+- (void)forwarderBeginRefreshing;
|
||||
|
||||
@end
|
||||
diff --git a/node_modules/react-native/React/Views/RefreshControl/RCTRefreshControl.m b/node_modules/react-native/React/Views/RefreshControl/RCTRefreshControl.m
|
||||
index 53bfd04..ff1b1ed 100644
|
||||
--- a/node_modules/react-native/React/Views/RefreshControl/RCTRefreshControl.m
|
||||
+++ b/node_modules/react-native/React/Views/RefreshControl/RCTRefreshControl.m
|
||||
@@ -23,6 +23,7 @@
|
||||
UIColor *_titleColor;
|
||||
CGFloat _progressViewOffset;
|
||||
BOOL _hasMovedToWindow;
|
||||
+ UIColor *_customTintColor;
|
||||
}
|
||||
|
||||
- (instancetype)init
|
||||
@@ -58,6 +59,12 @@ RCT_NOT_IMPLEMENTED(-(instancetype)initWithCoder : (NSCoder *)aDecoder)
|
||||
_isInitialRender = false;
|
||||
}
|
||||
|
||||
+- (void)didMoveToSuperview
|
||||
+{
|
||||
+ [super didMoveToSuperview];
|
||||
+ [self setTintColor:_customTintColor];
|
||||
+}
|
||||
+
|
||||
- (void)didMoveToWindow
|
||||
{
|
||||
[super didMoveToWindow];
|
||||
@@ -221,4 +228,50 @@ RCT_NOT_IMPLEMENTED(-(instancetype)initWithCoder : (NSCoder *)aDecoder)
|
||||
}
|
||||
}
|
||||
|
||||
+// Fix for https://github.com/facebook/react-native/issues/43388
|
||||
+// A bug in iOS 17.4 causes the haptic to not play when refreshing if the tintColor
|
||||
+// is set before the refresh control gets added to the scrollview. We'll call this
|
||||
+// function whenever the superview changes. We'll also call it if the value of customTintColor
|
||||
+// changes.
|
||||
+- (void)setTintColor:(UIColor *)tintColor
|
||||
+{
|
||||
+ if ([self.superview isKindOfClass:[UIScrollView class]] && self.tintColor != tintColor) {
|
||||
+ [super setTintColor:tintColor];
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+// This method is used by Bluesky's ExpoScrollForwarder. This allows other React Native
|
||||
+// libraries to perform a refresh of a scrollview and access the refresh control's onRefresh
|
||||
+// function.
|
||||
+- (void)forwarderBeginRefreshing
|
||||
+{
|
||||
+ _refreshingProgrammatically = NO;
|
||||
+
|
||||
+ [self sizeToFit];
|
||||
+
|
||||
+ if (!self.scrollView) {
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ UIScrollView *scrollView = (UIScrollView *)self.scrollView;
|
||||
+
|
||||
+ [UIView animateWithDuration:0.3
|
||||
+ delay:0
|
||||
+ options:UIViewAnimationOptionBeginFromCurrentState
|
||||
+ animations:^(void) {
|
||||
+ // Whenever we call this method, the scrollview will always be at a position of
|
||||
+ // -130 or less. Scrolling back to -65 simulates the default behavior of RCTRefreshControl
|
||||
+ [scrollView setContentOffset:CGPointMake(0, -65)];
|
||||
+ }
|
||||
+ completion:^(__unused BOOL finished) {
|
||||
+ [super beginRefreshing];
|
||||
+ [self setCurrentRefreshingState:super.refreshing];
|
||||
+
|
||||
+ if (self->_onRefresh) {
|
||||
+ self->_onRefresh(nil);
|
||||
+ }
|
||||
+ }
|
||||
+ ];
|
||||
+}
|
||||
+
|
||||
@end
|
||||
diff --git a/node_modules/react-native/React/Views/RefreshControl/RCTRefreshControlManager.m b/node_modules/react-native/React/Views/RefreshControl/RCTRefreshControlManager.m
|
||||
index 40aaf9c..1c60164 100644
|
||||
--- a/node_modules/react-native/React/Views/RefreshControl/RCTRefreshControlManager.m
|
||||
+++ b/node_modules/react-native/React/Views/RefreshControl/RCTRefreshControlManager.m
|
||||
@@ -22,11 +22,12 @@ RCT_EXPORT_MODULE()
|
||||
|
||||
RCT_EXPORT_VIEW_PROPERTY(onRefresh, RCTDirectEventBlock)
|
||||
RCT_EXPORT_VIEW_PROPERTY(refreshing, BOOL)
|
||||
-RCT_EXPORT_VIEW_PROPERTY(tintColor, UIColor)
|
||||
RCT_EXPORT_VIEW_PROPERTY(title, NSString)
|
||||
RCT_EXPORT_VIEW_PROPERTY(titleColor, UIColor)
|
||||
RCT_EXPORT_VIEW_PROPERTY(progressViewOffset, CGFloat)
|
||||
|
||||
+RCT_REMAP_VIEW_PROPERTY(tintColor, customTintColor, UIColor)
|
||||
+
|
||||
RCT_EXPORT_METHOD(setNativeRefreshing : (nonnull NSNumber *)viewTag toRefreshing : (BOOL)refreshing)
|
||||
{
|
||||
[self.bridge.uiManager addUIBlock:^(RCTUIManager *uiManager, NSDictionary<NSNumber *, UIView *> *viewRegistry) {
|
||||
diff --git a/node_modules/react-native/React/Views/ScrollView/RCTScrollViewManager.m b/node_modules/react-native/React/Views/ScrollView/RCTScrollViewManager.m
|
||||
index cd1e7eb..c1d0172 100644
|
||||
--- a/node_modules/react-native/React/Views/ScrollView/RCTScrollViewManager.m
|
||||
+++ b/node_modules/react-native/React/Views/ScrollView/RCTScrollViewManager.m
|
||||
@@ -83,6 +83,7 @@ RCT_EXPORT_VIEW_PROPERTY(showsVerticalScrollIndicator, BOOL)
|
||||
RCT_EXPORT_VIEW_PROPERTY(scrollEventThrottle, NSTimeInterval)
|
||||
RCT_EXPORT_VIEW_PROPERTY(zoomScale, CGFloat)
|
||||
RCT_EXPORT_VIEW_PROPERTY(contentInset, UIEdgeInsets)
|
||||
+RCT_EXPORT_VIEW_PROPERTY(scrollIndicatorInsets, UIEdgeInsets)
|
||||
RCT_EXPORT_VIEW_PROPERTY(verticalScrollIndicatorInsets, UIEdgeInsets)
|
||||
RCT_EXPORT_VIEW_PROPERTY(scrollToOverflowEnabled, BOOL)
|
||||
RCT_EXPORT_VIEW_PROPERTY(snapToInterval, int)
|
@ -11,7 +11,3 @@ in the RN repo: https://github.com/facebook/react-native/issues/43388
|
||||
Patching `RCTRefreshControl.m` and `RCTRefreshControl.h` to add a new `forwarderBeginRefreshing` method to the class.
|
||||
This method is used by `ExpoScrollForwarder` to initiate a refresh of the underlying `UIScrollView` from inside that
|
||||
module.
|
||||
|
||||
## ScrollView centerContent fix
|
||||
|
||||
Includes https://github.com/facebook/react-native/pull/47591 early. Delete when it's in a release.
|
@ -1,5 +1,5 @@
|
||||
diff --git a/node_modules/react-native-image-crop-picker/android/src/main/AndroidManifest.xml b/node_modules/react-native-image-crop-picker/android/src/main/AndroidManifest.xml
|
||||
index 391f303..8e2c3db 100644
|
||||
index a08629b..fab6299 100644
|
||||
--- a/node_modules/react-native-image-crop-picker/android/src/main/AndroidManifest.xml
|
||||
+++ b/node_modules/react-native-image-crop-picker/android/src/main/AndroidManifest.xml
|
||||
@@ -24,7 +24,7 @@
|
||||
@ -8,12 +8,12 @@ index 391f303..8e2c3db 100644
|
||||
android:name="com.yalantis.ucrop.UCropActivity"
|
||||
- android:theme="@style/Theme.AppCompat.Light.NoActionBar" />
|
||||
+ android:theme="@style/Theme.UCropNoEdgeToEdge" />
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
|
||||
<!-- Prompt Google Play services to install the backported photo picker module -->
|
||||
diff --git a/node_modules/react-native-image-crop-picker/android/src/main/res/values-v35/styles.xml b/node_modules/react-native-image-crop-picker/android/src/main/res/values-v35/styles.xml
|
||||
new file mode 100644
|
||||
index 0000000..396d5a8
|
||||
index 0000000..5301f74
|
||||
--- /dev/null
|
||||
+++ b/node_modules/react-native-image-crop-picker/android/src/main/res/values-v35/styles.xml
|
||||
@@ -0,0 +1,5 @@
|
||||
@ -22,26 +22,27 @@ index 0000000..396d5a8
|
||||
+ <item name="android:windowOptOutEdgeToEdgeEnforcement">true</item>
|
||||
+ </style>
|
||||
+</resources>
|
||||
\ No newline at end of file
|
||||
diff --git a/node_modules/react-native-image-crop-picker/android/src/main/res/values/styles.xml b/node_modules/react-native-image-crop-picker/android/src/main/res/values/styles.xml
|
||||
new file mode 100644
|
||||
index 0000000..50129b6
|
||||
index 0000000..55569aa
|
||||
--- /dev/null
|
||||
+++ b/node_modules/react-native-image-crop-picker/android/src/main/res/values/styles.xml
|
||||
@@ -0,0 +1,3 @@
|
||||
+<resources>
|
||||
+ <style name="Theme.UCropNoEdgeToEdge" parent="Theme.AppCompat.Light.NoActionBar"/>
|
||||
+</resources>
|
||||
\ No newline at end of file
|
||||
diff --git a/node_modules/react-native-image-crop-picker/ios/src/ImageCropPicker.m b/node_modules/react-native-image-crop-picker/ios/src/ImageCropPicker.m
|
||||
index 9f20973..68d4766 100644
|
||||
index 9f20973..c414a7a 100644
|
||||
--- a/node_modules/react-native-image-crop-picker/ios/src/ImageCropPicker.m
|
||||
+++ b/node_modules/react-native-image-crop-picker/ios/src/ImageCropPicker.m
|
||||
@@ -126,7 +126,8 @@ - (void) setConfiguration:(NSDictionary *)options
|
||||
@@ -126,7 +126,7 @@ - (void) setConfiguration:(NSDictionary *)options
|
||||
|
||||
- (UIViewController*) getRootVC {
|
||||
UIViewController *root = [[[[UIApplication sharedApplication] delegate] window] rootViewController];
|
||||
- while (root.presentedViewController != nil) {
|
||||
+ while (root.presentedViewController != nil &&
|
||||
+ !root.presentedViewController.isBeingDismissed) {
|
||||
+ while (root.presentedViewController != nil && !root.presentedViewController.isBeingDismissed) {
|
||||
root = root.presentedViewController;
|
||||
}
|
||||
|
44
patches/react-native-reanimated+3.17.5.patch
Normal file
44
patches/react-native-reanimated+3.17.5.patch
Normal file
@ -0,0 +1,44 @@
|
||||
diff --git a/node_modules/react-native-reanimated/android/src/main/cpp/reanimated/android/NativeProxy.cpp b/node_modules/react-native-reanimated/android/src/main/cpp/reanimated/android/NativeProxy.cpp
|
||||
index eae3989..432745a 100644
|
||||
--- a/node_modules/react-native-reanimated/android/src/main/cpp/reanimated/android/NativeProxy.cpp
|
||||
+++ b/node_modules/react-native-reanimated/android/src/main/cpp/reanimated/android/NativeProxy.cpp
|
||||
@@ -416,6 +416,10 @@ void NativeProxy::progressLayoutAnimation(
|
||||
tag, newPropsJNI, isSharedTransition);
|
||||
}
|
||||
|
||||
+void NativeProxy::endLayoutAnimation(int tag, bool shouldRemove) {
|
||||
+ layoutAnimations_->cthis()->endLayoutAnimation(tag, shouldRemove);
|
||||
+}
|
||||
+
|
||||
PlatformDepMethodsHolder NativeProxy::getPlatformDependentMethods() {
|
||||
#ifdef RCT_NEW_ARCH_ENABLED
|
||||
// nothing
|
||||
@@ -455,14 +459,7 @@ PlatformDepMethodsHolder NativeProxy::getPlatformDependentMethods() {
|
||||
auto progressLayoutAnimation =
|
||||
bindThis(&NativeProxy::progressLayoutAnimation);
|
||||
|
||||
- auto endLayoutAnimation = [weakThis = weak_from_this()](
|
||||
- int tag, bool removeView) {
|
||||
- auto strongThis = weakThis.lock();
|
||||
- if (!strongThis) {
|
||||
- return;
|
||||
- }
|
||||
- strongThis->layoutAnimations_->cthis()->endLayoutAnimation(tag, removeView);
|
||||
- };
|
||||
+ auto endLayoutAnimation = bindThis(&NativeProxy::endLayoutAnimation);
|
||||
|
||||
auto maybeFlushUiUpdatesQueueFunction =
|
||||
bindThis(&NativeProxy::maybeFlushUIUpdatesQueue);
|
||||
diff --git a/node_modules/react-native-reanimated/android/src/main/cpp/reanimated/android/NativeProxy.h b/node_modules/react-native-reanimated/android/src/main/cpp/reanimated/android/NativeProxy.h
|
||||
index 2ee2cc8..2edb5c9 100644
|
||||
--- a/node_modules/react-native-reanimated/android/src/main/cpp/reanimated/android/NativeProxy.h
|
||||
+++ b/node_modules/react-native-reanimated/android/src/main/cpp/reanimated/android/NativeProxy.h
|
||||
@@ -234,6 +234,8 @@ class NativeProxy : public jni::HybridClass<NativeProxy>,
|
||||
const jsi::Object &newProps,
|
||||
bool isSharedTransition);
|
||||
|
||||
+ void endLayoutAnimation(int tag, bool shouldRemove);
|
||||
+
|
||||
/***
|
||||
* Wraps a method of `NativeProxy` in a function object capturing `this`
|
||||
* @tparam TReturn return type of passed method
|
@ -1,41 +1,41 @@
|
||||
const {withAppDelegate} = require('@expo/config-plugins')
|
||||
const {mergeContents} = require('@expo/config-plugins/build/utils/generateCode')
|
||||
const path = require('path')
|
||||
const fs = require('fs')
|
||||
|
||||
module.exports = config => {
|
||||
// eslint-disable-next-line no-shadow
|
||||
return withAppDelegate(config, async config => {
|
||||
const delegatePath = path.join(
|
||||
config.modRequest.platformProjectRoot,
|
||||
'AppDelegate.mm',
|
||||
)
|
||||
module.exports = config =>
|
||||
withAppDelegate(config, config => {
|
||||
let contents = config.modResults.contents
|
||||
|
||||
let newContents = config.modResults.contents
|
||||
newContents = mergeContents({
|
||||
src: newContents,
|
||||
contents = mergeContents({
|
||||
src: contents,
|
||||
anchor: '// Linking API',
|
||||
newSrc: `
|
||||
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
|
||||
[defaults setObject:options[UIApplicationOpenURLOptionsSourceApplicationKey] forKey:@"referrerApp"];\n`,
|
||||
offset: 2,
|
||||
// @generated begin referrer info – deep links
|
||||
let defaults = UserDefaults.standard
|
||||
defaults.set(
|
||||
options[.sourceApplication] as? String,
|
||||
forKey: "referrerApp"
|
||||
)
|
||||
// @generated end referrer info – deep links
|
||||
`,
|
||||
offset: 6,
|
||||
tag: 'referrer info - deep links',
|
||||
comment: '//',
|
||||
}).contents
|
||||
|
||||
newContents = mergeContents({
|
||||
src: newContents,
|
||||
contents = mergeContents({
|
||||
src: contents,
|
||||
anchor: '// Universal Links',
|
||||
newSrc: `
|
||||
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
|
||||
[defaults setURL:userActivity.referrerURL forKey:@"referrer"];\n`,
|
||||
offset: 2,
|
||||
// @generated begin referrer info – universal links
|
||||
let defaults = UserDefaults.standard
|
||||
defaults.set(userActivity.referrerURL, forKey: "referrer")
|
||||
// @generated end referrer info – universal links
|
||||
`,
|
||||
offset: 6,
|
||||
tag: 'referrer info - universal links',
|
||||
comment: '//',
|
||||
}).contents
|
||||
|
||||
config.modResults.contents = newContents
|
||||
|
||||
config.modResults.contents = contents
|
||||
return config
|
||||
})
|
||||
}
|
||||
|
@ -1,70 +0,0 @@
|
||||
const {withAppBuildGradle} = require('@expo/config-plugins')
|
||||
|
||||
/**
|
||||
* A Config Plugin to disable bundle compression in Android build.gradle.
|
||||
* @param {import('@expo/config-plugins').ConfigPlugin} config
|
||||
* @returns {import('@expo/config-plugins').ConfigPlugin}
|
||||
*/
|
||||
module.exports = function withNoBundleCompression(config) {
|
||||
return withAppBuildGradle(config, androidConfig => {
|
||||
let buildGradle = androidConfig.modResults.contents
|
||||
|
||||
const hasAndroidResources = buildGradle.includes('androidResources {')
|
||||
const hasNoCompress = buildGradle.includes('noCompress')
|
||||
|
||||
if (hasAndroidResources) {
|
||||
if (hasNoCompress) {
|
||||
if (
|
||||
buildGradle.includes('noCompress += ["bundle"]') ||
|
||||
buildGradle.includes("noCompress += 'bundle'") ||
|
||||
buildGradle.includes('noCompress += "bundle"')
|
||||
) {
|
||||
return androidConfig
|
||||
}
|
||||
|
||||
const lines = buildGradle.split('\n')
|
||||
const modifiedLines = lines.map(line => {
|
||||
if (line.trim().startsWith('noCompress')) {
|
||||
if (line.includes('+=')) {
|
||||
return line.replace(/\]/, ', "bundle"]')
|
||||
} else if (line.includes('=')) {
|
||||
return line.replace('=', '+= ["bundle",') + ']'
|
||||
}
|
||||
}
|
||||
return line
|
||||
})
|
||||
androidConfig.modResults.contents = modifiedLines.join('\n')
|
||||
} else {
|
||||
const androidResources = buildGradle.indexOf('androidResources {')
|
||||
if (androidResources === -1) {
|
||||
throw new Error(
|
||||
`Cannot find androidResources { block in build.gradle!`,
|
||||
)
|
||||
}
|
||||
const insertPosition = buildGradle.indexOf('\n', androidResources) + 1
|
||||
const newContent =
|
||||
buildGradle.slice(0, insertPosition) +
|
||||
' noCompress += ["bundle"]\n' +
|
||||
buildGradle.slice(insertPosition)
|
||||
|
||||
androidConfig.modResults.contents = newContent
|
||||
}
|
||||
} else {
|
||||
const androidBlock = buildGradle.indexOf('android {')
|
||||
if (androidBlock === -1) {
|
||||
throw new Error(`Cannot find android { block in build.gradle!`)
|
||||
}
|
||||
const insertPosition = buildGradle.indexOf('\n', androidBlock) + 1
|
||||
const newContent =
|
||||
buildGradle.slice(0, insertPosition) +
|
||||
' androidResources {\n' +
|
||||
' noCompress += ["bundle"]\n' +
|
||||
' }\n' +
|
||||
buildGradle.slice(insertPosition)
|
||||
|
||||
androidConfig.modResults.contents = newContent
|
||||
}
|
||||
|
||||
return androidConfig
|
||||
})
|
||||
}
|
@ -1,4 +1,3 @@
|
||||
import 'react-native-url-polyfill/auto'
|
||||
import '#/logger/sentry/setup'
|
||||
import '#/logger/bitdrift/setup'
|
||||
import '#/view/icons'
|
||||
|
@ -951,8 +951,8 @@ export const atoms = {
|
||||
userSelect: 'all',
|
||||
},
|
||||
outline_inset_1: {
|
||||
outlineOffset: '-1px',
|
||||
} as StyleProp<ViewStyle>,
|
||||
outlineOffset: -1,
|
||||
},
|
||||
|
||||
/*
|
||||
* Text decoration
|
||||
|
@ -1,12 +1,13 @@
|
||||
import React, {Children} from 'react'
|
||||
import {TextProps as RNTextProps} from 'react-native'
|
||||
import {StyleProp, TextStyle} from 'react-native'
|
||||
import {Children} from 'react'
|
||||
import {type TextProps as RNTextProps} from 'react-native'
|
||||
import {type StyleProp, type TextStyle} from 'react-native'
|
||||
import {UITextView} from 'react-native-uitextview'
|
||||
import createEmojiRegex from 'emoji-regex'
|
||||
import type React from 'react'
|
||||
|
||||
import {isNative} from '#/platform/detection'
|
||||
import {isIOS} from '#/platform/detection'
|
||||
import {Alf, applyFonts, atoms, flatten} from '#/alf'
|
||||
import {type Alf, applyFonts, atoms, flatten} from '#/alf'
|
||||
|
||||
/**
|
||||
* Util to calculate lineHeight from a text size atom and a leading atom
|
||||
@ -110,7 +111,10 @@ export function renderChildrenWithEmoji(
|
||||
return child.split(EMOJI).map((stringPart, index) => [
|
||||
stringPart,
|
||||
emojis[index] ? (
|
||||
<UITextView {...props} style={[props?.style, {fontFamily: 'System'}]}>
|
||||
<UITextView
|
||||
{...props}
|
||||
style={[props?.style, {fontFamily: 'System'}]}
|
||||
key={index}>
|
||||
{emojis[index]}
|
||||
</UITextView>
|
||||
) : null,
|
||||
|
@ -23,6 +23,7 @@ import {useWebMediaQueries} from '#/lib/hooks/useWebMediaQueries'
|
||||
import {type NavigationProp} from '#/lib/routes/types'
|
||||
import {parseStarterPackUri} from '#/lib/strings/starter-pack'
|
||||
import {logger} from '#/logger'
|
||||
import {isIOS} from '#/platform/detection'
|
||||
import {useActorStarterPacksQuery} from '#/state/queries/actor-starter-packs'
|
||||
import {List, type ListRef} from '#/view/com/util/List'
|
||||
import {FeedLoadingPlaceholder} from '#/view/com/util/LoadingPlaceholder'
|
||||
@ -111,7 +112,7 @@ export const ProfileStarterPacks = React.forwardRef<
|
||||
}, [isFetchingNextPage, hasNextPage, isError, fetchNextPage])
|
||||
|
||||
useEffect(() => {
|
||||
if (enabled && scrollElRef.current) {
|
||||
if (isIOS && enabled && scrollElRef.current) {
|
||||
const nativeTag = findNodeHandle(scrollElRef.current)
|
||||
setScrollViewTag(nativeTag)
|
||||
}
|
||||
|
@ -1,15 +1,14 @@
|
||||
import {useState} from 'react'
|
||||
import {Modal, Pressable, View} from 'react-native'
|
||||
// @ts-expect-error internal component, not supposed to be used directly
|
||||
// waiting on more customisability: https://github.com/okwasniewski/react-native-emoji-popup/issues/1#issuecomment-2737463753
|
||||
import EmojiPopupView from 'react-native-emoji-popup/src/EmojiPopupViewNativeComponent'
|
||||
import {SafeAreaView} from 'react-native-safe-area-context'
|
||||
import {msg, Trans} from '@lingui/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
|
||||
import {atoms as a, useTheme} from '#/alf'
|
||||
import {Button, ButtonIcon} from '#/components/Button'
|
||||
import {TimesLarge_Stroke2_Corner0_Rounded} from '#/components/icons/Times'
|
||||
import {TimesLarge_Stroke2_Corner0_Rounded as CloseIcon} from '#/components/icons/Times'
|
||||
import {Text} from '#/components/Typography'
|
||||
import {EmojiPicker} from '../../../modules/expo-emoji-picker'
|
||||
|
||||
export function EmojiPopup({
|
||||
children,
|
||||
@ -34,13 +33,14 @@ export function EmojiPopup({
|
||||
|
||||
<Modal
|
||||
animationType="slide"
|
||||
transparent={true}
|
||||
visible={modalVisible}
|
||||
onRequestClose={() => setModalVisible(false)}>
|
||||
<View style={[a.flex_1, {backgroundColor: t.palette.white}]}>
|
||||
onRequestClose={() => setModalVisible(false)}
|
||||
transparent
|
||||
statusBarTranslucent
|
||||
navigationBarTranslucent>
|
||||
<SafeAreaView style={[a.flex_1, t.atoms.bg]}>
|
||||
<View
|
||||
style={[
|
||||
t.atoms.bg,
|
||||
a.pl_lg,
|
||||
a.pr_md,
|
||||
a.py_sm,
|
||||
@ -61,21 +61,16 @@ export function EmojiPopup({
|
||||
variant="ghost"
|
||||
color="secondary"
|
||||
shape="round">
|
||||
<ButtonIcon icon={TimesLarge_Stroke2_Corner0_Rounded} />
|
||||
<ButtonIcon icon={CloseIcon} />
|
||||
</Button>
|
||||
</View>
|
||||
<EmojiPopupView
|
||||
onEmojiSelected={({
|
||||
nativeEvent: {emoji},
|
||||
}: {
|
||||
nativeEvent: {emoji: string}
|
||||
}) => {
|
||||
<EmojiPicker
|
||||
onEmojiSelected={emoji => {
|
||||
setModalVisible(false)
|
||||
onEmojiSelected(emoji)
|
||||
}}
|
||||
style={[a.flex_1, a.w_full]}
|
||||
/>
|
||||
</View>
|
||||
</SafeAreaView>
|
||||
</Modal>
|
||||
</>
|
||||
)
|
||||
|
@ -1 +1 @@
|
||||
export {EmojiPopup} from 'react-native-emoji-popup'
|
||||
export {EmojiPicker as EmojiPopup} from '../../../modules/expo-emoji-picker'
|
||||
|
@ -1,23 +1,23 @@
|
||||
import {
|
||||
$Typed,
|
||||
AppBskyEmbedExternal,
|
||||
AppBskyEmbedImages,
|
||||
AppBskyEmbedRecord,
|
||||
AppBskyEmbedRecordWithMedia,
|
||||
AppBskyEmbedVideo,
|
||||
AppBskyFeedPost,
|
||||
type $Typed,
|
||||
type AppBskyEmbedExternal,
|
||||
type AppBskyEmbedImages,
|
||||
type AppBskyEmbedRecord,
|
||||
type AppBskyEmbedRecordWithMedia,
|
||||
type AppBskyEmbedVideo,
|
||||
type AppBskyFeedPost,
|
||||
AtUri,
|
||||
BlobRef,
|
||||
BskyAgent,
|
||||
ComAtprotoLabelDefs,
|
||||
ComAtprotoRepoApplyWrites,
|
||||
ComAtprotoRepoStrongRef,
|
||||
type BskyAgent,
|
||||
type ComAtprotoLabelDefs,
|
||||
type ComAtprotoRepoApplyWrites,
|
||||
type ComAtprotoRepoStrongRef,
|
||||
RichText,
|
||||
} from '@atproto/api'
|
||||
import {TID} from '@atproto/common-web'
|
||||
import * as dcbor from '@ipld/dag-cbor'
|
||||
import {t} from '@lingui/macro'
|
||||
import {QueryClient} from '@tanstack/react-query'
|
||||
import {type QueryClient} from '@tanstack/react-query'
|
||||
import {sha256} from 'js-sha256'
|
||||
import {CID} from 'multiformats/cid'
|
||||
import * as Hasher from 'multiformats/hashes/hasher'
|
||||
@ -35,9 +35,9 @@ import {
|
||||
threadgateAllowUISettingToAllowRecordValue,
|
||||
} from '#/state/queries/threadgate'
|
||||
import {
|
||||
EmbedDraft,
|
||||
PostDraft,
|
||||
ThreadDraft,
|
||||
type EmbedDraft,
|
||||
type PostDraft,
|
||||
type ThreadDraft,
|
||||
} from '#/view/com/composer/state/composer'
|
||||
import {createGIFDescription} from '../gif-alt-text'
|
||||
import {uploadBlob} from './upload-blob'
|
||||
|
@ -1,6 +1,6 @@
|
||||
import {ForwardedRef, useEffect, useMemo, useRef} from 'react'
|
||||
import type {ScrollView} from 'react-native'
|
||||
import {findNodeHandle, Platform} from 'react-native'
|
||||
import {type ForwardedRef, useEffect, useMemo, useRef} from 'react'
|
||||
import {type ScrollView} from 'react-native'
|
||||
import {Platform} from 'react-native'
|
||||
|
||||
import {mergeRefs} from '#/lib/merge-refs'
|
||||
|
||||
@ -19,7 +19,7 @@ export function useDraggableScroll<Scrollable extends ScrollView = ScrollView>({
|
||||
if (Platform.OS !== 'web' || !ref.current) {
|
||||
return
|
||||
}
|
||||
const slider = findNodeHandle(ref.current) as unknown as HTMLDivElement
|
||||
const slider = ref.current as unknown as HTMLDivElement
|
||||
if (!slider) {
|
||||
return
|
||||
}
|
||||
|
@ -4,7 +4,7 @@ import {CommonActions, useNavigation} from '@react-navigation/native'
|
||||
import {useQueryClient} from '@tanstack/react-query'
|
||||
|
||||
import {useAccountSwitcher} from '#/lib/hooks/useAccountSwitcher'
|
||||
import {NavigationProp} from '#/lib/routes/types'
|
||||
import {type NavigationProp} from '#/lib/routes/types'
|
||||
import {logEvent} from '#/lib/statsig/statsig'
|
||||
import {Logger} from '#/logger'
|
||||
import {isAndroid} from '#/platform/detection'
|
||||
@ -41,10 +41,11 @@ type NotificationPayload =
|
||||
}
|
||||
|
||||
const DEFAULT_HANDLER_OPTIONS = {
|
||||
shouldShowAlert: false,
|
||||
shouldShowBanner: false,
|
||||
shouldShowList: false,
|
||||
shouldPlaySound: false,
|
||||
shouldSetBadge: true,
|
||||
}
|
||||
} satisfies Notifications.NotificationBehavior
|
||||
|
||||
// These need to stay outside the hook to persist between account switches
|
||||
let storedPayload: NotificationPayload | undefined
|
||||
@ -195,11 +196,13 @@ export function useNotificationsHandler() {
|
||||
payload.reason === 'chat-message' &&
|
||||
payload.recipientDid === currentAccount?.did
|
||||
) {
|
||||
const shouldAlert = payload.convoId !== currentConvoId
|
||||
return {
|
||||
shouldShowAlert: payload.convoId !== currentConvoId,
|
||||
shouldShowList: shouldAlert,
|
||||
shouldShowBanner: shouldAlert,
|
||||
shouldPlaySound: false,
|
||||
shouldSetBadge: false,
|
||||
}
|
||||
} satisfies Notifications.NotificationBehavior
|
||||
}
|
||||
|
||||
// Any notification other than a chat message should invalidate the unread page
|
||||
|
@ -1,6 +1,6 @@
|
||||
import {AtUri} from '@atproto/api'
|
||||
|
||||
import * as bsky from '#/types/bsky'
|
||||
import type * as bsky from '#/types/bsky'
|
||||
|
||||
export function createStarterPackLinkFromAndroidReferrer(
|
||||
referrerQueryString: string,
|
||||
|
@ -1,10 +1,7 @@
|
||||
import 'react-native-url-polyfill/auto'
|
||||
import 'fast-text-encoding'
|
||||
// @ts-ignore no decl -prf
|
||||
import findLast from 'array.prototype.findlast'
|
||||
export {}
|
||||
|
||||
findLast.shim()
|
||||
|
||||
/**
|
||||
https://github.com/MaxArt2501/base64-js
|
||||
The MIT License (MIT)
|
||||
|
@ -1,9 +1,6 @@
|
||||
// @ts-ignore no decl -prf
|
||||
import * as findLast from 'array.prototype.findlast'
|
||||
import 'array.prototype.findlast/auto'
|
||||
/// <reference lib="dom" />
|
||||
|
||||
findLast.shim()
|
||||
|
||||
// @ts-ignore whatever typescript wants to complain about here, I dont care about -prf
|
||||
window.setImmediate = (cb: () => void) => setTimeout(cb, 0)
|
||||
|
||||
|
@ -5,7 +5,7 @@ import {useLingui} from '@lingui/react'
|
||||
import {useQueryClient} from '@tanstack/react-query'
|
||||
|
||||
import {useInitialNumToRender} from '#/lib/hooks/useInitialNumToRender'
|
||||
import {isNative} from '#/platform/detection'
|
||||
import {isIOS, isNative} from '#/platform/detection'
|
||||
import {type FeedDescriptor} from '#/state/queries/post-feed'
|
||||
import {RQKEY as FEED_RQKEY} from '#/state/queries/post-feed'
|
||||
import {truncateAndInvalidate} from '#/state/queries/util'
|
||||
@ -67,7 +67,7 @@ export const ProfileFeedSection = React.forwardRef<
|
||||
}, [_])
|
||||
|
||||
React.useEffect(() => {
|
||||
if (isFocused && scrollElRef.current) {
|
||||
if (isIOS && isFocused && scrollElRef.current) {
|
||||
const nativeTag = findNodeHandle(scrollElRef.current)
|
||||
setScrollViewTag(nativeTag)
|
||||
}
|
||||
|
@ -14,7 +14,7 @@ import {useLingui} from '@lingui/react'
|
||||
import {useAnimatedScrollHandler} from '#/lib/hooks/useAnimatedScrollHandler_FIXED'
|
||||
import {isLabelerSubscribed, lookupLabelValueDefinition} from '#/lib/moderation'
|
||||
import {useScrollHandlers} from '#/lib/ScrollContext'
|
||||
import {isNative} from '#/platform/detection'
|
||||
import {isIOS, isNative} from '#/platform/detection'
|
||||
import {type ListRef} from '#/view/com/util/List'
|
||||
import {atoms as a, useTheme} from '#/alf'
|
||||
import {Divider} from '#/components/Divider'
|
||||
@ -92,7 +92,7 @@ export const ProfileLabelsSection = React.forwardRef<
|
||||
}))
|
||||
|
||||
React.useEffect(() => {
|
||||
if (isFocused && scrollElRef.current) {
|
||||
if (isIOS && isFocused && scrollElRef.current) {
|
||||
const nativeTag = findNodeHandle(scrollElRef.current)
|
||||
setScrollViewTag(nativeTag)
|
||||
}
|
||||
|
@ -118,7 +118,7 @@ import {LazyQuoteEmbed, QuoteX} from '#/view/com/util/post-embeds/QuoteEmbed'
|
||||
import {Text} from '#/view/com/util/text/Text'
|
||||
import * as Toast from '#/view/com/util/Toast'
|
||||
import {UserAvatar} from '#/view/com/util/UserAvatar'
|
||||
import {atoms as a, native, useTheme} from '#/alf'
|
||||
import {atoms as a, native, useTheme, web} from '#/alf'
|
||||
import {Button, ButtonIcon, ButtonText} from '#/components/Button'
|
||||
import {useDialogControl} from '#/components/Dialog'
|
||||
import {VerifyEmailDialog} from '#/components/dialogs/VerifyEmailDialog'
|
||||
@ -1266,39 +1266,41 @@ function ComposerFooter({
|
||||
a.justify_between,
|
||||
]}>
|
||||
<View style={[a.flex_row, a.align_center]}>
|
||||
{video && video.status !== 'done' ? (
|
||||
<VideoUploadToolbar state={video} />
|
||||
) : (
|
||||
<ToolbarWrapper style={[a.flex_row, a.align_center, a.gap_xs]}>
|
||||
<SelectPhotoBtn
|
||||
size={images.length}
|
||||
disabled={media?.type === 'images' ? isMaxImages : !!media}
|
||||
onAdd={onImageAdd}
|
||||
/>
|
||||
<SelectVideoBtn
|
||||
onSelectVideo={asset => onSelectVideo(post.id, asset)}
|
||||
disabled={!!media}
|
||||
setError={onError}
|
||||
/>
|
||||
<OpenCameraBtn
|
||||
disabled={media?.type === 'images' ? isMaxImages : !!media}
|
||||
onAdd={onImageAdd}
|
||||
/>
|
||||
<SelectGifBtn onSelectGif={onSelectGif} disabled={!!media} />
|
||||
{!isMobile ? (
|
||||
<Button
|
||||
onPress={onEmojiButtonPress}
|
||||
style={a.p_sm}
|
||||
label={_(msg`Open emoji picker`)}
|
||||
accessibilityHint={_(msg`Opens emoji picker`)}
|
||||
variant="ghost"
|
||||
shape="round"
|
||||
color="primary">
|
||||
<EmojiSmile size="lg" />
|
||||
</Button>
|
||||
) : null}
|
||||
</ToolbarWrapper>
|
||||
)}
|
||||
<LayoutAnimationConfig skipEntering skipExiting>
|
||||
{video && video.status !== 'done' ? (
|
||||
<VideoUploadToolbar state={video} />
|
||||
) : (
|
||||
<ToolbarWrapper style={[a.flex_row, a.align_center, a.gap_xs]}>
|
||||
<SelectPhotoBtn
|
||||
size={images.length}
|
||||
disabled={media?.type === 'images' ? isMaxImages : !!media}
|
||||
onAdd={onImageAdd}
|
||||
/>
|
||||
<SelectVideoBtn
|
||||
onSelectVideo={asset => onSelectVideo(post.id, asset)}
|
||||
disabled={!!media}
|
||||
setError={onError}
|
||||
/>
|
||||
<OpenCameraBtn
|
||||
disabled={media?.type === 'images' ? isMaxImages : !!media}
|
||||
onAdd={onImageAdd}
|
||||
/>
|
||||
<SelectGifBtn onSelectGif={onSelectGif} disabled={!!media} />
|
||||
{!isMobile ? (
|
||||
<Button
|
||||
onPress={onEmojiButtonPress}
|
||||
style={a.p_sm}
|
||||
label={_(msg`Open emoji picker`)}
|
||||
accessibilityHint={_(msg`Opens emoji picker`)}
|
||||
variant="ghost"
|
||||
shape="round"
|
||||
color="primary">
|
||||
<EmojiSmile size="lg" />
|
||||
</Button>
|
||||
) : null}
|
||||
</ToolbarWrapper>
|
||||
)}
|
||||
</LayoutAnimationConfig>
|
||||
</View>
|
||||
<View style={[a.flex_row, a.align_center, a.justify_between]}>
|
||||
{showAddButton && (
|
||||
@ -1515,10 +1517,10 @@ const styles = StyleSheet.create({
|
||||
paddingVertical: 6,
|
||||
marginLeft: 12,
|
||||
},
|
||||
stickyFooterWeb: {
|
||||
stickyFooterWeb: web({
|
||||
position: 'sticky',
|
||||
bottom: 0,
|
||||
},
|
||||
}),
|
||||
errorLine: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
|
@ -15,7 +15,7 @@ import {sanitizeHandle} from '#/lib/strings/handles'
|
||||
import {type ComposerOptsPostRef} from '#/state/shell/composer'
|
||||
import {MaybeQuoteEmbed} from '#/view/com/util/post-embeds/QuoteEmbed'
|
||||
import {PreviewableUserAvatar} from '#/view/com/util/UserAvatar'
|
||||
import {atoms as a, useTheme} from '#/alf'
|
||||
import {atoms as a, useTheme, web} from '#/alf'
|
||||
import {Text} from '#/components/Typography'
|
||||
import {useSimpleVerificationState} from '#/components/verification'
|
||||
import {VerificationCheck} from '#/components/verification/VerificationCheck'
|
||||
@ -76,7 +76,7 @@ export function ComposerReplyTo({replyTo}: {replyTo: ComposerOptsPostRef}) {
|
||||
a.mx_lg,
|
||||
a.border_b,
|
||||
t.atoms.border_contrast_medium,
|
||||
a.user_select_text,
|
||||
web(a.user_select_text),
|
||||
]}
|
||||
onPress={onPress}
|
||||
accessibilityRole="button"
|
||||
|
@ -12,7 +12,7 @@ import {useQueryClient} from '@tanstack/react-query'
|
||||
|
||||
import {cleanError} from '#/lib/strings/errors'
|
||||
import {logger} from '#/logger'
|
||||
import {isNative, isWeb} from '#/platform/detection'
|
||||
import {isIOS, isNative, isWeb} from '#/platform/detection'
|
||||
import {usePreferencesQuery} from '#/state/queries/preferences'
|
||||
import {RQKEY, useProfileFeedgensQuery} from '#/state/queries/profile-feedgens'
|
||||
import {EmptyState} from '#/view/com/util/EmptyState'
|
||||
@ -175,7 +175,7 @@ export const ProfileFeedgens = React.forwardRef<
|
||||
)
|
||||
|
||||
React.useEffect(() => {
|
||||
if (enabled && scrollElRef.current) {
|
||||
if (isIOS && enabled && scrollElRef.current) {
|
||||
const nativeTag = findNodeHandle(scrollElRef.current)
|
||||
setScrollViewTag(nativeTag)
|
||||
}
|
||||
|
@ -510,20 +510,22 @@ function LightboxImage({
|
||||
// This is a bug in Reanimated, but for now we'll work around it like this.
|
||||
dismissSwipeTranslateY.set(1)
|
||||
}
|
||||
dismissSwipeTranslateY.set(() =>
|
||||
withDecay({
|
||||
dismissSwipeTranslateY.set(() => {
|
||||
'worklet'
|
||||
return withDecay({
|
||||
velocity: e.velocityY,
|
||||
velocityFactor: Math.max(3500 / Math.abs(e.velocityY), 1), // Speed up if it's too slow.
|
||||
deceleration: 1, // Danger! This relies on the reaction below stopping it.
|
||||
}),
|
||||
)
|
||||
})
|
||||
})
|
||||
} else {
|
||||
dismissSwipeTranslateY.set(() =>
|
||||
withSpring(0, {
|
||||
dismissSwipeTranslateY.set(() => {
|
||||
'worklet'
|
||||
return withSpring(0, {
|
||||
stiffness: 700,
|
||||
damping: 50,
|
||||
}),
|
||||
)
|
||||
})
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
|
@ -12,7 +12,7 @@ import {useQueryClient} from '@tanstack/react-query'
|
||||
|
||||
import {cleanError} from '#/lib/strings/errors'
|
||||
import {logger} from '#/logger'
|
||||
import {isNative, isWeb} from '#/platform/detection'
|
||||
import {isIOS, isNative, isWeb} from '#/platform/detection'
|
||||
import {RQKEY, useProfileListsQuery} from '#/state/queries/profile-lists'
|
||||
import {EmptyState} from '#/view/com/util/EmptyState'
|
||||
import {ErrorMessage} from '#/view/com/util/error/ErrorMessage'
|
||||
@ -171,7 +171,7 @@ export const ProfileLists = React.forwardRef<SectionRef, ProfileListsProps>(
|
||||
)
|
||||
|
||||
React.useEffect(() => {
|
||||
if (enabled && scrollElRef.current) {
|
||||
if (isIOS && enabled && scrollElRef.current) {
|
||||
const nativeTag = findNodeHandle(scrollElRef.current)
|
||||
setScrollViewTag(nativeTag)
|
||||
}
|
||||
|
@ -1,16 +1,25 @@
|
||||
import React, {ComponentProps} from 'react'
|
||||
import {type ComponentPropsWithRef} from 'react'
|
||||
import {ScrollView} from 'react-native'
|
||||
|
||||
import {useDraggableScroll} from '#/lib/hooks/useDraggableScrollView'
|
||||
import {atoms as a, web} from '#/alf'
|
||||
|
||||
export const DraggableScrollView = React.forwardRef<
|
||||
ScrollView,
|
||||
ComponentProps<typeof ScrollView>
|
||||
>(function DraggableScrollView(props, ref) {
|
||||
export function DraggableScrollView({
|
||||
ref,
|
||||
style,
|
||||
...props
|
||||
}: ComponentPropsWithRef<typeof ScrollView>) {
|
||||
const {refs} = useDraggableScroll<ScrollView>({
|
||||
outerRef: ref,
|
||||
cursor: 'grab', // optional, default
|
||||
})
|
||||
|
||||
return <ScrollView ref={refs} horizontal {...props} />
|
||||
})
|
||||
return (
|
||||
<ScrollView
|
||||
ref={refs}
|
||||
style={[style, web(a.user_select_none)]}
|
||||
horizontal
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
@ -1,11 +1,16 @@
|
||||
import {useCallback} from 'react'
|
||||
import {LayoutChangeEvent, ScrollView, StyleSheet, View} from 'react-native'
|
||||
import {
|
||||
type LayoutChangeEvent,
|
||||
ScrollView,
|
||||
StyleSheet,
|
||||
View,
|
||||
} from 'react-native'
|
||||
import Animated, {
|
||||
interpolate,
|
||||
runOnJS,
|
||||
runOnUI,
|
||||
scrollTo,
|
||||
SharedValue,
|
||||
type SharedValue,
|
||||
useAnimatedReaction,
|
||||
useAnimatedRef,
|
||||
useAnimatedStyle,
|
||||
@ -267,15 +272,27 @@ export function TabBar({
|
||||
{
|
||||
translateX: interpolate(
|
||||
dragProgress.get(),
|
||||
layoutsValue.map((l, i) => i),
|
||||
layoutsValue.map(l => l.x + l.width / 2 - contentSize.get() / 2),
|
||||
layoutsValue.map((l, i) => {
|
||||
'worklet'
|
||||
return i
|
||||
}),
|
||||
layoutsValue.map(l => {
|
||||
'worklet'
|
||||
return l.x + l.width / 2 - contentSize.get() / 2
|
||||
}),
|
||||
),
|
||||
},
|
||||
{
|
||||
scaleX: interpolate(
|
||||
dragProgress.get(),
|
||||
textLayoutsValue.map((l, i) => i),
|
||||
textLayoutsValue.map((l, i) => getScaleX(i)),
|
||||
textLayoutsValue.map((l, i) => {
|
||||
'worklet'
|
||||
return i
|
||||
}),
|
||||
textLayoutsValue.map((l, i) => {
|
||||
'worklet'
|
||||
return getScaleX(i)
|
||||
}),
|
||||
),
|
||||
},
|
||||
],
|
||||
|
@ -1,7 +1,7 @@
|
||||
import {useCallback, useEffect, useRef} from 'react'
|
||||
import {ScrollView, StyleSheet, View} from 'react-native'
|
||||
import {type ScrollView, StyleSheet, View} from 'react-native'
|
||||
|
||||
import {atoms as a, useBreakpoints, useTheme} from '#/alf'
|
||||
import {atoms as a, useBreakpoints, useTheme, web} from '#/alf'
|
||||
import {Text} from '#/components/Typography'
|
||||
import {PressableWithHover} from '../util/PressableWithHover'
|
||||
import {DraggableScrollView} from './DraggableScrollView'
|
||||
@ -161,7 +161,7 @@ const desktopStyles = StyleSheet.create({
|
||||
},
|
||||
itemInner: {
|
||||
alignItems: 'center',
|
||||
overflowX: 'hidden',
|
||||
...web({overflowX: 'hidden'}),
|
||||
},
|
||||
itemText: {
|
||||
textAlign: 'center',
|
||||
@ -204,7 +204,7 @@ const mobileStyles = StyleSheet.create({
|
||||
itemInner: {
|
||||
flexGrow: 1,
|
||||
alignItems: 'center',
|
||||
overflowX: 'hidden',
|
||||
...web({overflowX: 'hidden'}),
|
||||
},
|
||||
itemText: {
|
||||
textAlign: 'center',
|
||||
|
@ -2,7 +2,8 @@ import React from 'react'
|
||||
import {StyleSheet, View} from 'react-native'
|
||||
import Svg, {Circle, Line} from 'react-native-svg'
|
||||
import {AtUri} from '@atproto/api'
|
||||
import {Trans} from '@lingui/macro'
|
||||
import {msg} from '@lingui/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
|
||||
import {usePalette} from '#/lib/hooks/usePalette'
|
||||
import {makeProfileLink} from '#/lib/routes/links'
|
||||
@ -22,6 +23,7 @@ export function ViewFullThread({uri}: {uri: string}) {
|
||||
const urip = new AtUri(uri)
|
||||
return makeProfileLink({did: urip.hostname, handle: ''}, 'post', urip.rkey)
|
||||
}, [uri])
|
||||
const {_} = useLingui()
|
||||
|
||||
return (
|
||||
<Link
|
||||
@ -53,7 +55,8 @@ export function ViewFullThread({uri}: {uri: string}) {
|
||||
</View>
|
||||
|
||||
<Text type="md" style={[pal.link, {paddingTop: 18, paddingBottom: 4}]}>
|
||||
<Trans>View full thread</Trans>
|
||||
{/* HACKFIX: Trans isn't working after SDK 53 upgrade -sfn */}
|
||||
{_(msg`View full thread`)}
|
||||
</Text>
|
||||
</Link>
|
||||
)
|
||||
|
@ -19,7 +19,7 @@ import RootSiblings from 'react-native-root-siblings'
|
||||
import {useSafeAreaInsets} from 'react-native-safe-area-context'
|
||||
import {
|
||||
FontAwesomeIcon,
|
||||
Props as FontAwesomeProps,
|
||||
type Props as FontAwesomeProps,
|
||||
} from '@fortawesome/react-native-fontawesome'
|
||||
|
||||
import {useNonReactiveCallback} from '#/lib/hooks/useNonReactiveCallback'
|
||||
|
@ -2,13 +2,14 @@
|
||||
* Note: the dataSet properties are used to leverage custom CSS in public/index.html
|
||||
*/
|
||||
|
||||
import React, {useEffect, useState} from 'react'
|
||||
import {useEffect, useState} from 'react'
|
||||
import {Pressable, StyleSheet, Text, View} from 'react-native'
|
||||
import {
|
||||
FontAwesomeIcon,
|
||||
FontAwesomeIconStyle,
|
||||
Props as FontAwesomeProps,
|
||||
type FontAwesomeIconStyle,
|
||||
type Props as FontAwesomeProps,
|
||||
} from '@fortawesome/react-native-fontawesome'
|
||||
import type React from 'react'
|
||||
|
||||
const DURATION = 3500
|
||||
|
||||
|
@ -239,7 +239,6 @@ const getKey = (label: string, index: number, id?: string) => {
|
||||
return `${label}_${index}`
|
||||
}
|
||||
|
||||
// @ts-expect-error - web only styles. the only style that should be broken here is `outline`
|
||||
const styles = StyleSheet.create({
|
||||
separator: {
|
||||
height: 1,
|
||||
@ -264,7 +263,6 @@ const styles = StyleSheet.create({
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'center',
|
||||
columnGap: 20,
|
||||
// @ts-ignore -web
|
||||
cursor: 'pointer',
|
||||
paddingTop: 8,
|
||||
paddingBottom: 8,
|
||||
@ -273,6 +271,7 @@ const styles = StyleSheet.create({
|
||||
borderRadius: 8,
|
||||
fontFamily:
|
||||
'-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Liberation Sans", Helvetica, Arial, sans-serif',
|
||||
// @ts-expect-error web only
|
||||
outline: 0,
|
||||
border: 0,
|
||||
},
|
||||
|
@ -12,9 +12,8 @@ import {useWebMediaQueries} from '#/lib/hooks/useWebMediaQueries'
|
||||
import {clamp} from '#/lib/numbers'
|
||||
import {useGate} from '#/lib/statsig/statsig'
|
||||
import {colors} from '#/lib/styles'
|
||||
import {isWeb} from '#/platform/detection'
|
||||
import {useSession} from '#/state/session'
|
||||
import {useLayoutBreakpoints} from '#/alf'
|
||||
import {atoms as a, useLayoutBreakpoints} from '#/alf'
|
||||
|
||||
export function LoadLatestBtn({
|
||||
onPress,
|
||||
@ -80,7 +79,7 @@ export function LoadLatestBtn({
|
||||
const styles = StyleSheet.create({
|
||||
loadLatest: {
|
||||
zIndex: 20,
|
||||
position: isWeb ? 'fixed' : 'absolute',
|
||||
...a.fixed,
|
||||
left: 18,
|
||||
borderWidth: StyleSheet.hairlineWidth,
|
||||
width: 52,
|
||||
|
@ -1,6 +1,7 @@
|
||||
import {StyleSheet} from 'react-native'
|
||||
|
||||
import {colors} from '#/lib/styles'
|
||||
import {atoms as a} from '#/alf'
|
||||
|
||||
export const styles = StyleSheet.create({
|
||||
bottomBar: {
|
||||
@ -13,9 +14,7 @@ export const styles = StyleSheet.create({
|
||||
paddingLeft: 5,
|
||||
paddingRight: 10,
|
||||
},
|
||||
bottomBarWeb: {
|
||||
position: 'fixed',
|
||||
},
|
||||
bottomBarWeb: a.fixed,
|
||||
ctrl: {
|
||||
flex: 1,
|
||||
paddingTop: 13,
|
||||
|
@ -32,7 +32,7 @@ import {LoadingPlaceholder} from '#/view/com/util/LoadingPlaceholder'
|
||||
import {PressableWithHover} from '#/view/com/util/PressableWithHover'
|
||||
import {UserAvatar} from '#/view/com/util/UserAvatar'
|
||||
import {NavSignupCard} from '#/view/shell/NavSignupCard'
|
||||
import {atoms as a, tokens, useLayoutBreakpoints, useTheme} from '#/alf'
|
||||
import {atoms as a, tokens, useLayoutBreakpoints, useTheme, web} from '#/alf'
|
||||
import {Button, ButtonIcon, ButtonText} from '#/components/Button'
|
||||
import {type DialogControlProps} from '#/components/Dialog'
|
||||
import {ArrowBoxLeft_Stroke2_Corner0_Rounded as LeaveIcon} from '#/components/icons/ArrowBoxLeft'
|
||||
@ -718,7 +718,7 @@ export function DesktopLeftNav() {
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
leftNav: {
|
||||
position: 'fixed',
|
||||
...a.fixed,
|
||||
top: 0,
|
||||
paddingTop: 10,
|
||||
paddingBottom: 10,
|
||||
@ -736,7 +736,7 @@ const styles = StyleSheet.create({
|
||||
height: '100%',
|
||||
width: 86,
|
||||
alignItems: 'center',
|
||||
overflowX: 'hidden',
|
||||
...web({overflowX: 'hidden'}),
|
||||
},
|
||||
backBtn: {
|
||||
position: 'absolute',
|
||||
|
@ -8,7 +8,7 @@ import {RemoveScrollBar} from 'react-remove-scroll-bar'
|
||||
import {useColorSchemeStyle} from '#/lib/hooks/useColorSchemeStyle'
|
||||
import {useIntentHandler} from '#/lib/hooks/useIntentHandler'
|
||||
import {useWebMediaQueries} from '#/lib/hooks/useWebMediaQueries'
|
||||
import {NavigationProp} from '#/lib/routes/types'
|
||||
import {type NavigationProp} from '#/lib/routes/types'
|
||||
import {colors} from '#/lib/styles'
|
||||
import {useIsDrawerOpen, useSetDrawerOpen} from '#/state/shell'
|
||||
import {useComposerKeyboardShortcut} from '#/state/shell/composer/useComposerKeyboardShortcut'
|
||||
@ -130,7 +130,7 @@ const styles = StyleSheet.create({
|
||||
backgroundColor: colors.black, // TODO
|
||||
},
|
||||
drawerMask: {
|
||||
position: 'fixed',
|
||||
...a.fixed,
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
top: 0,
|
||||
@ -138,7 +138,7 @@ const styles = StyleSheet.create({
|
||||
},
|
||||
drawerContainer: {
|
||||
display: 'flex',
|
||||
position: 'fixed',
|
||||
...a.fixed,
|
||||
top: 0,
|
||||
left: 0,
|
||||
height: '100%',
|
||||
|
@ -4,13 +4,12 @@
|
||||
"jsx": "react-jsx",
|
||||
"module": "esnext",
|
||||
"types": ["node", "jest"],
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"#/*": ["./src/*"],
|
||||
"lib/*": ["./src/lib/*"],
|
||||
"platform/*": ["./src/platform/*"],
|
||||
"state/*": ["./src/state/*"],
|
||||
"view/*": ["./src/view/*"],
|
||||
"crypto": ["./src/platform/crypto.ts"]
|
||||
"crypto": ["./src/platform/crypto.ts"],
|
||||
"multiformats/cid": ["node_modules/multiformats/types/src/cid.d.ts"],
|
||||
"multiformats/hashes/hasher": ["node_modules/multiformats/types/src/hashes/hasher.d.ts"]
|
||||
}
|
||||
},
|
||||
"exclude": ["bskyweb", "bskyembed", "web-build"]
|
||||
|
Loading…
x
Reference in New Issue
Block a user