diff --git a/__tests__/usecase/buffers/ui/Buffer.tsx b/__tests__/usecase/buffers/ui/Buffer.tsx index d1cef97..5228a68 100644 --- a/__tests__/usecase/buffers/ui/Buffer.tsx +++ b/__tests__/usecase/buffers/ui/Buffer.tsx @@ -2,11 +2,13 @@ import { fireEvent, render, screen, - waitFor + waitFor, + within } from '@testing-library/react-native'; import React from 'react'; import { ScrollView } from 'react-native'; import Buffer from '../../../../src/usecase/buffers/ui/Buffer'; +import { CellContainer } from '@shopify/flash-list'; jest.useFakeTimers(); @@ -15,7 +17,7 @@ describe(Buffer, () => { const nickWidthText = screen.getByText('aaaaaaaa', { hidden: true }); fireEvent(nickWidthText, 'layout', { nativeEvent: { - layout: { height: 26.5, width: 68, x: 0, y: 0 } + layout: { height: 16.7, width: 68, x: 0, y: 0 } } }); }; @@ -33,7 +35,8 @@ describe(Buffer, () => { date_printed: '2024-04-06T17:20:30.000Z', displayed: 1, highlight: 0, - message: 'Second message', + message: + 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', pointers: ['86c417600', '8580eeec0', '8580dcc40', '86c2ff040'], prefix: 'user', tags_array: ['irc_privmsg', 'notify_message'] @@ -60,53 +63,65 @@ describe(Buffer, () => { measureNickWidth(); - // Simulate layout event for the FlatList - const listElement = screen.getByLabelText('Message list'); - fireEvent(listElement, 'layout', { + // Simulate layout event for the ScrollView + const scrollView = screen.UNSAFE_getByType(ScrollView); + fireEvent(scrollView, 'layout', { nativeEvent: { layout: { height: 26.5, width: 1024, x: 0, y: 0 } } }); // Simulate layout event for first line - let message = screen.getByTestId('renderCell(0)'); - fireEvent(message, 'layout', { + let messageCell = screen + .UNSAFE_getAllByType(CellContainer) + .find((container) => + within(container).queryByText( + 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.' + ) + ); + expect(messageCell).toBeDefined(); + fireEvent(messageCell, 'layout', { nativeEvent: { - layout: { height: 26.5, width: 1024, x: 0, y: 0 } + layout: { height: 43, width: 1024, x: 0, y: 0 } } }); + jest.advanceTimersToNextTimer(); + bufferRef.current?.scrollToLine('86c2fefd0'); expect(ScrollView.prototype.scrollTo).toHaveBeenNthCalledWith(1, { animated: false, - y: 0 + x: 0, + y: 43 }); - // This is effectively a no-op, we are already at 0, 0. However, scrollTo - // triggers this and the VirtualizedList will update internal state based - // on the layout properties, so fire it here as well. - fireEvent.scroll(listElement, { + // Simulate scroll event in response to scrollTo + fireEvent.scroll(scrollView, { nativeEvent: { contentInset: { bottom: 0, left: 0, right: 0, top: 0 }, - contentOffset: { x: 0, y: 0 }, - contentSize: { height: 26.5, width: 1024 }, + contentOffset: { x: 0, y: 43 }, + contentSize: { height: 43, width: 1024 }, layoutMeasurement: { height: 26.5, width: 1024 } } }); // Simulate layout event for second line - message = screen.getByTestId('renderCell(1)'); - fireEvent(message, 'layout', { + messageCell = screen + .UNSAFE_getAllByType(CellContainer) + .find((container) => within(container).queryByText('First message')); + expect(messageCell).toBeDefined(); + fireEvent(messageCell, 'layout', { nativeEvent: { - layout: { height: 26.5, width: 1024, x: 0, y: 26.5 } + layout: { height: 26.5, width: 1024, x: 0, y: 43 } } }); await waitFor(() => { expect(ScrollView.prototype.scrollTo).toHaveBeenNthCalledWith(2, { animated: false, - y: 26.5 + x: 0, + y: 43 }); }); }); diff --git a/package-lock.json b/package-lock.json index 6414b48..85c7fed 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,15 +8,16 @@ "name": "WeechatNative", "version": "1.2.0", "dependencies": { - "@react-native-async-storage/async-storage": "1.21.0", + "@react-native-async-storage/async-storage": "1.23.1", "@reduxjs/toolkit": "^1.9.7", + "@shopify/flash-list": "1.6.3", "date-fns": "^3.3.1", "emoji-regex": "^10.3.0", - "expo": "~50.0.15", + "expo": "~50.0.17", "expo-clipboard": "~5.0.1", "expo-file-system": "~16.0.7", "expo-image-picker": "~14.7.1", - "expo-notifications": "~0.27.6", + "expo-notifications": "~0.27.7", "expo-updates": "~0.24.12", "react": "18.2.0", "react-native": "0.73.6", @@ -2101,14 +2102,14 @@ } }, "node_modules/@expo/cli": { - "version": "0.17.8", - "resolved": "https://registry.npmjs.org/@expo/cli/-/cli-0.17.8.tgz", - "integrity": "sha512-yfkoghCltbGPDbRI71Qu3puInjXx4wO82+uhW82qbWLvosfIN7ep5Gr0Lq54liJpvlUG6M0IXM1GiGqcCyP12w==", + "version": "0.17.10", + "resolved": "https://registry.npmjs.org/@expo/cli/-/cli-0.17.10.tgz", + "integrity": "sha512-Jw2wY+lsavP9GRqwwLqF/SvB7w2GZ4sWBMcBKTZ8F0lWjwmLGAUt4WYquf20agdmnY/oZUHvWNkrz/t3SflhnA==", "dependencies": { "@babel/runtime": "^7.20.0", "@expo/code-signing-certificates": "0.0.5", "@expo/config": "~8.5.0", - "@expo/config-plugins": "~7.8.0", + "@expo/config-plugins": "~7.9.0", "@expo/devcert": "^1.0.0", "@expo/env": "~0.2.2", "@expo/image-utils": "^0.4.0", @@ -2117,7 +2118,7 @@ "@expo/osascript": "^2.0.31", "@expo/package-manager": "^1.1.1", "@expo/plist": "^0.1.0", - "@expo/prebuild-config": "6.7.4", + "@expo/prebuild-config": "6.8.1", "@expo/rudder-sdk-node": "1.1.1", "@expo/spawn-async": "1.5.0", "@expo/xcpretty": "^4.3.0", @@ -2186,6 +2187,49 @@ "expo-internal": "build/bin/cli" } }, + "node_modules/@expo/cli/node_modules/@expo/config-plugins": { + "version": "7.9.1", + "resolved": "https://registry.npmjs.org/@expo/config-plugins/-/config-plugins-7.9.1.tgz", + "integrity": "sha512-ICt6Jed1J0tPYMQrJ8K5Qusgih2I6pZ2PU4VSvxsN3T4n97L13XpYV1vyq1Uc/HMl3UhOwldipmgpEbCfeDqsQ==", + "dependencies": { + "@expo/config-types": "^50.0.0-alpha.1", + "@expo/fingerprint": "^0.6.0", + "@expo/json-file": "~8.3.0", + "@expo/plist": "^0.1.0", + "@expo/sdk-runtime-versions": "^1.0.0", + "@react-native/normalize-color": "^2.0.0", + "chalk": "^4.1.2", + "debug": "^4.3.1", + "find-up": "~5.0.0", + "getenv": "^1.0.0", + "glob": "7.1.6", + "resolve-from": "^5.0.0", + "semver": "^7.5.3", + "slash": "^3.0.0", + "slugify": "^1.6.6", + "xcode": "^3.0.1", + "xml2js": "0.6.0" + } + }, + "node_modules/@expo/cli/node_modules/@expo/config-plugins/node_modules/glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/@expo/cli/node_modules/ansi-regex": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", @@ -2487,11 +2531,12 @@ } }, "node_modules/@expo/config": { - "version": "8.5.4", - "license": "MIT", + "version": "8.5.6", + "resolved": "https://registry.npmjs.org/@expo/config/-/config-8.5.6.tgz", + "integrity": "sha512-wF5awSg6MNn1cb1lIgjnhOn5ov2TEUTnkAVCsOl0QqDwcP+YIerteSFwjn9V52UZvg58L+LKxpCuGbw5IHavbg==", "dependencies": { "@babel/code-frame": "~7.10.4", - "@expo/config-plugins": "~7.8.2", + "@expo/config-plugins": "~7.9.0", "@expo/config-types": "^50.0.0", "@expo/json-file": "^8.2.37", "getenv": "^1.0.0", @@ -2570,6 +2615,30 @@ "@babel/highlight": "^7.10.4" } }, + "node_modules/@expo/config/node_modules/@expo/config-plugins": { + "version": "7.9.1", + "resolved": "https://registry.npmjs.org/@expo/config-plugins/-/config-plugins-7.9.1.tgz", + "integrity": "sha512-ICt6Jed1J0tPYMQrJ8K5Qusgih2I6pZ2PU4VSvxsN3T4n97L13XpYV1vyq1Uc/HMl3UhOwldipmgpEbCfeDqsQ==", + "dependencies": { + "@expo/config-types": "^50.0.0-alpha.1", + "@expo/fingerprint": "^0.6.0", + "@expo/json-file": "~8.3.0", + "@expo/plist": "^0.1.0", + "@expo/sdk-runtime-versions": "^1.0.0", + "@react-native/normalize-color": "^2.0.0", + "chalk": "^4.1.2", + "debug": "^4.3.1", + "find-up": "~5.0.0", + "getenv": "^1.0.0", + "glob": "7.1.6", + "resolve-from": "^5.0.0", + "semver": "^7.5.3", + "slash": "^3.0.0", + "slugify": "^1.6.6", + "xcode": "^3.0.1", + "xml2js": "0.6.0" + } + }, "node_modules/@expo/config/node_modules/glob": { "version": "7.1.6", "license": "ISC", @@ -2737,9 +2806,9 @@ } }, "node_modules/@expo/metro-config": { - "version": "0.17.6", - "resolved": "https://registry.npmjs.org/@expo/metro-config/-/metro-config-0.17.6.tgz", - "integrity": "sha512-WaC1C+sLX/Wa7irwUigLhng3ckmXIEQefZczB8DfYmleV6uhfWWo2kz/HijFBpV7FKs2cW6u8J/aBQpFkxlcqg==", + "version": "0.17.7", + "resolved": "https://registry.npmjs.org/@expo/metro-config/-/metro-config-0.17.7.tgz", + "integrity": "sha512-3vAdinAjMeRwdhGWWLX6PziZdAPvnyJ6KVYqnJErHHqH0cA6dgAENT3Vq6PEM1H2HgczKr2d5yG9AMgwy848ow==", "dependencies": { "@babel/core": "^7.20.0", "@babel/generator": "^7.20.5", @@ -2983,12 +3052,12 @@ } }, "node_modules/@expo/prebuild-config": { - "version": "6.7.4", - "resolved": "https://registry.npmjs.org/@expo/prebuild-config/-/prebuild-config-6.7.4.tgz", - "integrity": "sha512-x8EUdCa8DTMZ/dtEXjHAdlP+ljf6oSeSKNzhycXiHhpMSMG9jEhV28ocCwc6cKsjK5GziweEiHwvrj6+vsBlhA==", + "version": "6.8.1", + "resolved": "https://registry.npmjs.org/@expo/prebuild-config/-/prebuild-config-6.8.1.tgz", + "integrity": "sha512-ptK9e0dcj1eYlAWV+fG+QkuAWcLAT1AmtEbj++tn7ZjEj8+LkXRM73LCOEGaF0Er8i8ZWNnaVsgGW4vjgP5ZsA==", "dependencies": { "@expo/config": "~8.5.0", - "@expo/config-plugins": "~7.8.0", + "@expo/config-plugins": "~7.9.0", "@expo/config-types": "^50.0.0-alpha.1", "@expo/image-utils": "^0.4.0", "@expo/json-file": "^8.2.37", @@ -3002,6 +3071,49 @@ "expo-modules-autolinking": ">=0.8.1" } }, + "node_modules/@expo/prebuild-config/node_modules/@expo/config-plugins": { + "version": "7.9.1", + "resolved": "https://registry.npmjs.org/@expo/config-plugins/-/config-plugins-7.9.1.tgz", + "integrity": "sha512-ICt6Jed1J0tPYMQrJ8K5Qusgih2I6pZ2PU4VSvxsN3T4n97L13XpYV1vyq1Uc/HMl3UhOwldipmgpEbCfeDqsQ==", + "dependencies": { + "@expo/config-types": "^50.0.0-alpha.1", + "@expo/fingerprint": "^0.6.0", + "@expo/json-file": "~8.3.0", + "@expo/plist": "^0.1.0", + "@expo/sdk-runtime-versions": "^1.0.0", + "@react-native/normalize-color": "^2.0.0", + "chalk": "^4.1.2", + "debug": "^4.3.1", + "find-up": "~5.0.0", + "getenv": "^1.0.0", + "glob": "7.1.6", + "resolve-from": "^5.0.0", + "semver": "^7.5.3", + "slash": "^3.0.0", + "slugify": "^1.6.6", + "xcode": "^3.0.1", + "xml2js": "0.6.0" + } + }, + "node_modules/@expo/prebuild-config/node_modules/glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/@expo/prebuild-config/node_modules/semver": { "version": "7.5.3", "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.3.tgz", @@ -3718,8 +3830,9 @@ } }, "node_modules/@react-native-async-storage/async-storage": { - "version": "1.21.0", - "license": "MIT", + "version": "1.23.1", + "resolved": "https://registry.npmjs.org/@react-native-async-storage/async-storage/-/async-storage-1.23.1.tgz", + "integrity": "sha512-Qd2kQ3yi6Y3+AcUlrHxSLlnBvpdCEMVGFlVBneVOjaFaPU61g1huc38g339ysXspwY1QZA2aNhrk/KlHGO+ewA==", "dependencies": { "merge-options": "^3.0.4" }, @@ -4451,6 +4564,20 @@ "join-component": "^1.1.0" } }, + "node_modules/@shopify/flash-list": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/@shopify/flash-list/-/flash-list-1.6.3.tgz", + "integrity": "sha512-XM2iu4CeD9SOEUxaGG3UkxfUxGPWG9yacga1yQSgskAjUsRDFTsD3y4Dyon9n8MfDwgrRpEwuijd+7NeQQoWaQ==", + "dependencies": { + "recyclerlistview": "4.2.0", + "tslib": "2.4.0" + }, + "peerDependencies": { + "@babel/runtime": "*", + "react": "*", + "react-native": "*" + } + }, "node_modules/@sideway/address": { "version": "4.1.5", "resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.5.tgz", @@ -5547,8 +5674,9 @@ } }, "node_modules/babel-preset-expo": { - "version": "10.0.1", - "license": "MIT", + "version": "10.0.2", + "resolved": "https://registry.npmjs.org/babel-preset-expo/-/babel-preset-expo-10.0.2.tgz", + "integrity": "sha512-hg06qdSTK7MjKmFXSiq6cFoIbI3n3uT8a3NI2EZoISWhu+tedCj4DQduwi+3adFuRuYvAwECI0IYn/5iGh5zWQ==", "dependencies": { "@babel/plugin-proposal-decorators": "^7.12.9", "@babel/plugin-transform-export-namespace-from": "^7.22.11", @@ -7488,19 +7616,19 @@ } }, "node_modules/expo": { - "version": "50.0.15", - "resolved": "https://registry.npmjs.org/expo/-/expo-50.0.15.tgz", - "integrity": "sha512-tsyRmMHjA8lPlM7AsqH1smSH8hzmn1+x/vsP+xgbKYJTGtYccdY/wsm6P84VJWeK5peWSVqrWNos+YuPqXKLSQ==", + "version": "50.0.17", + "resolved": "https://registry.npmjs.org/expo/-/expo-50.0.17.tgz", + "integrity": "sha512-eD8Nh10BgVwecU7EVyogx7X314ajxVpJdFwkXhi341AD61S2WPX31NMHW82XGXas6dbDjdbgtaOMo5H/vylB7Q==", "dependencies": { "@babel/runtime": "^7.20.0", - "@expo/cli": "0.17.8", - "@expo/config": "8.5.4", - "@expo/config-plugins": "7.8.4", - "@expo/metro-config": "0.17.6", + "@expo/cli": "0.17.10", + "@expo/config": "8.5.6", + "@expo/config-plugins": "7.9.1", + "@expo/metro-config": "0.17.7", "@expo/vector-icons": "^14.0.0", - "babel-preset-expo": "~10.0.1", + "babel-preset-expo": "~10.0.2", "expo-asset": "~9.0.2", - "expo-file-system": "~16.0.8", + "expo-file-system": "~16.0.9", "expo-font": "~11.10.3", "expo-keep-awake": "~12.8.2", "expo-modules-autolinking": "1.10.3", @@ -7553,9 +7681,9 @@ "license": "MIT" }, "node_modules/expo-file-system": { - "version": "16.0.8", - "resolved": "https://registry.npmjs.org/expo-file-system/-/expo-file-system-16.0.8.tgz", - "integrity": "sha512-yDbVT0TUKd7ewQjaY5THum2VRFx2n/biskGhkUmLh3ai21xjIVtaeIzHXyv9ir537eVgt4ReqDNWi7jcXjdUcA==", + "version": "16.0.9", + "resolved": "https://registry.npmjs.org/expo-file-system/-/expo-file-system-16.0.9.tgz", + "integrity": "sha512-3gRPvKVv7/Y7AdD9eHMIdfg5YbUn2zbwKofjsloTI5sEC57SLUFJtbLvUCz9Pk63DaSQ7WIE1JM0EASyvuPbuw==", "peerDependencies": { "expo": "*" } @@ -7634,8 +7762,9 @@ } }, "node_modules/expo-notifications": { - "version": "0.27.6", - "license": "MIT", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/expo-notifications/-/expo-notifications-0.27.7.tgz", + "integrity": "sha512-qcetBEQlmV3VHvsJrpbQYDWpxXxFLs9HgUCb75YlGNzLrLG9puCE5lBIVskgErrG5ph8LaJs3JmazuwgW4qpQA==", "dependencies": { "@expo/image-utils": "^0.4.0", "@ide/backoff": "^1.0.0", @@ -7685,6 +7814,63 @@ "expo": "*" } }, + "node_modules/expo/node_modules/@expo/config-plugins": { + "version": "7.9.1", + "resolved": "https://registry.npmjs.org/@expo/config-plugins/-/config-plugins-7.9.1.tgz", + "integrity": "sha512-ICt6Jed1J0tPYMQrJ8K5Qusgih2I6pZ2PU4VSvxsN3T4n97L13XpYV1vyq1Uc/HMl3UhOwldipmgpEbCfeDqsQ==", + "dependencies": { + "@expo/config-types": "^50.0.0-alpha.1", + "@expo/fingerprint": "^0.6.0", + "@expo/json-file": "~8.3.0", + "@expo/plist": "^0.1.0", + "@expo/sdk-runtime-versions": "^1.0.0", + "@react-native/normalize-color": "^2.0.0", + "chalk": "^4.1.2", + "debug": "^4.3.1", + "find-up": "~5.0.0", + "getenv": "^1.0.0", + "glob": "7.1.6", + "resolve-from": "^5.0.0", + "semver": "^7.5.3", + "slash": "^3.0.0", + "slugify": "^1.6.6", + "xcode": "^3.0.1", + "xml2js": "0.6.0" + } + }, + "node_modules/expo/node_modules/glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/expo/node_modules/semver": { + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", + "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/fast-deep-equal": { "version": "3.1.3", "dev": true, @@ -10202,6 +10388,16 @@ "node": ">=0.8" } }, + "node_modules/json-schema-deref-sync/node_modules/md5": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/md5/-/md5-2.2.1.tgz", + "integrity": "sha512-PlGG4z5mBANDGCKsYQe0CaUYHdZYZt8ZPZLmEt+Urf0W4GlpTX4HescwHU+dc9+Z/G/vZKYZYFrwgm9VxK6QOQ==", + "dependencies": { + "charenc": "~0.0.1", + "crypt": "~0.0.1", + "is-buffer": "~1.1.1" + } + }, "node_modules/json-schema-traverse": { "version": "0.4.1", "dev": true, @@ -10726,13 +10922,13 @@ "license": "Apache-2.0" }, "node_modules/md5": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/md5/-/md5-2.2.1.tgz", - "integrity": "sha512-PlGG4z5mBANDGCKsYQe0CaUYHdZYZt8ZPZLmEt+Urf0W4GlpTX4HescwHU+dc9+Z/G/vZKYZYFrwgm9VxK6QOQ==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/md5/-/md5-2.3.0.tgz", + "integrity": "sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g==", "dependencies": { - "charenc": "~0.0.1", - "crypt": "~0.0.1", - "is-buffer": "~1.1.1" + "charenc": "0.0.2", + "crypt": "0.0.2", + "is-buffer": "~1.1.6" } }, "node_modules/md5-file": { @@ -12580,6 +12776,20 @@ "node": ">= 4" } }, + "node_modules/recyclerlistview": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/recyclerlistview/-/recyclerlistview-4.2.0.tgz", + "integrity": "sha512-uuBCi0c+ggqHKwrzPX4Z/mJOzsBbjZEAwGGmlwpD/sD7raXixdAbdJ6BTcAmuWG50Cg4ru9p12M94Njwhr/27A==", + "dependencies": { + "lodash.debounce": "4.0.8", + "prop-types": "15.8.1", + "ts-object-utils": "0.0.5" + }, + "peerDependencies": { + "react": ">= 15.2.1", + "react-native": ">= 0.30.0" + } + }, "node_modules/redent": { "version": "3.0.0", "dev": true, @@ -13843,10 +14053,15 @@ "version": "0.1.13", "license": "Apache-2.0" }, + "node_modules/ts-object-utils": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/ts-object-utils/-/ts-object-utils-0.0.5.tgz", + "integrity": "sha512-iV0GvHqOmilbIKJsfyfJY9/dNHCs969z3so90dQWsO1eMMozvTpnB1MEaUbb3FYtZTGjv5sIy/xmslEz0Rg2TA==" + }, "node_modules/tslib": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", - "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", + "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" }, "node_modules/type-check": { "version": "0.3.2", diff --git a/package.json b/package.json index f81b5dd..8f95295 100644 --- a/package.json +++ b/package.json @@ -8,15 +8,15 @@ "lint": "eslint . --ext .ts --ext .tsx --ext .js" }, "dependencies": { - "@react-native-async-storage/async-storage": "1.21.0", + "@react-native-async-storage/async-storage": "1.23.1", "@reduxjs/toolkit": "^1.9.7", "date-fns": "^3.3.1", "emoji-regex": "^10.3.0", - "expo": "~50.0.15", + "expo": "~50.0.17", "expo-clipboard": "~5.0.1", "expo-file-system": "~16.0.7", "expo-image-picker": "~14.7.1", - "expo-notifications": "~0.27.6", + "expo-notifications": "~0.27.7", "expo-updates": "~0.24.12", "react": "18.2.0", "react-native": "0.73.6", @@ -28,7 +28,8 @@ "react-redux": "^8.0.2", "redux": "^4.0.5", "redux-persist": "^6.0.0", - "redux-thunk": "^2.4.2" + "redux-thunk": "^2.4.2", + "@shopify/flash-list": "1.6.3" }, "devDependencies": { "@babel/core": "^7.19.3", diff --git a/src/usecase/buffers/ui/Buffer.tsx b/src/usecase/buffers/ui/Buffer.tsx index 3455de1..c333b23 100644 --- a/src/usecase/buffers/ui/Buffer.tsx +++ b/src/usecase/buffers/ui/Buffer.tsx @@ -1,13 +1,7 @@ import * as React from 'react'; -import { - Button, - CellRendererProps, - FlatList, - ListRenderItem, - Text, - View -} from 'react-native'; +import { Button, Text, View } from 'react-native'; +import { FlashList, ListRenderItem } from '@shopify/flash-list'; import { useEffect, useState } from 'react'; import { ParseShape } from 'react-native-parsed-text'; import BufferLine from './BufferLine'; @@ -63,7 +57,7 @@ interface State { export default class Buffer extends React.PureComponent { static readonly DEFAULT_LINE_INCREMENT = 300; - linesList = React.createRef>(); + linesList = React.createRef>(); state: State = { nickWidth: 0, @@ -90,31 +84,7 @@ export default class Buffer extends React.PureComponent { } } - onCellLayout?: (index: number) => void; - - onScrollToIndexFailed = async (info: { - index: number; - highestMeasuredFrameIndex: number; - averageItemLength: number; - }) => { - this.linesList.current?.scrollToIndex({ - index: info.highestMeasuredFrameIndex, - animated: false - }); - - await new Promise((resolve) => { - this.onCellLayout = (index: number) => { - if (index > info.highestMeasuredFrameIndex) resolve(); - }; - }); - this.onCellLayout = undefined; - - this.linesList.current?.scrollToIndex({ - index: info.index, - animated: false, - viewPosition: 0.5 - }); - }; + resolveViewableItems?: () => void; scrollToLine = async (lineId: string) => { const index = this.props.lines.findIndex( @@ -122,6 +92,21 @@ export default class Buffer extends React.PureComponent { ); if (index < 0) return; + const listView = this.linesList.current?.recyclerlistview_unsafe; + if (!listView) return; + + while (!listView.getLayout(index)?.isOverridden) { + this.linesList.current?.scrollToIndex({ + index: index, + animated: false + }); + + await new Promise((resolve) => { + this.resolveViewableItems = resolve; + }); + this.resolveViewableItems = undefined; + } + this.linesList.current?.scrollToIndex({ index: index, animated: false, @@ -151,38 +136,18 @@ export default class Buffer extends React.PureComponent { ); }; - renderCell: React.FC> = ({ - index, - children, - onLayout, - style - }) => { - return ( - { - onLayout?.(event); - this.onCellLayout?.(index); - }} - > - {children} - - ); - }; - render() { const { bufferId, lines, fetchMoreLines, notificationLineId } = this.props; const resetList = notificationLineId && !this.state.listReset; if (!this.state.nickWidth) { return ( - + { this.setState({ nickWidth: layout.nativeEvent.layout.width }); }} - style={[lineStyles.text, { opacity: 0 }]} + style={[lineStyles.text, { position: 'absolute' }]} > aaaaaaaa @@ -191,20 +156,14 @@ export default class Buffer extends React.PureComponent { } return ( - { fetchMoreLines={fetchMoreLines} /> } - onScrollToIndexFailed={this.onScrollToIndexFailed} + onViewableItemsChanged={() => { + this.resolveViewableItems?.(); + }} + estimatedItemSize={26.5} /> ); } diff --git a/src/usecase/buffers/ui/BufferLine.tsx b/src/usecase/buffers/ui/BufferLine.tsx index 1de15aa..4789010 100644 --- a/src/usecase/buffers/ui/BufferLine.tsx +++ b/src/usecase/buffers/ui/BufferLine.tsx @@ -5,7 +5,6 @@ import { formatDateDayChange } from '../../../lib/helpers/date-formatter'; import { cof } from '../../../lib/weechat/colors'; import Default, { styles } from './themes/Default'; import { isSameDay } from 'date-fns'; -import { memo } from 'react'; interface Props { line: WeechatLine; @@ -56,4 +55,4 @@ const BufferLine: React.FC = ({ ); }; -export default memo(BufferLine); +export default BufferLine;