diff --git a/__e2e__/tests/create-account.test.ts b/__e2e__/tests/create-account.test.ts index 7db4e912..8706fae7 100644 --- a/__e2e__/tests/create-account.test.ts +++ b/__e2e__/tests/create-account.test.ts @@ -25,6 +25,8 @@ describe('Create account', () => { await element(by.id('handleInput')).typeText('e2e-test') await device.takeScreenshot('4- entered handle') await element(by.id('nextBtn')).tap() + await expect(element(by.id('welcomeScreen'))).toBeVisible() + await element(by.id('continueBtn')).tap() await expect(element(by.id('homeScreen'))).toBeVisible() }) }) diff --git a/__e2e__/tests/home-screen.test.ts b/__e2e__/tests/home-screen.test.ts index 7fa9ff28..d0eeb670 100644 --- a/__e2e__/tests/home-screen.test.ts +++ b/__e2e__/tests/home-screen.test.ts @@ -55,7 +55,7 @@ describe('Home screen', () => { await element(by.id('postDropdownBtn').withAncestor(carlaPosts)) .atIndex(0) .tap() - await element(by.id('postDropdownReportBtn')).tap() + await element(by.text('Report post')).tap() await expect(element(by.id('reportPostModal'))).toBeVisible() await element( by.id('reportPostRadios-com.atproto.moderation.defs#reasonSpam'), @@ -84,7 +84,7 @@ describe('Home screen', () => { await element(by.id('postDropdownBtn').withAncestor(alicePosts)) .atIndex(0) .tap() - await element(by.id('postDropdownDeleteBtn')).tap() + await element(by.text('Delete post')).tap() await expect(element(by.id('confirmModal'))).toBeVisible() await element(by.id('confirmBtn')).tap() await expect( diff --git a/__e2e__/tests/invite-codes.test.ts b/__e2e__/tests/invite-codes.test.ts index 846d3b76..74b80a8d 100644 --- a/__e2e__/tests/invite-codes.test.ts +++ b/__e2e__/tests/invite-codes.test.ts @@ -42,6 +42,8 @@ describe('invite-codes', () => { await element(by.id('handleInput')).typeText('e2e-test') await device.takeScreenshot('4- entered handle') await element(by.id('nextBtn')).tap() + await expect(element(by.id('welcomeScreen'))).toBeVisible() + await element(by.id('continueBtn')).tap() await expect(element(by.id('homeScreen'))).toBeVisible() await element(by.id('viewHeaderDrawerBtn')).tap() await element(by.id('menuItemButton-Settings')).tap() diff --git a/__e2e__/tests/profile-screen.test.ts b/__e2e__/tests/profile-screen.test.ts index a7bb9365..6c6d6db9 100644 --- a/__e2e__/tests/profile-screen.test.ts +++ b/__e2e__/tests/profile-screen.test.ts @@ -62,10 +62,10 @@ describe('Profile screen', () => { await element(by.id('profileHeaderEditProfileButton')).tap() await expect(element(by.id('editProfileModal'))).toBeVisible() await element(by.id('changeBannerBtn')).tap() - await element(by.id('changeBannerLibraryBtn')).tap() + await element(by.text('Library')).tap() await sleep(3e3) await element(by.id('changeAvatarBtn')).tap() - await element(by.id('changeAvatarLibraryBtn')).tap() + await element(by.text('Library')).tap() await sleep(3e3) await element(by.id('editProfileSaveBtn')).tap() await expect(element(by.id('editProfileModal'))).not.toBeVisible() @@ -79,9 +79,9 @@ describe('Profile screen', () => { await element(by.id('profileHeaderEditProfileButton')).tap() await expect(element(by.id('editProfileModal'))).toBeVisible() await element(by.id('changeBannerBtn')).tap() - await element(by.id('changeBannerRemoveBtn')).tap() + await element(by.text('Remove')).tap() await element(by.id('changeAvatarBtn')).tap() - await element(by.id('changeAvatarRemoveBtn')).tap() + await element(by.text('Remove')).tap() await element(by.id('editProfileSaveBtn')).tap() await expect(element(by.id('editProfileModal'))).not.toBeVisible() await expect(element(by.id('userBannerFallback'))).toExist() @@ -109,16 +109,16 @@ describe('Profile screen', () => { it('Can mute/unmute another user', async () => { await expect(element(by.id('profileHeaderMutedNotice'))).not.toExist() await element(by.id('profileHeaderDropdownBtn')).tap() - await element(by.id('profileHeaderDropdownMuteBtn')).tap() + await element(by.text('Mute Account')).tap() await expect(element(by.id('profileHeaderMutedNotice'))).toBeVisible() await element(by.id('profileHeaderDropdownBtn')).tap() - await element(by.id('profileHeaderDropdownMuteBtn')).tap() + await element(by.text('Unmute Account')).tap() await expect(element(by.id('profileHeaderMutedNotice'))).not.toExist() }) it('Can report another user', async () => { await element(by.id('profileHeaderDropdownBtn')).tap() - await element(by.id('profileHeaderDropdownReportBtn')).tap() + await element(by.text('Report Account')).tap() await expect(element(by.id('reportAccountModal'))).toBeVisible() await element( by.id('reportAccountRadios-com.atproto.moderation.defs#reasonSpam'), @@ -166,7 +166,7 @@ describe('Profile screen', () => { it('Can report posts', async () => { const posts = by.id('feedItem-by-bob.test') await element(by.id('postDropdownBtn').withAncestor(posts)).atIndex(0).tap() - await element(by.id('postDropdownReportBtn')).tap() + await element(by.text('Report post')).tap() await expect(element(by.id('reportPostModal'))).toBeVisible() await element( by.id('reportPostRadios-com.atproto.moderation.defs#reasonSpam'), diff --git a/__e2e__/tests/thread-muting.test.ts b/__e2e__/tests/thread-muting.test.ts index a5cefdb2..8acd9d81 100644 --- a/__e2e__/tests/thread-muting.test.ts +++ b/__e2e__/tests/thread-muting.test.ts @@ -45,7 +45,7 @@ describe('Thread muting', () => { await element(by.id('postDropdownBtn').withAncestor(bobNotifs)) .atIndex(0) .tap() - await element(by.id('postDropdownMuteThreadBtn')).tap() + await element(by.text('Mute thread')).tap() // have to wait for the toast to clear await waitFor(element(by.id('viewHeaderDrawerBtn'))) .toBeVisible() @@ -93,7 +93,7 @@ describe('Thread muting', () => { await element(by.id('postDropdownBtn').withAncestor(alicePosts)) .atIndex(0) .tap() - await element(by.id('postDropdownMuteThreadBtn')).tap() + await element(by.text('Mute thread')).tap() // TODO // the swipe down to trigger PTR isnt working and I dont want to block on this diff --git a/__e2e__/tests/thread-screen.test.ts b/__e2e__/tests/thread-screen.test.ts index 8d3eacc8..081282a3 100644 --- a/__e2e__/tests/thread-screen.test.ts +++ b/__e2e__/tests/thread-screen.test.ts @@ -104,7 +104,7 @@ describe('Thread screen', () => { it('Can report the root post', async () => { const post = by.id('postThreadItem-by-bob.test') await element(by.id('postDropdownBtn').withAncestor(post)).atIndex(0).tap() - await element(by.id('postDropdownReportBtn')).tap() + await element(by.text('Report post')).tap() await expect(element(by.id('reportPostModal'))).toBeVisible() await element( by.id('reportPostRadios-com.atproto.moderation.defs#reasonSpam'), @@ -116,7 +116,7 @@ describe('Thread screen', () => { it('Can report a reply post', async () => { const post = by.id('postThreadItem-by-carla.test') await element(by.id('postDropdownBtn').withAncestor(post)).atIndex(0).tap() - await element(by.id('postDropdownReportBtn')).tap() + await element(by.text('Report post')).tap() await expect(element(by.id('reportPostModal'))).toBeVisible() await element( by.id('reportPostRadios-com.atproto.moderation.defs#reasonSpam'), diff --git a/__mocks__/zeego/dropdown-menu.js b/__mocks__/zeego/dropdown-menu.js new file mode 100644 index 00000000..1d51addc --- /dev/null +++ b/__mocks__/zeego/dropdown-menu.js @@ -0,0 +1,2 @@ +export const DropdownMenu = jest.fn().mockImplementation(() => {}) +export const create = jest.fn().mockImplementation(() => {}) diff --git a/app.json b/app.json index 2513fbba..be643334 100644 --- a/app.json +++ b/app.json @@ -80,6 +80,8 @@ { "android": { "compileSdkVersion": 34, + "targetSdkVersion": 34, + "buildToolsVersion": "34.0.0", "kotlinVersion": "1.8.0" } } diff --git a/package.json b/package.json index 4bb54087..1ede7bf1 100644 --- a/package.json +++ b/package.json @@ -42,6 +42,7 @@ "@react-native-clipboard/clipboard": "^1.10.0", "@react-native-community/blur": "^4.3.0", "@react-native-community/datetimepicker": "6.7.3", + "@react-native-menu/menu": "^0.8.0", "@react-navigation/bottom-tabs": "^6.5.7", "@react-navigation/drawer": "^6.6.2", "@react-navigation/native": "^6.1.6", @@ -120,6 +121,7 @@ "react-native-haptic-feedback": "^1.14.0", "react-native-image-crop-picker": "^0.38.1", "react-native-inappbrowser-reborn": "^3.6.3", + "react-native-ios-context-menu": "^1.15.3", "react-native-linear-gradient": "^2.6.2", "react-native-pager-view": "6.1.4", "react-native-progress": "bluesky-social/react-native-progress", @@ -139,6 +141,7 @@ "sentry-expo": "~6.1.0", "tippy.js": "^6.3.7", "tlds": "^1.234.0", + "zeego": "^1.6.2", "zod": "^3.20.2" }, "devDependencies": { diff --git a/src/lib/constants.ts b/src/lib/constants.ts index 34da35e4..001cdf8c 100644 --- a/src/lib/constants.ts +++ b/src/lib/constants.ts @@ -1,3 +1,5 @@ +import {Insets} from 'react-native' + const HELP_DESK_LANG = 'en-us' export const HELP_DESK_URL = `https://blueskyweb.zendesk.com/hc/${HELP_DESK_LANG}` @@ -134,3 +136,15 @@ export function LINK_META_PROXY(serviceUrl: string) { } export const STATUS_PAGE_URL = 'https://status.bsky.app/' + +// Hitslop constants +export const createHitslop = (size: number): Insets => ({ + top: size, + left: size, + bottom: size, + right: size, +}) +export const HITSLOP_10 = createHitslop(10) +export const HITSLOP_20 = createHitslop(20) +export const HITSLOP_30 = createHitslop(30) +export const BACK_HITSLOP = HITSLOP_30 diff --git a/src/view/com/auth/onboarding/Welcome.tsx b/src/view/com/auth/onboarding/Welcome.tsx index e7c068ea..87435c88 100644 --- a/src/view/com/auth/onboarding/Welcome.tsx +++ b/src/view/com/auth/onboarding/Welcome.tsx @@ -10,7 +10,7 @@ export const Welcome = ({next}: {next: () => void}) => { const pal = usePalette('default') return ( - + Welcome to Bluesky @@ -52,7 +52,12 @@ export const Welcome = ({next}: {next: () => void}) => { -