Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/main' into divy/bskylink
Browse files Browse the repository at this point in the history
  • Loading branch information
devinivy committed Jun 20, 2024
2 parents 4afa5b1 + 8019755 commit 6e5c9e8
Show file tree
Hide file tree
Showing 91 changed files with 2,178 additions and 1,237 deletions.
1 change: 1 addition & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ module.exports = {
},
},
],
'bsky-internal/use-exact-imports': 'error',
'bsky-internal/use-typed-gates': 'error',
'simple-import-sort/imports': [
'warn',
Expand Down
2 changes: 1 addition & 1 deletion .husky/pre-commit
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"

yarn lint-staged
npx lint-staged
74 changes: 0 additions & 74 deletions __tests__/lib/string.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import {createFullHandle, makeValidHandle} from '../../src/lib/strings/handles'
import {enforceLen} from '../../src/lib/strings/helpers'
import {detectLinkables} from '../../src/lib/strings/rich-text-detection'
import {shortenLinks} from '../../src/lib/strings/rich-text-manip'
import {ago} from '../../src/lib/strings/time'
import {
makeRecordUri,
toNiceDomain,
Expand Down Expand Up @@ -142,79 +141,6 @@ describe('makeRecordUri', () => {
})
})

// FIXME: Reenable after fixing non-deterministic test.
describe.skip('ago', () => {
const oneYearDate = new Date(
new Date().setMonth(new Date().getMonth() - 11),
).setDate(new Date().getDate() - 28)

const inputs = [
1671461038,
'04 Dec 1995 00:12:00 GMT',
new Date(),
new Date().setSeconds(new Date().getSeconds() - 10),
new Date().setMinutes(new Date().getMinutes() - 10),
new Date().setHours(new Date().getHours() - 1),
new Date().setDate(new Date().getDate() - 1),
new Date().setDate(new Date().getDate() - 20),
new Date().setDate(new Date().getDate() - 25),
new Date().setDate(new Date().getDate() - 28),
new Date().setDate(new Date().getDate() - 29),
new Date().setDate(new Date().getDate() - 30),
new Date().setMonth(new Date().getMonth() - 1),
new Date(new Date().setMonth(new Date().getMonth() - 1)).setDate(
new Date().getDate() - 20,
),
new Date(new Date().setMonth(new Date().getMonth() - 1)).setDate(
new Date().getDate() - 25,
),
new Date(new Date().setMonth(new Date().getMonth() - 1)).setDate(
new Date().getDate() - 28,
),
new Date(new Date().setMonth(new Date().getMonth() - 1)).setDate(
new Date().getDate() - 29,
),
new Date().setMonth(new Date().getMonth() - 11),
new Date(new Date().setMonth(new Date().getMonth() - 11)).setDate(
new Date().getDate() - 20,
),
new Date(new Date().setMonth(new Date().getMonth() - 11)).setDate(
new Date().getDate() - 25,
),
oneYearDate,
]
const outputs = [
new Date(1671461038).toLocaleDateString(),
new Date('04 Dec 1995 00:12:00 GMT').toLocaleDateString(),
'now',
'10s',
'10m',
'1h',
'1d',
'20d',
'25d',
'28d',
'29d',
'1mo',
'1mo',
'1mo',
'1mo',
'2mo',
'2mo',
'11mo',
'11mo',
'11mo',
new Date(oneYearDate).toLocaleDateString(),
]

it('correctly calculates how much time passed, in a string', () => {
for (let i = 0; i < inputs.length; i++) {
const result = ago(inputs[i])
expect(result).toEqual(outputs[i])
}
})
})

describe('makeValidHandle', () => {
const inputs = [
'test-handle-123',
Expand Down
1 change: 1 addition & 0 deletions assets/icons/newskie.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions eslint/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
module.exports = {
rules: {
'avoid-unwrapped-text': require('./avoid-unwrapped-text'),
'use-exact-imports': require('./use-exact-imports'),
'use-typed-gates': require('./use-typed-gates'),
},
}
22 changes: 22 additions & 0 deletions eslint/use-exact-imports.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/* eslint-disable bsky-internal/use-exact-imports */
const BANNED_IMPORTS = [
'@fortawesome/free-regular-svg-icons',
'@fortawesome/free-solid-svg-icons',
]

exports.create = function create(context) {
return {
Literal(node) {
if (typeof node.value !== 'string') {
return
}
if (BANNED_IMPORTS.includes(node.value)) {
context.report({
node,
message:
'Import the specific thing you want instead of the entire package',
})
}
},
}
}
8 changes: 5 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@
"open-analyzer": "EXPO_PUBLIC_OPEN_ANALYZER=1 yarn build-web"
},
"dependencies": {
"@atproto/api": "^0.12.18",
"@atproto/api": "^0.12.20",
"@bam.tech/react-native-image-resizer": "^3.0.4",
"@braintree/sanitize-url": "^6.0.2",
"@discord/bottom-sheet": "bluesky-social/react-native-bottom-sheet",
Expand All @@ -58,8 +58,9 @@
"@expo/webpack-config": "^19.0.0",
"@floating-ui/dom": "^1.6.3",
"@floating-ui/react-dom": "^2.0.8",
"@formatjs/intl-locale": "^3.4.3",
"@formatjs/intl-pluralrules": "^5.2.10",
"@formatjs/intl-locale": "^4.0.0",
"@formatjs/intl-numberformat": "^8.10.3",
"@formatjs/intl-pluralrules": "^5.2.14",
"@fortawesome/fontawesome-svg-core": "^6.1.1",
"@fortawesome/free-regular-svg-icons": "^6.1.1",
"@fortawesome/free-solid-svg-icons": "^6.1.1",
Expand Down Expand Up @@ -271,6 +272,7 @@
"resolutions": {
"@types/react": "^18",
"**/zeed-dom": "0.10.9",
"**/zod": "3.23.8",
"**/expo-constants": "16.0.1",
"**/expo-device": "6.0.2",
"@react-native/babel-preset": "0.74.1"
Expand Down
46 changes: 36 additions & 10 deletions patches/react-native+0.74.1.patch
Original file line number Diff line number Diff line change
@@ -1,11 +1,37 @@
diff --git a/node_modules/react-native/Libraries/Text/TextInput/RCTBaseTextInputView.mm b/node_modules/react-native/Libraries/Text/TextInput/RCTBaseTextInputView.mm
index b0d71dc..9974932 100644
--- a/node_modules/react-native/Libraries/Text/TextInput/RCTBaseTextInputView.mm
+++ b/node_modules/react-native/Libraries/Text/TextInput/RCTBaseTextInputView.mm
@@ -377,10 +377,6 @@ - (void)textInputDidBeginEditing
self.backedTextInputView.attributedText = [NSAttributedString new];
}

- if (_selectTextOnFocus) {
- [self.backedTextInputView selectAll:nil];
- }
-
[_eventDispatcher sendTextEventWithType:RCTTextEventTypeFocus
reactTag:self.reactTag
text:[self.backedTextInputView.attributedText.string copy]
@@ -611,6 +607,10 @@ - (UIView *)reactAccessibilityElement
- (void)reactFocus
{
[self.backedTextInputView reactFocus];
+
+ if (_selectTextOnFocus) {
+ [self.backedTextInputView selectAll:nil];
+ }
}

- (void)reactBlur
diff --git a/node_modules/react-native/React/Views/RefreshControl/RCTRefreshControl.h b/node_modules/react-native/React/Views/RefreshControl/RCTRefreshControl.h
index e9b330f..1ecdf0a 100644
--- a/node_modules/react-native/React/Views/RefreshControl/RCTRefreshControl.h
+++ b/node_modules/react-native/React/Views/RefreshControl/RCTRefreshControl.h
@@ -16,4 +16,6 @@
@property (nonatomic, copy) RCTDirectEventBlock onRefresh;
@property (nonatomic, weak) UIScrollView *scrollView;

+- (void)forwarderBeginRefreshing;
+
@end
Expand All @@ -16,7 +42,7 @@ index b09e653..4c32b31 100644
@@ -198,9 +198,53 @@ - (void)refreshControlValueChanged
[self setCurrentRefreshingState:super.refreshing];
_refreshingProgrammatically = NO;

+ if (@available(iOS 17.4, *)) {
+ if (_currentRefreshingState) {
+ UIImpactFeedbackGenerator *feedbackGenerator = [[UIImpactFeedbackGenerator alloc] initWithStyle:UIImpactFeedbackStyleLight];
Expand All @@ -29,7 +55,7 @@ index b09e653..4c32b31 100644
_onRefresh(nil);
}
}

+/*
+ 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
Expand All @@ -38,15 +64,15 @@ index b09e653..4c32b31 100644
+- (void)forwarderBeginRefreshing
+{
+ _refreshingProgrammatically = NO;
+
+
+ [self sizeToFit];
+
+
+ if (!self.scrollView) {
+ return;
+ }
+
+
+ UIScrollView *scrollView = (UIScrollView *)self.scrollView;
+
+
+ [UIView animateWithDuration:0.3
+ delay:0
+ options:UIViewAnimationOptionBeginFromCurrentState
Expand All @@ -58,7 +84,7 @@ index b09e653..4c32b31 100644
+ completion:^(__unused BOOL finished) {
+ [super beginRefreshing];
+ [self setCurrentRefreshingState:super.refreshing];
+
+
+ if (self->_onRefresh) {
+ self->_onRefresh(nil);
+ }
Expand All @@ -73,13 +99,13 @@ index 5f5e1ab..aac00b6 100644
+++ b/node_modules/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/core/JavaTimerManager.java
@@ -99,8 +99,9 @@ public class JavaTimerManager {
}

// If the JS thread is busy for multiple frames we cancel any other pending runnable.
- if (mCurrentIdleCallbackRunnable != null) {
- mCurrentIdleCallbackRunnable.cancel();
+ IdleCallbackRunnable currentRunnable = mCurrentIdleCallbackRunnable;
+ if (currentRunnable != null) {
+ currentRunnable.cancel();
}

mCurrentIdleCallbackRunnable = new IdleCallbackRunnable(frameTimeNanos);
7 changes: 7 additions & 0 deletions patches/react-native+0.74.1.patch.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,10 @@ 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.


## TextInput Patch - `selectTextOnFocus` fix

Patching `RCTBaseTextInputView.m` to fix an issue where `selectTextOnFocus` does not work as expected on iOS 17. This
patch _only_ fixes the Paper version of `TextInput`. If we migrate to Fabric and the fix has not been made upstream,
we can apply the same fix. See https://github.com/facebook/react-native/pull/44307.
85 changes: 46 additions & 39 deletions src/App.native.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,36 +14,40 @@ import * as SplashScreen from 'expo-splash-screen'
import {msg} from '@lingui/macro'
import {useLingui} from '@lingui/react'

import {Provider as StatsigProvider} from '#/lib/statsig/statsig'
import {useIntentHandler} from '#/lib/hooks/useIntentHandler'
import {QueryProvider} from '#/lib/react-query'
import {
initialize,
Provider as StatsigProvider,
tryFetchGates,
} from '#/lib/statsig/statsig'
import {s} from '#/lib/styles'
import {ThemeProvider} from '#/lib/ThemeContext'
import {logger} from '#/logger'
import {Provider as MutedThreadsProvider} from '#/state/cache/thread-mutes'
import {Provider as DialogStateProvider} from '#/state/dialogs'
import {Provider as InvitesStateProvider} from '#/state/invites'
import {Provider as LightboxStateProvider} from '#/state/lightbox'
import {MessagesProvider} from '#/state/messages'
import {Provider as ModalStateProvider} from '#/state/modals'
import {init as initPersistedState} from '#/state/persisted'
import {Provider as PrefsStateProvider} from '#/state/preferences'
import {Provider as LabelDefsProvider} from '#/state/preferences/label-defs'
import {Provider as ModerationOptsProvider} from '#/state/preferences/moderation-opts'
import {readLastActiveAccount} from '#/state/session/util'
import {useIntentHandler} from 'lib/hooks/useIntentHandler'
import {QueryProvider} from 'lib/react-query'
import {s} from 'lib/styles'
import {ThemeProvider} from 'lib/ThemeContext'
import {Provider as DialogStateProvider} from 'state/dialogs'
import {Provider as InvitesStateProvider} from 'state/invites'
import {Provider as LightboxStateProvider} from 'state/lightbox'
import {Provider as ModalStateProvider} from 'state/modals'
import {Provider as MutedThreadsProvider} from 'state/muted-threads'
import {Provider as PrefsStateProvider} from 'state/preferences'
import {Provider as UnreadNotifsProvider} from 'state/queries/notifications/unread'
import {Provider as UnreadNotifsProvider} from '#/state/queries/notifications/unread'
import {
Provider as SessionProvider,
SessionAccount,
useSession,
useSessionApi,
} from 'state/session'
import {Provider as ShellStateProvider} from 'state/shell'
import {Provider as LoggedOutViewProvider} from 'state/shell/logged-out'
import {Provider as SelectedFeedProvider} from 'state/shell/selected-feed'
import {TestCtrls} from 'view/com/testing/TestCtrls'
import * as Toast from 'view/com/util/Toast'
import {Shell} from 'view/shell'
} from '#/state/session'
import {readLastActiveAccount} from '#/state/session/util'
import {Provider as ShellStateProvider} from '#/state/shell'
import {Provider as LoggedOutViewProvider} from '#/state/shell/logged-out'
import {Provider as SelectedFeedProvider} from '#/state/shell/selected-feed'
import {TestCtrls} from '#/view/com/testing/TestCtrls'
import * as Toast from '#/view/com/util/Toast'
import {Shell} from '#/view/shell'
import {ThemeProvider as Alf} from '#/alf'
import {useColorModeTheme} from '#/alf/util/useColorModeTheme'
import {Provider as PortalProvider} from '#/components/Portal'
Expand All @@ -69,6 +73,9 @@ function InnerApp() {
try {
if (account) {
await resumeSession(account)
} else {
await initialize()
await tryFetchGates(undefined, 'prefer-fresh-gates')
}
} catch (e) {
logger.error(`session: resume failed`, {message: e})
Expand Down Expand Up @@ -105,10 +112,12 @@ function InnerApp() {
<SelectedFeedProvider>
<UnreadNotifsProvider>
<BackgroundNotificationPreferencesProvider>
<GestureHandlerRootView style={s.h100pct}>
<TestCtrls />
<Shell />
</GestureHandlerRootView>
<MutedThreadsProvider>
<GestureHandlerRootView style={s.h100pct}>
<TestCtrls />
<Shell />
</GestureHandlerRootView>
</MutedThreadsProvider>
</BackgroundNotificationPreferencesProvider>
</UnreadNotifsProvider>
</SelectedFeedProvider>
Expand Down Expand Up @@ -147,21 +156,19 @@ function App() {
<SessionProvider>
<ShellStateProvider>
<PrefsStateProvider>
<MutedThreadsProvider>
<InvitesStateProvider>
<ModalStateProvider>
<DialogStateProvider>
<LightboxStateProvider>
<I18nProvider>
<PortalProvider>
<InnerApp />
</PortalProvider>
</I18nProvider>
</LightboxStateProvider>
</DialogStateProvider>
</ModalStateProvider>
</InvitesStateProvider>
</MutedThreadsProvider>
<InvitesStateProvider>
<ModalStateProvider>
<DialogStateProvider>
<LightboxStateProvider>
<I18nProvider>
<PortalProvider>
<InnerApp />
</PortalProvider>
</I18nProvider>
</LightboxStateProvider>
</DialogStateProvider>
</ModalStateProvider>
</InvitesStateProvider>
</PrefsStateProvider>
</ShellStateProvider>
</SessionProvider>
Expand Down
Loading

0 comments on commit 6e5c9e8

Please sign in to comment.