diff --git a/.kilo/package-lock.json b/.kilo/package-lock.json
index 86ea34f..edda722 100644
--- a/.kilo/package-lock.json
+++ b/.kilo/package-lock.json
@@ -5,21 +5,22 @@
"packages": {
"": {
"dependencies": {
- "@kilocode/plugin": "7.2.10"
+ "@kilocode/plugin": "7.2.31"
}
},
"node_modules/@kilocode/plugin": {
- "version": "7.2.10",
- "resolved": "https://registry.npmjs.org/@kilocode/plugin/-/plugin-7.2.10.tgz",
- "integrity": "sha512-VJPhJC+E5WWu7XgEJzrVOxKJlwJ+OATwxEzgjqEPj8KN5N38YxUPBY/rzUTjv90x7nkzyk1rFGfCVqXdA/Koug==",
+ "version": "7.2.31",
+ "resolved": "https://registry.npmmirror.com/@kilocode/plugin/-/plugin-7.2.31.tgz",
+ "integrity": "sha512-KmKTTIly7hRlJdXKhqZ/j/brvTPh0z0UTjWSjJWq5fqf4pATgYGn7G0g3ZjILnN7MUkkZXuljgqExTEeQJHGkQ==",
"license": "MIT",
"dependencies": {
- "@kilocode/sdk": "7.2.10",
+ "@kilocode/sdk": "7.2.31",
+ "effect": "4.0.0-beta.48",
"zod": "4.1.8"
},
"peerDependencies": {
- "@opentui/core": ">=0.1.97",
- "@opentui/solid": ">=0.1.97"
+ "@opentui/core": ">=0.1.100",
+ "@opentui/solid": ">=0.1.100"
},
"peerDependenciesMeta": {
"@opentui/core": {
@@ -31,17 +32,101 @@
}
},
"node_modules/@kilocode/sdk": {
- "version": "7.2.10",
- "resolved": "https://registry.npmjs.org/@kilocode/sdk/-/sdk-7.2.10.tgz",
- "integrity": "sha512-H6jGXYAhN/yjOGX3MRZ0OxyEAuRGY3VOwDbLTh4O6ljpgutFHaLvomDZ82qNVy7gl7AjJgi3SAQAt9UQpeGl/w==",
+ "version": "7.2.31",
+ "resolved": "https://registry.npmmirror.com/@kilocode/sdk/-/sdk-7.2.31.tgz",
+ "integrity": "sha512-Sx05yv+3TIlc6M4Ze+YGgKCLoIg8B0WRE15JXDriVncT+wz7M6+e+4mjNWkwfsuywdeOTYPfeFViqX8iO7ckKA==",
"license": "MIT",
"dependencies": {
"cross-spawn": "7.0.6"
}
},
+ "node_modules/@msgpackr-extract/msgpackr-extract-darwin-arm64": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmmirror.com/@msgpackr-extract/msgpackr-extract-darwin-arm64/-/msgpackr-extract-darwin-arm64-3.0.3.tgz",
+ "integrity": "sha512-QZHtlVgbAdy2zAqNA9Gu1UpIuI8Xvsd1v8ic6B2pZmeFnFcMWiPLfWXh7TVw4eGEZ/C9TH281KwhVoeQUKbyjw==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ]
+ },
+ "node_modules/@msgpackr-extract/msgpackr-extract-darwin-x64": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmmirror.com/@msgpackr-extract/msgpackr-extract-darwin-x64/-/msgpackr-extract-darwin-x64-3.0.3.tgz",
+ "integrity": "sha512-mdzd3AVzYKuUmiWOQ8GNhl64/IoFGol569zNRdkLReh6LRLHOXxU4U8eq0JwaD8iFHdVGqSy4IjFL4reoWCDFw==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ]
+ },
+ "node_modules/@msgpackr-extract/msgpackr-extract-linux-arm": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmmirror.com/@msgpackr-extract/msgpackr-extract-linux-arm/-/msgpackr-extract-linux-arm-3.0.3.tgz",
+ "integrity": "sha512-fg0uy/dG/nZEXfYilKoRe7yALaNmHoYeIoJuJ7KJ+YyU2bvY8vPv27f7UKhGRpY6euFYqEVhxCFZgAUNQBM3nw==",
+ "cpu": [
+ "arm"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@msgpackr-extract/msgpackr-extract-linux-arm64": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmmirror.com/@msgpackr-extract/msgpackr-extract-linux-arm64/-/msgpackr-extract-linux-arm64-3.0.3.tgz",
+ "integrity": "sha512-YxQL+ax0XqBJDZiKimS2XQaf+2wDGVa1enVRGzEvLLVFeqa5kx2bWbtcSXgsxjQB7nRqqIGFIcLteF/sHeVtQg==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@msgpackr-extract/msgpackr-extract-linux-x64": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmmirror.com/@msgpackr-extract/msgpackr-extract-linux-x64/-/msgpackr-extract-linux-x64-3.0.3.tgz",
+ "integrity": "sha512-cvwNfbP07pKUfq1uH+S6KJ7dT9K8WOE4ZiAcsrSes+UY55E/0jLYc+vq+DO7jlmqRb5zAggExKm0H7O/CBaesg==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@msgpackr-extract/msgpackr-extract-win32-x64": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmmirror.com/@msgpackr-extract/msgpackr-extract-win32-x64/-/msgpackr-extract-win32-x64-3.0.3.tgz",
+ "integrity": "sha512-x0fWaQtYp4E6sktbsdAqnehxDgEc/VwM7uLsRCYWaiGu0ykYdZPiS8zCWdnjHwyiumousxfBm4SO31eXqwEZhQ==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
+ "node_modules/@standard-schema/spec": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmmirror.com/@standard-schema/spec/-/spec-1.1.0.tgz",
+ "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==",
+ "license": "MIT"
+ },
"node_modules/cross-spawn": {
"version": "7.0.6",
- "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
+ "resolved": "https://registry.npmmirror.com/cross-spawn/-/cross-spawn-7.0.6.tgz",
"integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==",
"license": "MIT",
"dependencies": {
@@ -53,24 +138,163 @@
"node": ">= 8"
}
},
+ "node_modules/detect-libc": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmmirror.com/detect-libc/-/detect-libc-2.1.2.tgz",
+ "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==",
+ "license": "Apache-2.0",
+ "optional": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/effect": {
+ "version": "4.0.0-beta.48",
+ "resolved": "https://registry.npmmirror.com/effect/-/effect-4.0.0-beta.48.tgz",
+ "integrity": "sha512-MMAM/ZabuNdNmgXiin+BAanQXK7qM8mlt7nfXDoJ/Gn9V8i89JlCq+2N0AiWmqFLXjGLA0u3FjiOjSOYQk5uMw==",
+ "license": "MIT",
+ "dependencies": {
+ "@standard-schema/spec": "^1.1.0",
+ "fast-check": "^4.6.0",
+ "find-my-way-ts": "^0.1.6",
+ "ini": "^6.0.0",
+ "kubernetes-types": "^1.30.0",
+ "msgpackr": "^1.11.9",
+ "multipasta": "^0.2.7",
+ "toml": "^4.1.1",
+ "uuid": "^13.0.0",
+ "yaml": "^2.8.3"
+ }
+ },
+ "node_modules/fast-check": {
+ "version": "4.7.0",
+ "resolved": "https://registry.npmmirror.com/fast-check/-/fast-check-4.7.0.tgz",
+ "integrity": "sha512-NsZRtqvSSoCP0HbNjUD+r1JH8zqZalyp6gLY9e7OYs7NK9b6AHOs2baBFeBG7bVNsuoukh89x2Yg3rPsul8ziQ==",
+ "funding": [
+ {
+ "type": "individual",
+ "url": "https://github.com/sponsors/dubzzz"
+ },
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/fast-check"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "pure-rand": "^8.0.0"
+ },
+ "engines": {
+ "node": ">=12.17.0"
+ }
+ },
+ "node_modules/find-my-way-ts": {
+ "version": "0.1.6",
+ "resolved": "https://registry.npmmirror.com/find-my-way-ts/-/find-my-way-ts-0.1.6.tgz",
+ "integrity": "sha512-a85L9ZoXtNAey3Y6Z+eBWW658kO/MwR7zIafkIUPUMf3isZG0NCs2pjW2wtjxAKuJPxMAsHUIP4ZPGv0o5gyTA==",
+ "license": "MIT"
+ },
+ "node_modules/ini": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmmirror.com/ini/-/ini-6.0.0.tgz",
+ "integrity": "sha512-IBTdIkzZNOpqm7q3dRqJvMaldXjDHWkEDfrwGEQTs5eaQMWV+djAhR+wahyNNMAa+qpbDUhBMVt4ZKNwpPm7xQ==",
+ "license": "ISC",
+ "engines": {
+ "node": "^20.17.0 || >=22.9.0"
+ }
+ },
"node_modules/isexe": {
"version": "2.0.0",
- "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
+ "resolved": "https://registry.npmmirror.com/isexe/-/isexe-2.0.0.tgz",
"integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
"license": "ISC"
},
+ "node_modules/kubernetes-types": {
+ "version": "1.30.0",
+ "resolved": "https://registry.npmmirror.com/kubernetes-types/-/kubernetes-types-1.30.0.tgz",
+ "integrity": "sha512-Dew1okvhM/SQcIa2rcgujNndZwU8VnSapDgdxlYoB84ZlpAD43U6KLAFqYo17ykSFGHNPrg0qry0bP+GJd9v7Q==",
+ "license": "Apache-2.0"
+ },
+ "node_modules/msgpackr": {
+ "version": "1.11.12",
+ "resolved": "https://registry.npmmirror.com/msgpackr/-/msgpackr-1.11.12.tgz",
+ "integrity": "sha512-RBdJ1Un7yGlXWajrkxcSa93nvQ0w4zBf60c0yYv7YtBelP8H2FA7XsfBbMHtXKXUMUxH7zV3Zuozh+kUQWhHvg==",
+ "license": "MIT",
+ "optionalDependencies": {
+ "msgpackr-extract": "^3.0.2"
+ }
+ },
+ "node_modules/msgpackr-extract": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmmirror.com/msgpackr-extract/-/msgpackr-extract-3.0.3.tgz",
+ "integrity": "sha512-P0efT1C9jIdVRefqjzOQ9Xml57zpOXnIuS+csaB4MdZbTdmGDLo8XhzBG1N7aO11gKDDkJvBLULeFTo46wwreA==",
+ "hasInstallScript": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "node-gyp-build-optional-packages": "5.2.2"
+ },
+ "bin": {
+ "download-msgpackr-prebuilds": "bin/download-prebuilds.js"
+ },
+ "optionalDependencies": {
+ "@msgpackr-extract/msgpackr-extract-darwin-arm64": "3.0.3",
+ "@msgpackr-extract/msgpackr-extract-darwin-x64": "3.0.3",
+ "@msgpackr-extract/msgpackr-extract-linux-arm": "3.0.3",
+ "@msgpackr-extract/msgpackr-extract-linux-arm64": "3.0.3",
+ "@msgpackr-extract/msgpackr-extract-linux-x64": "3.0.3",
+ "@msgpackr-extract/msgpackr-extract-win32-x64": "3.0.3"
+ }
+ },
+ "node_modules/multipasta": {
+ "version": "0.2.7",
+ "resolved": "https://registry.npmmirror.com/multipasta/-/multipasta-0.2.7.tgz",
+ "integrity": "sha512-KPA58d68KgGil15oDqXjkUBEBYc00XvbPj5/X+dyzeo/lWm9Nc25pQRlf1D+gv4OpK7NM0J1odrbu9JNNGvynA==",
+ "license": "MIT"
+ },
+ "node_modules/node-gyp-build-optional-packages": {
+ "version": "5.2.2",
+ "resolved": "https://registry.npmmirror.com/node-gyp-build-optional-packages/-/node-gyp-build-optional-packages-5.2.2.tgz",
+ "integrity": "sha512-s+w+rBWnpTMwSFbaE0UXsRlg7hU4FjekKU4eyAih5T8nJuNZT1nNsskXpxmeqSK9UzkBl6UgRlnKc8hz8IEqOw==",
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "detect-libc": "^2.0.1"
+ },
+ "bin": {
+ "node-gyp-build-optional-packages": "bin.js",
+ "node-gyp-build-optional-packages-optional": "optional.js",
+ "node-gyp-build-optional-packages-test": "build-test.js"
+ }
+ },
"node_modules/path-key": {
"version": "3.1.1",
- "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
+ "resolved": "https://registry.npmmirror.com/path-key/-/path-key-3.1.1.tgz",
"integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
"license": "MIT",
"engines": {
"node": ">=8"
}
},
+ "node_modules/pure-rand": {
+ "version": "8.4.0",
+ "resolved": "https://registry.npmmirror.com/pure-rand/-/pure-rand-8.4.0.tgz",
+ "integrity": "sha512-IoM8YF/jY0hiugFo/wOWqfmarlE6J0wc6fDK1PhftMk7MGhVZl88sZimmqBBFomLOCSmcCCpsfj7wXASCpvK9A==",
+ "funding": [
+ {
+ "type": "individual",
+ "url": "https://github.com/sponsors/dubzzz"
+ },
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/fast-check"
+ }
+ ],
+ "license": "MIT"
+ },
"node_modules/shebang-command": {
"version": "2.0.0",
- "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
+ "resolved": "https://registry.npmmirror.com/shebang-command/-/shebang-command-2.0.0.tgz",
"integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
"license": "MIT",
"dependencies": {
@@ -82,16 +306,38 @@
},
"node_modules/shebang-regex": {
"version": "3.0.0",
- "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
+ "resolved": "https://registry.npmmirror.com/shebang-regex/-/shebang-regex-3.0.0.tgz",
"integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
"license": "MIT",
"engines": {
"node": ">=8"
}
},
+ "node_modules/toml": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmmirror.com/toml/-/toml-4.1.1.tgz",
+ "integrity": "sha512-EBJnVBr3dTXdA89WVFoAIPUqkBjxPMwRqsfuo1r240tKFHXv3zgca4+NJib/h6TyvGF7vOawz0jGuryJCdNHrw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=20"
+ }
+ },
+ "node_modules/uuid": {
+ "version": "13.0.1",
+ "resolved": "https://registry.npmmirror.com/uuid/-/uuid-13.0.1.tgz",
+ "integrity": "sha512-9ezox2roIft6ExBVTVqibSd5dc5/47Sw/uY6b4SjQUT2TzQ0tltNquWA46y4xPQmdZYqvnio22SgWd41M86+jw==",
+ "funding": [
+ "https://github.com/sponsors/broofa",
+ "https://github.com/sponsors/ctavan"
+ ],
+ "license": "MIT",
+ "bin": {
+ "uuid": "dist-node/bin/uuid"
+ }
+ },
"node_modules/which": {
"version": "2.0.2",
- "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
+ "resolved": "https://registry.npmmirror.com/which/-/which-2.0.2.tgz",
"integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
"license": "ISC",
"dependencies": {
@@ -104,6 +350,21 @@
"node": ">= 8"
}
},
+ "node_modules/yaml": {
+ "version": "2.8.4",
+ "resolved": "https://registry.npmmirror.com/yaml/-/yaml-2.8.4.tgz",
+ "integrity": "sha512-ml/JPOj9fOQK8RNnWojA67GbZ0ApXAUlN2UQclwv2eVgTgn7O9gg9o7paZWKMp4g0H3nTLtS9LVzhkpOFIKzog==",
+ "license": "ISC",
+ "bin": {
+ "yaml": "bin.mjs"
+ },
+ "engines": {
+ "node": ">= 14.6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/eemeli"
+ }
+ },
"node_modules/zod": {
"version": "4.1.8",
"license": "MIT",
diff --git a/app/(app)/(tabs)/profile/_layout.tsx b/app/(app)/(tabs)/profile/_layout.tsx
index 78a343b..59c4f68 100644
--- a/app/(app)/(tabs)/profile/_layout.tsx
+++ b/app/(app)/(tabs)/profile/_layout.tsx
@@ -1,49 +1,28 @@
-import { useMemo } from 'react';
import { Stack } from 'expo-router';
-import { useRouter } from 'expo-router';
-
-import { AppBackButton } from '../../../../src/components/common';
-import { useAppColors } from '../../../../src/theme';
export default function ProfileStackLayout() {
- const router = useRouter();
- const colors = useAppColors();
-
- const headerOptions = useMemo(
- () => ({
- headerStyle: { backgroundColor: colors.background.paper },
- headerTintColor: colors.text.primary,
- headerTitleStyle: { fontWeight: '600' as const },
- headerShadowVisible: false,
- headerBackTitle: '',
- }),
- [colors]
- );
-
return (
router.back()} />,
+ headerShown: false,
}}
>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
);
}
diff --git a/app/_layout.tsx b/app/_layout.tsx
index 8d4f537..e854b2b 100644
--- a/app/_layout.tsx
+++ b/app/_layout.tsx
@@ -19,7 +19,7 @@ import {
usePaperThemeFromStore,
useResolvedColorScheme,
} from '../src/theme';
-import { AppBackButton } from '../src/components/common';
+
import AppPromptBar from '../src/components/common/AppPromptBar';
import AppDialogHost from '../src/components/common/AppDialogHost';
import { installAlertOverride } from '@/services/ui';
@@ -232,7 +232,6 @@ function APKUpdateBootstrap() {
function ThemedStack() {
const router = useRouter();
- const colors = useAppColors();
const resolved = useResolvedColorScheme();
return (
@@ -250,49 +249,25 @@ function ThemedStack() {
router.back()} />,
+ headerShown: false,
}}
/>
router.back()} />,
+ headerShown: false,
}}
/>
router.back()} />,
+ headerShown: false,
}}
/>
router.back()} />,
+ headerShown: false,
}}
/>
diff --git a/src/components/common/AppBackButton.tsx b/src/components/common/AppBackButton.tsx
index f1d357f..53ae537 100644
--- a/src/components/common/AppBackButton.tsx
+++ b/src/components/common/AppBackButton.tsx
@@ -50,6 +50,7 @@ const styles = StyleSheet.create({
marginLeft: -12,
marginRight: 0,
padding: 0,
+ backgroundColor: 'transparent',
},
});
diff --git a/src/components/common/SimpleHeader.tsx b/src/components/common/SimpleHeader.tsx
new file mode 100644
index 0000000..902bd9f
--- /dev/null
+++ b/src/components/common/SimpleHeader.tsx
@@ -0,0 +1,55 @@
+import React from 'react';
+import { View, StyleSheet } from 'react-native';
+import { useAppColors, spacing } from '../../theme';
+import { AppBackButton, Text } from './index';
+
+interface SimpleHeaderProps {
+ title: string;
+ onBack: () => void;
+ rightComponent?: React.ReactNode;
+}
+
+export const SimpleHeader: React.FC = ({ title, onBack, rightComponent }) => {
+ const colors = useAppColors();
+
+ return (
+
+
+
+ {title}
+
+ {rightComponent ? (
+
+ {rightComponent}
+
+ ) : (
+
+ )}
+
+ );
+};
+
+const styles = StyleSheet.create({
+ header: {
+ flexDirection: 'row',
+ alignItems: 'center',
+ height: 52,
+ paddingHorizontal: spacing.xs,
+ },
+ title: {
+ flex: 1,
+ fontSize: 17,
+ fontWeight: '600',
+ marginLeft: spacing.xs,
+ },
+ rightContainer: {
+ flexDirection: 'row',
+ alignItems: 'center',
+ },
+ rightPlaceholder: {
+ width: 40,
+ },
+ backButton: {
+ marginLeft: 0,
+ },
+});
diff --git a/src/components/common/index.ts b/src/components/common/index.ts
index 5b0bbc6..5bd7d6f 100644
--- a/src/components/common/index.ts
+++ b/src/components/common/index.ts
@@ -18,6 +18,7 @@ export { default as ResponsiveGrid } from './ResponsiveGrid';
export { default as ResponsiveStack, HStack, VStack } from './ResponsiveStack';
export { default as AdaptiveLayout, SidebarLayout } from './AdaptiveLayout';
export { default as AppBackButton } from './AppBackButton';
+export { SimpleHeader } from './SimpleHeader';
export { default as PagerView } from './PagerView';
// 图片相关组件
diff --git a/src/screens/home/PostDetailScreen.tsx b/src/screens/home/PostDetailScreen.tsx
index c3ca3a3..9b21c17 100644
--- a/src/screens/home/PostDetailScreen.tsx
+++ b/src/screens/home/PostDetailScreen.tsx
@@ -23,8 +23,9 @@ import {
Dimensions,
} from 'react-native';
import { FlashList, ListRenderItem, FlashListRef } from '@shopify/flash-list';
-import { useSafeAreaInsets } from 'react-native-safe-area-context';
+import { SafeAreaView, useSafeAreaInsets } from 'react-native-safe-area-context';
import { useNavigation, useRouter, useLocalSearchParams } from 'expo-router';
+import { StatusBar } from 'expo-status-bar';
import { MaterialCommunityIcons } from '@expo/vector-icons';
import * as ImagePicker from 'expo-image-picker';
import {
@@ -131,6 +132,7 @@ export const PostDetailScreen: React.FC = () => {
postId?: string;
scrollToComments?: string;
}>();
+
const postId = postIdParam || '';
const shouldScrollToComments = scrollParam === '1' || scrollParam === 'true';
@@ -367,58 +369,43 @@ export const PostDetailScreen: React.FC = () => {
}
}, [shouldScrollToComments, isPostInitialLoading, comments?.length]);
- // 动态设置导航头部
- useEffect(() => {
- if (!post?.author) return;
-
- const author = post.author;
- const handleBackPress = () => {
- if (router.canGoBack()) {
- router.back();
- return;
- }
- router.replace(hrefs.hrefHome());
- };
-
- navigation.setOptions({
- // 与页面容器 background.default 一致,并去掉原生 header 底部分隔阴影,避免「一条线」
- headerStyle: { backgroundColor: colors.background.default },
- headerShadowVisible: false,
- headerBackVisible: false,
- headerTitleAlign: 'left',
- headerLeft: () => (
-
- ),
- headerTitle: () => (
+ const handleBackPress = useCallback(() => {
+ if (router.canGoBack()) {
+ router.back();
+ return;
+ }
+ router.replace(hrefs.hrefHome());
+ }, [router]);
+
+ const renderCustomHeader = () => (
+
+
+ {post?.author ? (
handleUserPress(author.id)}
+ onPress={() => handleUserPress(post.author!.id)}
style={styles.headerAvatarWrapper}
>
-
+
- handleUserPress(author.id)}>
+ handleUserPress(post.author!.id)}>
- {author.nickname && author.nickname.length > 10
- ? `${author.nickname.slice(0, 10)}...`
- : author.nickname}
+ {post.author.nickname && post.author.nickname.length > 10
+ ? `${post.author.nickname.slice(0, 10)}...`
+ : post.author.nickname}
- ),
- headerRight: () => (
-
- {renderFollowButton()}
-
- ),
- });
- }, [post?.author, isFollowing, isFollowingMe, isFollowLoading, navigation, colors.background.default, styles]);
+ ) : (
+
+ )}
+
+ {renderFollowButton()}
+
+
+ );
// 监听键盘事件
useEffect(() => {
@@ -1076,12 +1063,15 @@ export const PostDetailScreen: React.FC = () => {
}
};
- // 渲染关注按钮
- const renderFollowButton = () => {
- if (!post?.author?.id || currentUser?.id === post.author.id) return null;
-
+ // 渲染关注按钮(始终返回同尺寸占位,避免 header 右侧宽度跳动)
+ const renderFollowButton = useCallback(() => {
+ const shouldShow = post?.author?.id && currentUser?.id !== post.author.id;
+ if (!shouldShow) {
+ return ;
+ }
+
const config = getFollowButtonConfig();
-
+
return (
{
);
- };
+ }, [post?.author?.id, currentUser?.id, isFollowing, isFollowingMe, isFollowLoading, styles]);
// 使用 useMemo 缓存图片数据,避免输入时重新创建数组导致图片重新加载
const postImages = useMemo(() => {
@@ -1712,7 +1702,9 @@ export const PostDetailScreen: React.FC = () => {
// 桌面端双栏布局
if (useDualColumnLayout) {
return (
-
+
+
+ {renderCustomHeader()}
{
onClose={() => setShowImageModal(false)}
enableSave
/>
-
+
);
}
// 移动端单栏布局
return (
-
+
+
+ {renderCustomHeader()}
{
}
}}
/>
-
+
);
};
@@ -1909,6 +1903,16 @@ function createPostDetailStyles(colors: AppColors) {
flex: 1,
backgroundColor: colors.background.default,
},
+ customHeader: {
+ flexDirection: 'row',
+ alignItems: 'center',
+ backgroundColor: colors.background.default,
+ height: 52,
+ paddingRight: spacing.sm,
+ },
+ headerPlaceholder: {
+ flex: 1,
+ },
// Header 样式
headerContainer: {
flexDirection: 'row',
@@ -1932,10 +1936,12 @@ function createPostDetailStyles(colors: AppColors) {
flexDirection: 'row',
alignItems: 'center',
marginRight: spacing.sm,
+ backgroundColor: 'transparent',
},
headerBackButton: {
marginLeft: 0,
marginRight: 0,
+ backgroundColor: 'transparent',
},
// 帖子容器
postContainer: {
@@ -1950,6 +1956,7 @@ function createPostDetailStyles(colors: AppColors) {
minWidth: 64,
alignItems: 'center',
justifyContent: 'center',
+ backgroundColor: 'transparent',
},
followButtonPrimary: {
backgroundColor: colors.primary.main,
@@ -1967,6 +1974,12 @@ function createPostDetailStyles(colors: AppColors) {
followButtonLoading: {
opacity: 0.7,
},
+ followButtonPlaceholder: {
+ minWidth: 64,
+ paddingHorizontal: spacing.md,
+ paddingVertical: 4,
+ backgroundColor: 'transparent',
+ },
followButtonText: {
fontSize: fontSizes.sm,
fontWeight: '600',
diff --git a/src/screens/profile/AboutScreen.tsx b/src/screens/profile/AboutScreen.tsx
index f6a9ef2..40b18d6 100644
--- a/src/screens/profile/AboutScreen.tsx
+++ b/src/screens/profile/AboutScreen.tsx
@@ -18,6 +18,7 @@ import {
import { SafeAreaView, useSafeAreaInsets } from 'react-native-safe-area-context';
import { MaterialCommunityIcons } from '@expo/vector-icons';
import Constants from 'expo-constants';
+import { StatusBar } from 'expo-status-bar';
import { useRouter } from 'expo-router';
import {
useAppColors,
@@ -26,7 +27,7 @@ import {
borderRadius,
type AppColors,
} from '../../theme';
-import { Text } from '../../components/common';
+import { Text, SimpleHeader } from '../../components/common';
import { useResponsive, useResponsiveSpacing } from '../../hooks';
import { checkForAPKUpdate, type VersionCheckResult } from '@/services/platform';
import * as hrefs from '../../navigation/hrefs';
@@ -517,7 +518,9 @@ export const AboutScreen: React.FC = () => {
);
return (
-
+
+
+ router.back()} />
{
if (loading) {
return (
-
+
@@ -284,7 +285,9 @@ export const AccountDeletionScreen: React.FC = () => {
}
return (
-
+
+
+ router.back()} />
{status?.is_pending_deletion ? (
diff --git a/src/screens/profile/AccountSecurityScreen.tsx b/src/screens/profile/AccountSecurityScreen.tsx
index 20555a7..11909f4 100644
--- a/src/screens/profile/AccountSecurityScreen.tsx
+++ b/src/screens/profile/AccountSecurityScreen.tsx
@@ -7,10 +7,12 @@ import {
ActivityIndicator,
ScrollView,
} from 'react-native';
+import { StatusBar } from 'expo-status-bar';
+import { useRouter } from 'expo-router';
import { SafeAreaView, useSafeAreaInsets } from 'react-native-safe-area-context';
import { MaterialCommunityIcons } from '@expo/vector-icons';
import { spacing, fontSizes, borderRadius, useAppColors, type AppColors } from '../../theme';
-import { Text } from '../../components/common';
+import { Text, SimpleHeader } from '../../components/common';
import { useResponsive, useResponsiveSpacing } from '../../hooks';
// 内容最大宽度
@@ -21,6 +23,7 @@ import { showPrompt } from '@/services/ui';
import { useAuthStore } from '../../stores';
export const AccountSecurityScreen: React.FC = () => {
+ const router = useRouter();
const colors = useAppColors();
const styles = useMemo(() => createAccountSecurityStyles(colors), [colors]);
const { isWideScreen, isMobile } = useResponsive();
@@ -202,7 +205,9 @@ export const AccountSecurityScreen: React.FC = () => {
const responsivePadding = useResponsiveSpacing({ xs: 8, sm: 12, md: 16, lg: 24, xl: 32 });
return (
-
+
+
+ router.back()} />
{/* 邮箱验证分组 */}
diff --git a/src/screens/profile/BlockedUsersScreen.tsx b/src/screens/profile/BlockedUsersScreen.tsx
index 2f05eb1..5226065 100644
--- a/src/screens/profile/BlockedUsersScreen.tsx
+++ b/src/screens/profile/BlockedUsersScreen.tsx
@@ -10,7 +10,8 @@ import {
} from 'react-native';
import { SafeAreaView, useSafeAreaInsets } from 'react-native-safe-area-context';
import { useRouter } from 'expo-router';
-import { Avatar, Button, EmptyState, ResponsiveContainer, Text } from '../../components/common';
+import { StatusBar } from 'expo-status-bar';
+import { Avatar, Button, EmptyState, ResponsiveContainer, SimpleHeader, Text } from '../../components/common';
import { authService } from '../../services';
import { spacing, borderRadius, shadows, useAppColors, type AppColors } from '../../theme';
import { User } from '../../types';
@@ -140,7 +141,8 @@ export const BlockedUsersScreen: React.FC = () => {
if (loading) {
return (
-
+
+
@@ -149,7 +151,9 @@ export const BlockedUsersScreen: React.FC = () => {
}
return (
-
+
+
+ router.back()} />
{
+ const router = useRouter();
const colors = useAppColors();
const styles = useMemo(() => createStyles(colors), [colors]);
const responsivePadding = useResponsiveSpacing({ xs: 8, sm: 12, md: 16, lg: 24, xl: 32 });
@@ -379,7 +382,9 @@ export const ChatSettingsScreen: React.FC = () => {
);
return (
-
+
+
+ router.back()} />
{
+ const router = useRouter();
const colors = useAppColors();
const styles = useMemo(() => createDataStorageStyles(colors), [colors]);
const { isMobile } = useResponsive();
@@ -372,7 +375,9 @@ export const DataStorageScreen: React.FC = () => {
};
return (
-
+
+
+ router.back()} />
{
const colors = useAppColors();
const styles = useMemo(() => createEditProfileStyles(colors), [colors]);
const navigation = useNavigation();
+ const router = useRouter();
const { currentUser, updateUser } = useAuthStore();
const { isWideScreen, isMobile, width } = useResponsive();
const responsivePadding = useResponsiveSpacing({ xs: 0, sm: 0, md: 0, lg: 24, xl: 32 });
@@ -596,7 +599,9 @@ export const EditProfileScreen: React.FC = () => {
);
return (
-
+
+
+ router.back()} />
{
+ const router = useRouter();
const colors = useAppColors();
const styles = useMemo(() => createNotificationSettingsStyles(colors), [colors]);
const [vibrationEnabled, setVibrationEnabledState] = useState(true);
@@ -316,7 +319,9 @@ export const NotificationSettingsScreen: React.FC = () => {
const responsivePadding = useResponsiveSpacing({ xs: 8, sm: 12, md: 16, lg: 24, xl: 32 });
return (
-
+
+
+ router.back()} />
{renderContent()}
diff --git a/src/screens/profile/PrivacyPolicyScreen.tsx b/src/screens/profile/PrivacyPolicyScreen.tsx
index 5e83d8d..97aa167 100644
--- a/src/screens/profile/PrivacyPolicyScreen.tsx
+++ b/src/screens/profile/PrivacyPolicyScreen.tsx
@@ -10,13 +10,15 @@ import {
StyleSheet,
ScrollView,
} from 'react-native';
+import { StatusBar } from 'expo-status-bar';
+import { useRouter } from 'expo-router';
import { SafeAreaView, useSafeAreaInsets } from 'react-native-safe-area-context';
import {
useAppColors,
spacing,
type AppColors,
} from '../../theme';
-import { Text } from '../../components/common';
+import { Text, SimpleHeader } from '../../components/common';
import { useResponsive, useResponsiveSpacing } from '../../hooks';
// 内容最大宽度
@@ -278,6 +280,7 @@ export const PrivacyPolicyScreen: React.FC = () => {
const colors = useAppColors();
const styles = useMemo(() => createPrivacyStyles(colors), [colors]);
const insets = useSafeAreaInsets();
+ const router = useRouter();
const { isMobile } = useResponsive();
const responsivePadding = useResponsiveSpacing({ xs: 20, sm: 24, md: 28, lg: 32, xl: 40 });
@@ -285,7 +288,9 @@ export const PrivacyPolicyScreen: React.FC = () => {
const scrollBottomInset = isMobile ? 64 + 24 + insets.bottom + spacing.md : spacing.lg;
return (
-
+
+
+ router.back()} />
{
if (loading) {
return (
-
+
+
@@ -209,7 +211,9 @@ export const PrivacySettingsScreen: React.FC = () => {
}
return (
-
+
+
+ router.back()} />
diff --git a/src/screens/profile/SettingsScreen.tsx b/src/screens/profile/SettingsScreen.tsx
index 805209d..2075247 100644
--- a/src/screens/profile/SettingsScreen.tsx
+++ b/src/screens/profile/SettingsScreen.tsx
@@ -13,6 +13,7 @@ import {
ScrollView,
} from 'react-native';
import { SafeAreaView } from 'react-native-safe-area-context';
+import { StatusBar } from 'expo-status-bar';
import { useRouter } from 'expo-router';
import { MaterialCommunityIcons } from '@expo/vector-icons';
import Constants from 'expo-constants';
@@ -26,7 +27,7 @@ import {
type AppColors,
} from '../../theme';
import { useAuthStore } from '../../stores';
-import { Text } from '../../components/common';
+import { Text, SimpleHeader } from '../../components/common';
import { useResponsive, useResponsiveSpacing } from '../../hooks';
import { useSafeAreaInsets } from 'react-native-safe-area-context';
import * as hrefs from '../../navigation/hrefs';
@@ -365,7 +366,9 @@ export const SettingsScreen: React.FC = () => {
);
return (
-
+
+
+ router.back()} />
{renderContent()}
diff --git a/src/screens/profile/TermsOfServiceScreen.tsx b/src/screens/profile/TermsOfServiceScreen.tsx
index 50940ab..1b7ea04 100644
--- a/src/screens/profile/TermsOfServiceScreen.tsx
+++ b/src/screens/profile/TermsOfServiceScreen.tsx
@@ -10,13 +10,15 @@ import {
StyleSheet,
ScrollView,
} from 'react-native';
+import { StatusBar } from 'expo-status-bar';
import { SafeAreaView, useSafeAreaInsets } from 'react-native-safe-area-context';
+import { useRouter } from 'expo-router';
import {
useAppColors,
spacing,
type AppColors,
} from '../../theme';
-import { Text } from '../../components/common';
+import { Text, SimpleHeader } from '../../components/common';
import { useResponsive, useResponsiveSpacing } from '../../hooks';
// 内容最大宽度
@@ -213,12 +215,15 @@ export const TermsOfServiceScreen: React.FC = () => {
const insets = useSafeAreaInsets();
const { isMobile } = useResponsive();
const responsivePadding = useResponsiveSpacing({ xs: 20, sm: 24, md: 28, lg: 32, xl: 40 });
+ const router = useRouter();
// 底部间距,避免被 TabBar 遮挡
const scrollBottomInset = isMobile ? 64 + 24 + insets.bottom + spacing.md : spacing.lg;
return (
-
+
+
+ router.back()} />
{
const { userId: userIdParam } = useLocalSearchParams<{ userId?: string }>();
+ const router = useRouter();
const userId = userIdParam || '';
const currentUser = useCurrentUser();
const isSelfProfile = !!currentUser?.id && currentUser.id === userId;
-
+
return (
-
+
+ router.back()} />
+
+
);
};
diff --git a/src/screens/profile/VerificationSettingsScreen.tsx b/src/screens/profile/VerificationSettingsScreen.tsx
index fe6476e..91924f6 100644
--- a/src/screens/profile/VerificationSettingsScreen.tsx
+++ b/src/screens/profile/VerificationSettingsScreen.tsx
@@ -14,8 +14,10 @@ import {
Alert,
ActivityIndicator,
} from 'react-native';
+import { StatusBar } from 'expo-status-bar';
import { SafeAreaView } from 'react-native-safe-area-context';
import { useRouter } from 'expo-router';
+import { SimpleHeader } from '../../components/common';
import { MaterialCommunityIcons } from '@expo/vector-icons';
import { useAppColors, type AppColors } from '../../theme';
import {
@@ -91,7 +93,9 @@ export const VerificationSettingsScreen: React.FC = () => {
if (loading && !status) {
return (
-
+
+
+ router.back()} />
@@ -104,7 +108,9 @@ export const VerificationSettingsScreen: React.FC = () => {
const identityText = IDENTITY_TEXT[status?.identity || 'general'];
return (
-
+
+
+ router.back()} />