Skip to content
Open
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
53 changes: 26 additions & 27 deletions src/components/button/index.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
import React, { FC } from 'react';
import { ActivityIndicator, StyleSheet, Text, View } from 'react-native';
import { RectButton } from 'react-native-gesture-handler';
import { FC } from 'react';
import { StyleSheet, TouchableNativeFeedback, View } from 'react-native';
import { Button as RNEButton } from 'react-native-elements';
Comment on lines +1 to +3

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# 检查 package.json 中的 RNEUI 依赖,确认包名
cat package.json | grep -E "rneui|react-native-elements"

Repository: Muxi-X/ccnubox_rn

Length of output: 213


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# 仅查看该文件的相关片段
wc -l src/components/button/index.tsx
cat -n src/components/button/index.tsx | sed -n '1,120p'

Repository: Muxi-X/ccnubox_rn

Length of output: 2242


🏁 Script executed:

#!/bin/bash
set -euo pipefail
wc -l src/components/button/index.tsx
cat -n src/components/button/index.tsx | sed -n '1,160p'

Repository: Muxi-X/ccnubox_rn

Length of output: 2242


改为从 @rneui/themed 导入 Button
当前依赖里只有 @rneui/base / @rneui/themed,继续使用 react-native-elements 会导致模块解析失败。

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/button/index.tsx` around lines 1 - 3, Update the Button import
in the button component to use Button from `@rneui/themed` instead of
react-native-elements, while preserving the existing RNEButton alias and other
imports.


import { ButtonProps } from '@/components/button/type';

import useVisualScheme from '@/store/visualScheme';

import { commonColors } from '@/styles/common';

const Button: FC<ButtonProps> = ({
Expand All @@ -16,29 +14,31 @@ const Button: FC<ButtonProps> = ({
children,
}) => {
const currentStyle = useVisualScheme(state => state.currentStyle);
const btnGlobalStyle = currentStyle?.button_style ?? {};
const textGlobalStyle = currentStyle?.button_text_style ?? {};
const ripplePurple = commonColors.lightPurple ?? '#B8A6F5';

return (
<RectButton
rippleColor={commonColors.lightPurple}
activeOpacity={0.6}
style={[
styles.rect_button,
currentStyle?.button_style,
{ opacity: isLoading ? 0.4 : 1 },
style,
]}
onPress={(...props) => {
if (!isLoading) onPress?.(...props);
}}
<TouchableNativeFeedback
background={TouchableNativeFeedback.Ripple(ripplePurple, false)}
disabled={isLoading}
onPress={() => onPress?.(true)}
>
<View accessible accessibilityRole="button" style={[styles.button]}>
{isLoading && (
<ActivityIndicator color="#fff" style={{ marginRight: 5 }} /> // 加载指示器
)}
<Text style={[currentStyle?.button_text_style, text_style]}>
{children}
</Text>
<View
style={[styles.rect_button, { opacity: isLoading ? 0.4 : 1 }, style]}
>
<RNEButton
activeOpacity={1}
containerStyle={[btnGlobalStyle]}
buttonStyle={styles.button}
titleStyle={[textGlobalStyle, text_style]}
loading={isLoading}
loadingProps={{ color: '#fff', style: { marginRight: 5 } }}
title={children}
accessibilityRole="button"
/>
</View>
</RectButton>
</TouchableNativeFeedback>
Comment on lines +19 to +41

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🔴 Critical | 🏗️ Heavy lift

修复 iOS 平台闪退及嵌套触摸组件导致的点击失效问题

当前实现存在以下三个严重的运行时和交互风险:

  1. 点击失效RNEButton 内部默认封装了触摸反馈组件(如 TouchableOpacity)。在 React Native 中,最深层的触摸组件会拦截事件。由于 onPress 绑定在外层,内层的 RNEButton 会拦截点击但无响应,导致按钮彻底无法触发 onPress
  2. iOS 闪退:无条件调用了 TouchableNativeFeedback.Ripple,该方法在 iOS 平台上为 undefined,运行到此行会导致应用直接崩溃。
  3. iOS 缺少交互反馈:如果强制设置 activeOpacity={1},则会导致 iOS 端在使用原生的 TouchableOpacity 时完全失去点击的透明度反馈。

建议移除外层的 TouchableNativeFeedback,将 onPressdisabled 等交互属性交由 RNEButton 直接接管。通过判断 Platform.OS,仅在 Android 平台启用原生的水波纹属性(将其传给 background 即可传递至底层的反馈组件),同时移除 activeOpacity={1} 以恢复 iOS 的默认按压效果。

根据提供的 relevant code snippets (src/store/visualScheme.ts),项目中包含多平台逻辑 (Platform.OS === 'ios'),因此必须妥善处理 iOS 下特有 API 的兼容性。

🐛 建议的修复方案
   const ripplePurple = commonColors.lightPurple ?? '`#B8A6F5`';
+  
+  // 仅在 Android 上使用 TouchableNativeFeedback.Ripple,避免 iOS 闪退
+  const background = Platform.OS === 'android' 
+    ? TouchableNativeFeedback.Ripple(ripplePurple, false) 
+    : undefined;

   return (
-    <TouchableNativeFeedback
-      background={TouchableNativeFeedback.Ripple(ripplePurple, false)}
-      disabled={isLoading}
-      onPress={() => onPress?.(true)}
-    >
-      <View
-        style={[styles.rect_button, { opacity: isLoading ? 0.4 : 1 }, style]}
-      >
-        <RNEButton
-          activeOpacity={1}
-          containerStyle={[btnGlobalStyle]}
-          buttonStyle={styles.button}
-          titleStyle={[textGlobalStyle, text_style]}
-          loading={isLoading}
-          loadingProps={{ color: '`#fff`', style: { marginRight: 5 } }}
-          title={children}
-          accessibilityRole="button"
-        />
-      </View>
-    </TouchableNativeFeedback>
+    <View style={[styles.rect_button, { opacity: isLoading ? 0.4 : 1 }, style]}>
+      <RNEButton
+        containerStyle={[btnGlobalStyle]}
+        buttonStyle={styles.button}
+        titleStyle={[textGlobalStyle, text_style]}
+        loading={isLoading}
+        loadingProps={{ color: '`#fff`', style: { marginRight: 5 } }}
+        title={children}
+        accessibilityRole="button"
+        onPress={() => onPress?.(true)}
+        disabled={isLoading}
+        background={background}
+      />
+    </View>
   );
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const ripplePurple = commonColors.lightPurple ?? '#B8A6F5';
return (
<RectButton
rippleColor={commonColors.lightPurple}
activeOpacity={0.6}
style={[
styles.rect_button,
currentStyle?.button_style,
{ opacity: isLoading ? 0.4 : 1 },
style,
]}
onPress={(...props) => {
if (!isLoading) onPress?.(...props);
}}
<TouchableNativeFeedback
background={TouchableNativeFeedback.Ripple(ripplePurple, false)}
disabled={isLoading}
onPress={() => onPress?.(true)}
>
<View accessible accessibilityRole="button" style={[styles.button]}>
{isLoading && (
<ActivityIndicator color="#fff" style={{ marginRight: 5 }} /> // 加载指示器
)}
<Text style={[currentStyle?.button_text_style, text_style]}>
{children}
</Text>
<View
style={[styles.rect_button, { opacity: isLoading ? 0.4 : 1 }, style]}
>
<RNEButton
activeOpacity={1}
containerStyle={[btnGlobalStyle]}
buttonStyle={styles.button}
titleStyle={[textGlobalStyle, text_style]}
loading={isLoading}
loadingProps={{ color: '#fff', style: { marginRight: 5 } }}
title={children}
accessibilityRole="button"
/>
</View>
</RectButton>
</TouchableNativeFeedback>
const ripplePurple = commonColors.lightPurple ?? '`#B8A6F5`';
// 仅在 Android 上使用 TouchableNativeFeedback.Ripple,避免 iOS 闪退
const background = Platform.OS === 'android'
? TouchableNativeFeedback.Ripple(ripplePurple, false)
: undefined;
return (
<View style={[styles.rect_button, { opacity: isLoading ? 0.4 : 1 }, style]}>
<RNEButton
containerStyle={[btnGlobalStyle]}
buttonStyle={styles.button}
titleStyle={[textGlobalStyle, text_style]}
loading={isLoading}
loadingProps={{ color: '`#fff`', style: { marginRight: 5 } }}
title={children}
accessibilityRole="button"
onPress={() => onPress?.(true)}
disabled={isLoading}
background={background}
/>
</View>
);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/button/index.tsx` around lines 19 - 41, Remove the outer
TouchableNativeFeedback wrapper and move the onPress and disabled behavior onto
RNEButton so its internal touch handler receives clicks. In the RNEButton
configuration, only provide the Ripple background when Platform.OS is Android,
avoid calling TouchableNativeFeedback.Ripple on iOS, and remove
activeOpacity={1} so iOS retains default press feedback.

);
};

Expand All @@ -49,10 +49,9 @@ const styles = StyleSheet.create({
overflow: 'hidden',
},
button: {
flex: 1,
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'center',
flexDirection: 'row',
borderRadius: 6,
},
});
Expand Down
Loading