Skip to content
Open
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
40 changes: 40 additions & 0 deletions .github/workflows/eas-update.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
name: preview
on: pull_request

jobs:
update:
name: EAS Update
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: write
steps:
- name: Check for EXPO_TOKEN
run: |
if [ -z "${{ secrets.EXPO_TOKEN }}" ]; then
echo "You must provide an EXPO_TOKEN secret linked to this project's Expo account in this repo's secrets. Learn more: https://docs.expo.dev/eas-update/github-actions"
exit 1
fi

- name: Checkout repository
uses: actions/checkout@v3

- name: Setup Node
uses: actions/setup-node@v3
with:
node-version: 18.x
cache: 'npm'

- name: Setup EAS
uses: expo/expo-github-action@v8
with:
eas-version: latest
token: ${{ secrets.EXPO_TOKEN }}

- name: Install dependencies
run: npm install

- name: Create preview
uses: expo/expo-github-action/preview@v8
with:
command: eas update --auto
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,6 @@ expo-env.d.ts
storage/**

/ios
/android
/android

.idea
16 changes: 15 additions & 1 deletion app.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,27 @@
"plugins": [
[
"expo-router"
]
],
"react-native-image-marker"
],
"experiments": {
"typedRoutes": true
},
"runtimeVersion": {
"policy": "appVersion"
},
"extra": {
"router": {
"origin": false
},
"eas": {
"projectId": "b19fc96e-91a2-416a-a658-9271e4d93855"
}
},
"owner": "robertogolee",
"updates": {
"url": "https://u.expo.dev/b19fc96e-91a2-416a-a658-9271e4d93855"
}

}
}
13 changes: 11 additions & 2 deletions app/works/[id]/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ import { useFavStatusMutation } from "@/data/hooks/useFavStatusMutation";
import colors from "@/constants/colors";
import { useSafeAreaInsets } from "react-native-safe-area-context";
import { LoadingShade } from "@/components/LoadingShade";
import * as Sharing from "expo-sharing";
import ImagePicker from "react-native-image-crop-picker";

export default function DisplayWork() {
const dimensions = useWindowDimensions();
Expand All @@ -35,6 +37,10 @@ export default function DisplayWork() {
// update fav status
const favMutation = useFavStatusMutation();

async function share() {
await Sharing.shareAsync(work.images.web.url);
}

return (
<View className="flex-1 bg-shade-1">
<Stack.Screen
Expand All @@ -61,7 +67,7 @@ export default function DisplayWork() {
<Text className="flex-1 font-semibold text-3xl px-4 py-2 bg-shade-2">
{work?.title}
</Text>
<View className="justify-center px-4 flex-row items-center">
<View className="justify-center px-4 flex-row items-center gap-3">
<Pressable
className="active:opacity-50"
disabled={favQuery.isLoading || favMutation.isPending}
Expand All @@ -75,6 +81,9 @@ export default function DisplayWork() {
size={28}
/>
</Pressable>
<Link push href={`/works/${id}/share`} onPress={share}>
<Icon name="share-alt" color={colors.tint} size={28} />
</Link>
</View>
</View>
<View className="px-4 gap-y-2 py-2">
Expand Down Expand Up @@ -111,4 +120,4 @@ export default function DisplayWork() {

function stripTags(htmlish: string) {
return htmlish.replace(/<[^>]*>?/gm, "");
}
}
130 changes: 130 additions & 0 deletions app/works/[id]/share.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
import {View, Text, useWindowDimensions, Pressable, Platform} from "react-native";
import {Stack, useLocalSearchParams} from "expo-router";
import {Image} from "expo-image";
import {useWorkByIdQuery} from "@/data/hooks/useWorkByIdQuery";
import {LoadingShade} from "@/components/LoadingShade";
import ImagePicker from "react-native-image-crop-picker";
import {useState} from "react";
import * as Sharing from "expo-sharing";
import Marker, {ImageFormat, Position, TextBackgroundType} from "react-native-image-marker";

export default function ShareWork() {
const dimensions = useWindowDimensions();
const {id} = useLocalSearchParams<{ id: string }>();
const {data: work, isLoading} = useWorkByIdQuery(id!);

function normalizeFilePath(path: string) {
if (Platform.OS === "android" && !path.startsWith("file://")) {
return `file://${path}`;
}
return path;
}

const [editedImagePath, setEditedImagePath] = useState<string | undefined>(
undefined
);

async function crop() {

const image = await ImagePicker.openCropper({
path: work.images.web.url,
width: 300,
height: 300,
mediaType: "photo",
});

const markedImagePath = await Marker.markText({
backgroundImage: {
src: image.path,
scale: 1,
},

watermarkTexts: [
{
text: "#cma",
position: {
position: Position.bottomRight,
},
style: {
color: "#fff",
fontSize: 20,
textBackgroundStyle: {
type: TextBackgroundType.none,
color: "#000",
paddingX: 16,
paddingY: 6,
},
},
},
],
quality: 100,
filename: image.filename,
saveFormat: ImageFormat.jpg,
});

setEditedImagePath(normalizeFilePath(markedImagePath));
}

async function share() {
editedImagePath && await Sharing.shareAsync(editedImagePath);
}


return (
<View className="flex-1 bg-shade-1">
<Stack.Screen
options={{
title: "Share",
}}
/>
<View className="py-4 px-4 bg-shade-2 gap-3">
<Text className="text-2xl text-center">
Share a clip of this work with your friends.
</Text>
<View
style={{
height: dimensions.width - 50,
width: dimensions.width - 50,
alignSelf: "center",
}}
>
<Image
source={{ uri: editedImagePath ? editedImagePath : (work && work.images.web.url) }}
style={{width: "100%", height: "100%"}}
contentFit="cover"
transition={500}
/>
</View>
<RoundButton onPress={crop} title="Crop"/>
<RoundButton
title="Share"
onPress={share}
disabled={!editedImagePath}
/>
</View>
<LoadingShade isLoading={isLoading}/>
</View>
);
}

function RoundButton({
title,
onPress,
disabled = false,
}: {
title: string;
onPress: () => void;
disabled?: boolean;
}) {
return (
<Pressable
onPress={onPress}
disabled={disabled}
className={`py-2 rounded-md active:opacity-50 ${
disabled ? "bg-gray-500" : "bg-tint"
}`}
>
<Text className="text-xl text-center text-white">{title}</Text>
</Pressable>
);
}