Skip to content

Commit

Permalink
Merge branch 'dev' into feat/social-list
Browse files Browse the repository at this point in the history
  • Loading branch information
lawvs committed Feb 13, 2025
2 parents 5dc3b68 + 710ae5d commit cecd183
Show file tree
Hide file tree
Showing 13 changed files with 136 additions and 35 deletions.
50 changes: 50 additions & 0 deletions .github/workflows/build-eas.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
name: Build iOS IPA

on:
push:
branches: [dev, main]
paths:
- "apps/mobile/**"
pull_request:
branches: [dev, main]
paths:
- "apps/mobile/**"
workflow_dispatch:

jobs:
build:
name: Build iOS IPA
runs-on: macos-latest

steps:
- name: 📦 Checkout code
uses: actions/checkout@v4

- name: 📦 Setup pnpm
uses: pnpm/action-setup@v2
with:
run_install: true
- name: 🏗 Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 20
cache: "pnpm"

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

- name: 🔨 Build iOS IPA
run: |
cd apps/mobile
eas build --platform ios --profile production --non-interactive --local --output=./build.ipa
# Optional: Upload artifact
- name: 📤 Upload IPA
uses: actions/upload-artifact@v4
with:
name: app-ios
path: apps/mobile/build.ipa
retention-days: 5
2 changes: 1 addition & 1 deletion .github/workflows/tag.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,4 +46,4 @@ jobs:
-H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \
-H "Accept: application/vnd.github+json" \
https://api.github.com/repos/${{ github.repository }}/actions/workflows/build.yml/dispatches \
-d '{"ref":"main", "inputs": {"tag_version": "${{ env.tag_version }}"}}'
-d '{"ref":"main", "inputs": {"tag_version": "true"}}'
3 changes: 2 additions & 1 deletion apps/mobile/app.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import type { ConfigContext, ExpoConfig } from "expo/config"

import PKG from "./package.json"

const isDev = process.env.NODE_ENV === "development"
// const roundedIconPath = resolve(__dirname, "../../resources/icon.png")
const iconPath = resolve(__dirname, "./assets/icon.png")
const adaptiveIconPath = resolve(__dirname, "./assets/adaptive-icon.png")
Expand Down Expand Up @@ -105,7 +106,7 @@ export default ({ config }: ConfigContext): ExpoConfig => ({
require("./scripts/with-follow-assets.js"),
{
// Add asset directory paths, the plugin copies the files in the given paths to the app bundle folder named Assets
assetsPath: resolve(__dirname, "..", "..", "out", "rn-web"),
assetsPath: isDev ? resolve(__dirname, "..", "..", "out", "rn-web") : "/tmp/rn-web",
},
],
[require("./scripts/with-follow-app-delegate.js")],
Expand Down
20 changes: 5 additions & 15 deletions apps/mobile/babel.config.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
const path = require("node:path")

module.exports = function (api) {
api.cache(true)
return {
Expand All @@ -9,20 +7,12 @@ module.exports = function (api) {
[
"module-resolver",
{
root: ["./"],
alias: {
"es-toolkit/compat": path.resolve(
__dirname,
"../../node_modules/es-toolkit/dist/compat/index.js",
),
"es-toolkit": path.resolve(__dirname, "../../node_modules/es-toolkit/dist/index.js"),
"better-auth/react": path.resolve(
__dirname,
"../../node_modules/better-auth/dist/react.js",
),
"@better-auth/expo/client": path.resolve(
__dirname,
"../../node_modules/@better-auth/expo/dist/client.js",
),
"es-toolkit/compat": "../../node_modules/es-toolkit/dist/compat/index.js",
"es-toolkit": "../../node_modules/es-toolkit/dist/index.js",
"better-auth/react": "../../node_modules/better-auth/dist/react.js",
"@better-auth/expo/client": "../../node_modules/@better-auth/expo/dist/client.js",
},
extensions: [".js", ".jsx", ".ts", ".tsx"],
},
Expand Down
10 changes: 6 additions & 4 deletions apps/mobile/metro.config.js
Original file line number Diff line number Diff line change
@@ -1,21 +1,23 @@
const { getDefaultConfig } = require("expo/metro-config")
const { withNativeWind } = require("nativewind/metro")
const path = require("node:path")
const { wrapWithReanimatedMetroConfig } = require("react-native-reanimated/metro-config")

const config = getDefaultConfig(__dirname, { isCSSEnabled: true })
config.resolver.sourceExts.push("sql")

config.resolver.extraNodeModules = {
"follow-native": "./native",
}

config.transformer.getTransformOptions = async () => ({
transform: {
experimentalImportSupport: false,
inlineRequires: true,
},
})

config.resolver.nodeModulesPaths = [
path.resolve(__dirname, "./node_modules"),
path.resolve(__dirname, "../../node_modules"),
]

module.exports = wrapWithReanimatedMetroConfig(
withNativeWind(config, { input: "./src/global.css" }),
)
7 changes: 7 additions & 0 deletions apps/mobile/src/constants/spring.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import type { SpringConfig } from "react-native-reanimated/lib/typescript/animation/springUtils"

export const gentleSpringPreset: SpringConfig = {
damping: 15,
stiffness: 100,
mass: 1,
}
34 changes: 31 additions & 3 deletions apps/mobile/src/modules/entry-list/entry-list-article.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import type { ListRenderItemInfo } from "@shopify/flash-list"
import { Image } from "expo-image"
import { router } from "expo-router"
import { useCallback, useMemo } from "react"
import { Text, View } from "react-native"
import { useCallback, useEffect, useMemo } from "react"
import { Animated, Text, View } from "react-native"
import { useAnimatedStyle, useSharedValue, withSpring } from "react-native-reanimated"

import { setWebViewEntry } from "@/src/components/native/webview/EntryContentWebView"
import { ItemPressable } from "@/src/components/ui/pressable/item-pressable"
import { gentleSpringPreset } from "@/src/constants/spring"
import { useEntryListContext, useFetchEntriesControls } from "@/src/modules/feed-drawer/atoms"
import { useEntry } from "@/src/store/entry/hooks"
import { debouncedFetchEntryContentByStream } from "@/src/store/entry/store"
Expand Down Expand Up @@ -61,6 +63,28 @@ function EntryItem({ entryId }: { entryId: string }) {
router.push(`/entries/${entryId}`)
}, [entryId, entry])

const unreadZoomSharedValue = useSharedValue(entry?.read ? 0 : 1)

const unreadIndicatorStyle = useAnimatedStyle(() => {
return {
transform: [
{
scale: unreadZoomSharedValue.value,
},
],
}
})

useEffect(() => {
if (!entry) return

if (entry.read) {
unreadZoomSharedValue.value = withSpring(0, gentleSpringPreset)
} else {
unreadZoomSharedValue.value = withSpring(1, gentleSpringPreset)
}
}, [entry, entry?.read, unreadZoomSharedValue])

if (!entry) return <EntryItemSkeleton />
const { title, description, publishedAt, media } = entry
const image = media?.[0]?.url
Expand All @@ -69,7 +93,11 @@ function EntryItem({ entryId }: { entryId: string }) {
return (
<EntryItemContextMenu id={entryId}>
<ItemPressable className="flex flex-row items-center p-4" onPress={handlePress}>
{!entry.read && <View className="bg-red absolute left-1 top-6 size-2 rounded-full" />}
<Animated.View
className="bg-red absolute left-2 top-[22] size-2.5 rounded-full"
style={unreadIndicatorStyle}
/>

<View className="flex-1 space-y-2">
<Text numberOfLines={2} className="text-label text-lg font-semibold">
{title}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {
import { HomeLeftAction, HomeRightAction } from "@/src/modules/screen/action"
import { useEntryListContext, useSelectedFeedTitle } from "@/src/modules/screen/atoms"
import { headerHideableBottomHeight } from "@/src/modules/screen/hooks/useHeaderHeight"
import { ViewSelector } from "@/src/modules/screen/view-selector"
import { TimelineViewSelector } from "@/src/modules/screen/TimelineViewSelector"

export function TimelineSelectorHeader({ children }: { children: React.ReactNode }) {
const scrollY = useAnimatedValue(0)
Expand All @@ -32,7 +32,7 @@ export function TimelineSelectorHeader({ children }: { children: React.ReactNode
[isTimeline],
)}
headerHideableBottomHeight={isTimeline ? headerHideableBottomHeight : undefined}
headerHideableBottom={isTimeline ? ViewSelector : undefined}
headerHideableBottom={isTimeline ? TimelineViewSelector : undefined}
/>
{children}
</NavigationContext.Provider>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { useAnimatedStyle, useSharedValue, withSpring } from "react-native-reani

import { ReAnimatedTouchableOpacity } from "@/src/components/common/AnimatedComponents"
import { FallbackIcon } from "@/src/components/ui/icon/fallback-icon"
import { gentleSpringPreset } from "@/src/constants/spring"
import type { ViewDefinition } from "@/src/constants/views"
import { views } from "@/src/constants/views"
import { selectTimeline, useSelectedFeed } from "@/src/modules/screen/atoms"
Expand All @@ -15,7 +16,7 @@ import { useAllListSubscription } from "@/src/store/subscription/hooks"
import { useUnreadCountByView } from "@/src/store/unread/hooks"
import { accentColor, useColor } from "@/src/theme/colors"

export function ViewSelector() {
export function TimelineViewSelector() {
const lists = useAllListSubscription()

return (
Expand Down Expand Up @@ -48,12 +49,16 @@ function ItemWrapper({
onPress: () => void
style?: Exclude<StyleProp<ViewStyle>, number>
}) {
const width = useSharedValue(isActive ? 130 : 48)
const textWidth = useSharedValue(130)
const width = useSharedValue(isActive ? Math.max(130, textWidth.value + 48) : 48)
const bgColor = useColor("gray5")

useEffect(() => {
width.value = withSpring(isActive ? 130 : 48)
}, [isActive, width])
width.value = withSpring(
isActive ? Math.max(130, textWidth.value + 48) : 48,
gentleSpringPreset,
)
}, [isActive, width, textWidth])

return (
<ReAnimatedTouchableOpacity
Expand All @@ -65,7 +70,16 @@ function ItemWrapper({
...style,
}))}
>
{children}
<View
className="flex-row items-center gap-2"
onLayout={({ nativeEvent }) => {
if (isActive) {
textWidth.value = nativeEvent.layout.width
}
}}
>
{children}
</View>
</ReAnimatedTouchableOpacity>
)
}
Expand All @@ -89,7 +103,13 @@ function ViewItem({ view }: { view: ViewDefinition }) {
{view.name + (unreadCount ? ` (${unreadCount})` : "")}
</Text>
) : (
!!unreadCount && <View className="bg-gray absolute right-2 top-2 size-2 rounded-full" />
!!unreadCount &&
!isActive && (
<View
className="border-gray-2 absolute -right-0.5 -top-0.5 size-2.5 rounded-full"
style={{ backgroundColor: view.activeColor }}
/>
)
)}
</ItemWrapper>
)
Expand Down
2 changes: 1 addition & 1 deletion apps/mobile/src/modules/subscription/SubscriptionLists.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { useEventCallback } from "usehooks-ts"
import { ItemPressable } from "@/src/components/ui/pressable/item-pressable"
import { StarCuteFiIcon } from "@/src/icons/star_cute_fi"
import { closeDrawer, selectFeed } from "@/src/modules/screen/atoms"
import { TimelineSelectorList } from "@/src/modules/screen/timeline-selector-list"
import { TimelineSelectorList } from "@/src/modules/screen/TimelineSelectorList"
import { FEED_COLLECTION_LIST } from "@/src/store/entry/utils"
import {
useGroupedSubscription,
Expand Down
2 changes: 1 addition & 1 deletion apps/mobile/src/screens/(stack)/(tabs)/subscriptions.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { useSelectedFeed } from "@/src/modules/screen/atoms"
import { TimelineSelectorHeader } from "@/src/modules/screen/timeline-selector-header"
import { TimelineSelectorHeader } from "@/src/modules/screen/TimelineSelectorHeader"
import { SubscriptionList } from "@/src/modules/subscription/SubscriptionLists"

export default function Subscriptions() {
Expand Down
5 changes: 4 additions & 1 deletion apps/mobile/web-app/html-renderer/vite.config.mts
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,14 @@ import { defineConfig } from "vite"
import { viteRenderBaseConfig } from "../../../../configs/vite.render.config"
import { astPlugin } from "../../../../plugins/vite/ast"

const isDev = process.env.NODE_ENV === "development"
export default defineConfig({
...viteRenderBaseConfig,
base: "",
build: {
outDir: path.resolve(import.meta.dirname, "../../../../out/rn-web/html-renderer"),
outDir: isDev
? path.resolve(import.meta.dirname, "../../../../out/rn-web/html-renderer")
: path.resolve("/tmp/rn-web/html-renderer"),
},

plugins: [react({}), astPlugin],
Expand Down

0 comments on commit cecd183

Please sign in to comment.