优化工作流,添加app-icon

This commit is contained in:
Kevin
2026-03-23 10:25:51 +08:00
parent 584fb9ffe9
commit f8b3de6ff8
16 changed files with 209 additions and 42 deletions

View File

@@ -116,7 +116,7 @@ export default ({ config }: ConfigContext): ExpoConfig => {
userInterfaceStyle: 'automatic',
ios: {
...config?.ios,
icon: './assets/expo.icon',
icon: './assets/images/icon.png',
bundleIdentifier: 'com.anonymous.app-expo',
config: {
usesNonExemptEncryption: false,
@@ -140,7 +140,6 @@ export default ({ config }: ConfigContext): ExpoConfig => {
adaptiveIcon: {
backgroundColor: '#E6F4FE',
foregroundImage: './assets/images/android-icon-foreground.png',
backgroundImage: './assets/images/android-icon-background.png',
monochromeImage: './assets/images/android-icon-monochrome.png',
},
predictiveBackGestureEnabled: false,
@@ -166,11 +165,11 @@ export default ({ config }: ConfigContext): ExpoConfig => {
[
'expo-splash-screen',
{
backgroundColor: '#208AEF',
android: {
image: './assets/images/splash-icon.png',
imageWidth: 76,
},
// 与 android.adaptiveIcon.backgroundColor、品牌浅紫一致见 scripts/generate-app-icon.sh
backgroundColor: '#E6F4FE',
image: './assets/images/splash-icon.png',
resizeMode: 'contain',
imageWidth: 200,
},
],
[

Binary file not shown.

Before

Width:  |  Height:  |  Size: 77 KiB

After

Width:  |  Height:  |  Size: 110 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.0 KiB

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 780 KiB

After

Width:  |  Height:  |  Size: 80 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

View File

@@ -0,0 +1,48 @@
#!/usr/bin/env bash
# 一次性:用 ImageMagick 7+magick从 assets/life-echo-logo.jpg 生成各平台 PNG。
# 依赖brew install imagemagick
# 用法:在 app-expo 目录执行 ./scripts/generate-app-icon.sh
set -euo pipefail
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
SRC="$ROOT/assets/life-echo-logo.jpg"
OUT="$ROOT/assets/images"
# 与 Android adaptiveIcon.backgroundColor、开屏底色一致新 logo 浅紫系)
BRAND_BG="#E6F4FE"
TMP="$(mktemp -d)"
trap 'rm -rf "$TMP"' EXIT
if [[ ! -f "$SRC" ]]; then
echo "missing: $SRC" >&2
exit 1
fi
if ! command -v magick >/dev/null; then
echo "need: magick (ImageMagick 7)" >&2
exit 1
fi
mkdir -p "$OUT"
# 近白背景 → 透明JPG 白底)
magick "$SRC" -fuzz 12% -transparent white PNG32:"$TMP/fg.png"
# Android 自适应前景透明底1024内容约 78% 安全区)
magick "$TMP/fg.png" -resize '800x800>' -background none -gravity center -extent 1024x1024 \
PNG32:"$OUT/android-icon-foreground.png"
# 通用 / iOS 主图标(实色底)
magick -size 1024x1024 "xc:${BRAND_BG}" \( "$TMP/fg.png" -resize '800x800>' \) -gravity center -compose over -composite \
PNG32:"$OUT/icon.png"
# Android 13+ 单色层(白/透明)
magick "$OUT/android-icon-foreground.png" -alpha extract -fill white -colorize 100 -background none -alpha shape \
PNG32:"$OUT/android-icon-monochrome.png"
# 开屏图:仅透明 logo底色由 expo-splash-screen backgroundColor 填充)
magick "$SRC" -fuzz 12% -transparent white -resize '400x400>' PNG32:"$OUT/splash-icon.png"
magick "$OUT/icon.png" -resize 48x48 PNG32:"$OUT/favicon.png"
echo "OK → $OUT/icon.png, android-icon-foreground.png, android-icon-monochrome.png, splash-icon.png, favicon.png"

View File

@@ -501,7 +501,6 @@ function ChatInputBar({
styles.iconButton,
pressed && styles.iconButtonPressed,
]}
disabled={disabled && !isRecording}
accessibilityLabel={
inputMode === 'text' ? switchToVoiceLabel : switchToTextLabel
}
@@ -510,11 +509,7 @@ function ChatInputBar({
<Icon
as={inputMode === 'text' ? Mic : Type}
size={22}
color={
disabled && !isRecording
? 'rgba(141, 140, 144, 0.56)'
: CHAT_COLORS.onSurfaceVariant
}
color={CHAT_COLORS.onSurfaceVariant}
/>
</Pressable>
{/* 中间:文字输入 或 语音录制按钮 */}
@@ -531,7 +526,7 @@ function ChatInputBar({
scrollEnabled
textAlignVertical="top"
maxLength={2000}
editable={!disabled}
editable
onContentSizeChange={onInputContentSizeChange}
onSubmitEditing={onSend}
returnKeyType="send"
@@ -715,6 +710,15 @@ export default function ConversationScreen() {
const handleSend = () => {
const text = input.trim();
if (!text) return;
if (connectionState !== 'connected') {
Alert.alert(
t('chatUnavailableTitle'),
connectionState === 'connecting'
? t('chatUnavailableConnecting')
: t('chatUnavailableDisconnected'),
);
return;
}
sendText(text);
setInput('');
setInputResetKey((k) => k + 1);
@@ -726,6 +730,12 @@ export default function ConversationScreen() {
: connectionState === 'connecting'
? t('connectionConnecting')
: t('connectionDisconnected');
const showConnectionBadge = __DEV__;
const showConnectionNotice = connectionState !== 'connected';
const connectionNoticeText =
connectionState === 'connecting'
? t('chatUnavailableConnecting')
: t('chatUnavailableDisconnected');
/** iOS用键盘高度直接顶起根布局替代 KAV避免与 safe area 叠出缝,见 RN #52626 */
const keyboardLift =
@@ -744,22 +754,25 @@ export default function ConversationScreen() {
title={
<View style={styles.headerTitleBlock}>
<Text style={styles.headerTitle}>{tApp('name')}</Text>
<View
style={[
styles.statusBadge,
connectionState === 'connected' && styles.statusBadgeConnected,
]}
>
<Text
{showConnectionBadge ? (
<View
style={[
styles.statusBadgeText,
styles.statusBadge,
connectionState === 'connected' &&
styles.statusBadgeTextConnected,
styles.statusBadgeConnected,
]}
>
{connectionLabel}
</Text>
</View>
<Text
style={[
styles.statusBadgeText,
connectionState === 'connected' &&
styles.statusBadgeTextConnected,
]}
>
{connectionLabel}
</Text>
</View>
) : null}
</View>
}
backAccessibilityLabel={t('chatTitle')}
@@ -810,6 +823,16 @@ export default function ConversationScreen() {
},
]}
>
{showConnectionNotice ? (
<View style={styles.connectionNotice}>
<Text style={styles.connectionNoticeTitle}>
{t('chatUnavailableTitle')}
</Text>
<Text style={styles.connectionNoticeText}>
{connectionNoticeText}
</Text>
</View>
) : null}
<ChatInputBar
value={input}
onChangeText={setInput}
@@ -1028,6 +1051,28 @@ const styles = StyleSheet.create({
shadowRadius: 12,
elevation: 8,
},
connectionNotice: {
marginHorizontal: 14,
marginTop: 14,
marginBottom: 4,
paddingHorizontal: 12,
paddingVertical: 10,
borderRadius: 14,
backgroundColor: 'rgba(186, 26, 26, 0.08)',
borderWidth: 1,
borderColor: 'rgba(186, 26, 26, 0.14)',
},
connectionNoticeTitle: {
fontSize: 13,
fontWeight: '700',
color: CHAT_COLORS.errorRed,
marginBottom: 2,
},
connectionNoticeText: {
fontSize: 13,
lineHeight: 18,
color: CHAT_COLORS.onSurface,
},
inputBar: {
flexDirection: 'row',
alignItems: 'center',

View File

@@ -66,6 +66,9 @@ interface Resources {
cancel: 'Cancel';
cancelRecording: 'Cancel recording';
chatTitle: 'Conversation';
chatUnavailableConnecting: 'Reconnecting now. You can keep typing and send once the connection is back.';
chatUnavailableDisconnected: 'Connection lost. You can keep typing and send after reconnecting.';
chatUnavailableTitle: 'Chat unavailable';
confirm: 'OK';
confirmDeleteConversation: 'Are you sure you want to delete this conversation? It cannot be recovered.';
connectionConnected: 'Connected';

View File

@@ -1,6 +1,9 @@
{
"confirmDeleteConversation": "Are you sure you want to delete this conversation? It cannot be recovered.",
"createError": "Unable to create conversation. Please check your network and try again.",
"chatUnavailableTitle": "Chat unavailable",
"chatUnavailableConnecting": "Reconnecting now. You can keep typing and send once the connection is back.",
"chatUnavailableDisconnected": "Connection lost. You can keep typing and send after reconnecting.",
"confirm": "OK",
"cancel": "Cancel",
"delete": "Delete",

View File

@@ -1,6 +1,9 @@
{
"confirmDeleteConversation": "确定要删除此对话吗?删除后无法恢复。",
"createError": "无法创建对话,请检查网络连接或稍后重试",
"chatUnavailableTitle": "聊天暂不可用",
"chatUnavailableConnecting": "正在重新连接。你仍可继续输入,恢复后再发送。",
"chatUnavailableDisconnected": "当前连接已断开。你仍可先输入,连接恢复后再发送。",
"confirm": "知道了",
"cancel": "取消",
"delete": "删除",