Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions apps/mobile/src/components/ui/AppSymbol.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ import IconPlus from "@tabler/icons-react-native/IconPlus";
import IconQrcode from "@tabler/icons-react-native/IconQrcode";
import IconRefresh from "@tabler/icons-react-native/IconRefresh";
import IconSearch from "@tabler/icons-react-native/IconSearch";
import IconShare from "@tabler/icons-react-native/IconShare";
import IconServer from "@tabler/icons-react-native/IconServer";
import IconSettings from "@tabler/icons-react-native/IconSettings";
import IconSparkles from "@tabler/icons-react-native/IconSparkles";
Expand Down Expand Up @@ -244,6 +245,7 @@ const ANDROID_ICON_BY_SF_SYMBOL = {
"sidebar.left": IconLayoutSidebar,
"sidebar.right": IconLayoutSidebarRight,
"slider.horizontal.3": IconAdjustmentsHorizontal,
"square.and.arrow.up": IconShare,
"square.and.pencil": IconEdit,
"square.on.square": IconCopy,
"square.grid.2x2": IconApps,
Expand Down
38 changes: 32 additions & 6 deletions apps/mobile/src/features/pull-requests/PullRequestRouteScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ import { useAtomRefresh } from "@effect/atom-react";
import { pullRequestReviewKey } from "./pullRequestReviewDrafts";
import { type PullRequestDetail, type PullRequestListEntry } from "@t3tools/contracts";
import { PullRequestOverviewLoading } from "./PullRequestOverviewLoading";
import { copyPullRequestLink, sharePullRequestLink } from "./pullRequestLink";
import { pullRequestStatus } from "./pullRequestStatus";
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import {
Expand Down Expand Up @@ -420,12 +421,24 @@ export function PullRequestRouteScreen({ route }: StaticScreenProps<PullRequestP
},
]
: []),
...(pr
...(identity
? [
{
accessibilityLabel: openOnProviderLabel(pr.provider),
accessibilityLabel: openOnProviderLabel(identity.provider),
icon: "arrow.up.right" as const,
onPress: () => void Linking.openURL(pr.url),
onPress: () => void Linking.openURL(identity.url),
},
{
Comment thread
coderabbitai[bot] marked this conversation as resolved.
accessibilityLabel: "Copy link",
icon: "link" as const,
overflowOnly: true,
onPress: () => copyPullRequestLink(identity),
},
{
accessibilityLabel: "Share…",
icon: "square.and.arrow.up" as const,
overflowOnly: true,
onPress: () => sharePullRequestLink(identity),
},
]
: []),
Expand Down Expand Up @@ -470,12 +483,25 @@ export function PullRequestRouteScreen({ route }: StaticScreenProps<PullRequestP
<Toolbar.Label>Add comment</Toolbar.Label>
</Toolbar.MenuAction>
) : null}
{pr ? (
{identity ? (
<Toolbar.MenuAction
icon="arrow.up.right"
onPress={() => void Linking.openURL(pr.url)}
onPress={() => void Linking.openURL(identity.url)}
>
<Toolbar.Label>{openOnProviderLabel(identity.provider)}</Toolbar.Label>
</Toolbar.MenuAction>
) : null}
{identity ? (
<Toolbar.MenuAction icon="link" onPress={() => copyPullRequestLink(identity)}>
<Toolbar.Label>Copy link</Toolbar.Label>
</Toolbar.MenuAction>
) : null}
{identity ? (
<Toolbar.MenuAction
icon="square.and.arrow.up"
onPress={() => sharePullRequestLink(identity)}
>
<Toolbar.Label>{openOnProviderLabel(pr.provider)}</Toolbar.Label>
<Toolbar.Label>Share…</Toolbar.Label>
</Toolbar.MenuAction>
) : null}
{showsDeleteBranch ? (
Expand Down
18 changes: 18 additions & 0 deletions apps/mobile/src/features/pull-requests/pullRequestLink.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { Platform, Share } from "react-native";
import { copyTextWithHaptic } from "../../lib/copyTextWithHaptic";

interface PullRequestLink {
readonly url: string;
readonly title: string;
}

export function copyPullRequestLink(pr: PullRequestLink) {
copyTextWithHaptic(pr.url, { target: "pull request link" });
}

export function sharePullRequestLink(pr: PullRequestLink) {
// Android ignores `url`; iOS turns a `message` URL into plain text instead of a link preview.
Share.share(
Platform.OS === "ios" ? { url: pr.url, title: pr.title } : { message: pr.url, title: pr.title },
).catch((cause: unknown) => console.error("Failed to share pull request link.", cause));
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,9 @@ import { RegistryContext, useAtomValue } from "@effect/atom-react";
import { useNavigation } from "@react-navigation/native";
import { executeAtomQuery, squashAtomCommandFailure } from "@t3tools/client-runtime/state/runtime";
import type { EnvironmentId, PullRequestAction } from "@t3tools/contracts";
import * as Clipboard from "expo-clipboard";
import { Atom } from "effect/reactivity";
import { use, useCallback, useMemo, useRef, useState } from "react";
import { Linking, Platform, Share } from "react-native";
import { Linking, Platform } from "react-native";
import type { MenuProps } from "../../components/ui/Menu.types";
import { composerPullRequests } from "../../state/pull-requests";
import { useAtomCommand } from "../../state/use-atom-command";
Expand All @@ -16,6 +15,7 @@ import {
PR_ACTION_LABELS,
} from "./pullRequestActions";
import { scopedPullRequestListKey, type EnvironmentPullRequestListEntry } from "./pullRequestList";
import { copyPullRequestLink, sharePullRequestLink } from "./pullRequestLink";
import { pullRequestTarget } from "./usePullRequestDiff";
import { useAndroidWorkspaceSelection } from "../workspace/useAndroidWorkspaceSelection";

Expand Down Expand Up @@ -122,19 +122,15 @@ export function usePullRequestListActions(
return;
}
if (action === "copy") {
void Clipboard.setStringAsync(entry.url);
copyPullRequestLink(entry);
return;
}
if (action === "provider") {
void Linking.openURL(entry.url);
return;
}
if (action === "share") {
void Share.share(
Platform.OS === "ios"
? { url: entry.url, title: entry.title }
: { message: entry.url, title: entry.title },
);
sharePullRequestLink(entry);
return;
}
const supported = (["close", "reopen", "ready", "draft"] as const).find(
Expand Down
Loading