fix(PostImages, CreatePostScreen): adjust image gap for improved layout consistency
Some checks failed
Frontend CI / build-and-push-web (push) Successful in 9m17s
Frontend CI / ota-android (push) Successful in 11m48s
Frontend CI / build-android-apk (push) Successful in 1h12m38s
Frontend CI / ota-android (pull_request) Has been skipped
Frontend CI / build-and-push-web (pull_request) Failing after 37s
Frontend CI / build-android-apk (pull_request) Has been cancelled
Some checks failed
Frontend CI / build-and-push-web (push) Successful in 9m17s
Frontend CI / ota-android (push) Successful in 11m48s
Frontend CI / build-android-apk (push) Successful in 1h12m38s
Frontend CI / ota-android (pull_request) Has been skipped
Frontend CI / build-and-push-web (pull_request) Failing after 37s
Frontend CI / build-android-apk (pull_request) Has been cancelled
- Reduced image gap in PostImages and CreatePostScreen components from 12 to 4 (desktop) and 8 to 2 (mobile) for better spacing. - Updated ImageGrid component to modify grid item widths for enhanced layout. - Refactored PostRepository to improve local caching logic, ensuring non-blocking UI updates during cache writes. - Introduced saveConversationsWithRelatedCache function to streamline conversation, user, and group data saving in the database.
This commit is contained in:
@@ -16,7 +16,7 @@ const PostImages: React.FC<PostImagesProps> = ({ images, displayMode, onImagePre
|
|||||||
if (!images || images.length === 0) return null;
|
if (!images || images.length === 0) return null;
|
||||||
|
|
||||||
// 计算图片间距和圆角
|
// 计算图片间距和圆角
|
||||||
const imageGap = isDesktop ? 12 : 8;
|
const imageGap = isDesktop ? 4 : 2;
|
||||||
const imageBorderRadius = isDesktop ? borderRadius.xl : borderRadius.md;
|
const imageBorderRadius = isDesktop ? borderRadius.xl : borderRadius.md;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -132,10 +132,10 @@ function createImageGridStyles(colors: AppColors) {
|
|||||||
aspectRatio: 1,
|
aspectRatio: 1,
|
||||||
},
|
},
|
||||||
gridItem2: {
|
gridItem2: {
|
||||||
width: '48%',
|
width: '49%',
|
||||||
},
|
},
|
||||||
gridItem3: {
|
gridItem3: {
|
||||||
width: '31%',
|
width: '32.5%',
|
||||||
},
|
},
|
||||||
masonryContainer: {
|
masonryContainer: {
|
||||||
flexDirection: 'row',
|
flexDirection: 'row',
|
||||||
|
|||||||
@@ -265,10 +265,13 @@ export class PostRepository implements IPostRepository {
|
|||||||
const posts = (response.list || []).map(p => this.mapToPost(p));
|
const posts = (response.list || []).map(p => this.mapToPost(p));
|
||||||
|
|
||||||
// 缓存帖子
|
// 缓存帖子
|
||||||
posts.forEach(post => {
|
for (const post of posts) {
|
||||||
this.saveToMemoryCache(post);
|
this.saveToMemoryCache(post);
|
||||||
this.saveToLocalCache(post);
|
// 不等待本地缓存写入完成,避免阻塞 UI
|
||||||
|
this.saveToLocalCache(post).catch(err => {
|
||||||
|
console.warn('[PostRepository] 缓存帖子失败:', post.id, err);
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// 计算 hasMore:优先使用 has_more,否则通过 page/total_pages 计算
|
// 计算 hasMore:优先使用 has_more,否则通过 page/total_pages 计算
|
||||||
let hasMore = response.has_more;
|
let hasMore = response.has_more;
|
||||||
@@ -338,10 +341,12 @@ export class PostRepository implements IPostRepository {
|
|||||||
const posts = (response.list || []).map(p => this.mapToPost(p));
|
const posts = (response.list || []).map(p => this.mapToPost(p));
|
||||||
|
|
||||||
// 缓存帖子
|
// 缓存帖子
|
||||||
posts.forEach(post => {
|
for (const post of posts) {
|
||||||
this.saveToMemoryCache(post);
|
this.saveToMemoryCache(post);
|
||||||
this.saveToLocalCache(post);
|
this.saveToLocalCache(post).catch(err => {
|
||||||
|
console.warn('[PostRepository] 缓存帖子失败:', post.id, err);
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
posts,
|
posts,
|
||||||
@@ -373,10 +378,12 @@ export class PostRepository implements IPostRepository {
|
|||||||
const posts = (response.list || []).map(p => this.mapToPost(p));
|
const posts = (response.list || []).map(p => this.mapToPost(p));
|
||||||
|
|
||||||
// 缓存帖子
|
// 缓存帖子
|
||||||
posts.forEach(post => {
|
for (const post of posts) {
|
||||||
this.saveToMemoryCache(post);
|
this.saveToMemoryCache(post);
|
||||||
this.saveToLocalCache(post);
|
this.saveToLocalCache(post).catch(err => {
|
||||||
|
console.warn('[PostRepository] 缓存帖子失败:', post.id, err);
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
posts,
|
posts,
|
||||||
|
|||||||
@@ -128,11 +128,11 @@ export const CreatePostScreen: React.FC<CreatePostScreenProps> = (props) => {
|
|||||||
|
|
||||||
// 响应式图片网格配置
|
// 响应式图片网格配置
|
||||||
const imagesPerRow = useResponsiveValue({ xs: 3, sm: 3, md: 4, lg: 5, xl: 6 });
|
const imagesPerRow = useResponsiveValue({ xs: 3, sm: 3, md: 4, lg: 5, xl: 6 });
|
||||||
const imageGap = 8;
|
const imageGap = 4;
|
||||||
const availableWidth = isWideScreen
|
const availableWidth = isWideScreen
|
||||||
? Math.min(width, 800) - spacing.lg * 2
|
? Math.min(width, 800) - spacing.lg * 2
|
||||||
: width - spacing.lg * 2;
|
: width - spacing.lg * 2;
|
||||||
const imageSize = (availableWidth - imageGap * (imagesPerRow - 1)) / imagesPerRow;
|
const imageSize = Math.floor((availableWidth - imageGap * (imagesPerRow - 1)) / imagesPerRow);
|
||||||
const contentInputMinHeight = Math.max(
|
const contentInputMinHeight = Math.max(
|
||||||
isWideScreen ? 460 : 320,
|
isWideScreen ? 460 : 320,
|
||||||
Math.floor(windowHeight * (isWideScreen ? 0.56 : 0.5))
|
Math.floor(windowHeight * (isWideScreen ? 0.56 : 0.5))
|
||||||
@@ -896,7 +896,7 @@ function createCreatePostStyles(colors: AppColors) {
|
|||||||
flexWrap: 'wrap',
|
flexWrap: 'wrap',
|
||||||
paddingHorizontal: 0,
|
paddingHorizontal: 0,
|
||||||
paddingTop: spacing.md,
|
paddingTop: spacing.md,
|
||||||
gap: 8,
|
gap: 4,
|
||||||
},
|
},
|
||||||
imageGridItem: {
|
imageGridItem: {
|
||||||
borderRadius: borderRadius.md,
|
borderRadius: borderRadius.md,
|
||||||
|
|||||||
@@ -991,3 +991,53 @@ export const updateConversationCacheUnreadCount = async (
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量保存会话列表及其相关数据(用户、群组)
|
||||||
|
* 在单个队列操作中完成,避免多次并发数据库操作导致的 statement 生命周期问题
|
||||||
|
*/
|
||||||
|
export const saveConversationsWithRelatedCache = async (
|
||||||
|
conversations: ConversationResponse[],
|
||||||
|
users?: UserDTO[],
|
||||||
|
groups?: GroupResponse[]
|
||||||
|
): Promise<void> => {
|
||||||
|
if (!conversations || conversations.length === 0) return;
|
||||||
|
|
||||||
|
const now = new Date().toISOString();
|
||||||
|
|
||||||
|
await enqueueWrite(async () => {
|
||||||
|
const database = await getDb();
|
||||||
|
|
||||||
|
// 1. 保存会话列表
|
||||||
|
for (const conversation of conversations) {
|
||||||
|
await database.runAsync(
|
||||||
|
`INSERT OR REPLACE INTO conversation_list_cache (id, data, updatedAt) VALUES (?, ?, ?)`,
|
||||||
|
[
|
||||||
|
String(conversation.id),
|
||||||
|
JSON.stringify(conversation),
|
||||||
|
conversation.updated_at || now,
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 保存用户
|
||||||
|
if (users && users.length > 0) {
|
||||||
|
for (const user of users) {
|
||||||
|
await database.runAsync(
|
||||||
|
`INSERT OR REPLACE INTO users (id, data, updatedAt) VALUES (?, ?, ?)`,
|
||||||
|
[String(user.id), JSON.stringify(user), now]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. 保存群组
|
||||||
|
if (groups && groups.length > 0) {
|
||||||
|
for (const group of groups) {
|
||||||
|
await database.runAsync(
|
||||||
|
`INSERT OR REPLACE INTO groups (id, data, updatedAt) VALUES (?, ?, ?)`,
|
||||||
|
[String(group.id), JSON.stringify(group), now]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|||||||
@@ -25,9 +25,7 @@ import {
|
|||||||
getConversationCache,
|
getConversationCache,
|
||||||
getConversationListCache,
|
getConversationListCache,
|
||||||
saveConversationCache,
|
saveConversationCache,
|
||||||
saveConversationsCache,
|
saveConversationsWithRelatedCache,
|
||||||
saveGroupsCache,
|
|
||||||
saveUsersCache,
|
|
||||||
updateConversationCacheUnreadCount,
|
updateConversationCacheUnreadCount,
|
||||||
} from './database';
|
} from './database';
|
||||||
|
|
||||||
@@ -48,18 +46,14 @@ class MessageService {
|
|||||||
list: ConversationResponse[]
|
list: ConversationResponse[]
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
if (!list.length) return;
|
if (!list.length) return;
|
||||||
await saveConversationsCache(list);
|
const users = list.flatMap(conv => [
|
||||||
await saveUsersCache(
|
|
||||||
list.flatMap(conv => [
|
|
||||||
...(conv.participants || []),
|
...(conv.participants || []),
|
||||||
...(conv.last_message?.sender ? [conv.last_message.sender] : []),
|
...(conv.last_message?.sender ? [conv.last_message.sender] : []),
|
||||||
])
|
]);
|
||||||
);
|
const groups = list
|
||||||
await saveGroupsCache(
|
|
||||||
list
|
|
||||||
.map(conv => conv.group)
|
.map(conv => conv.group)
|
||||||
.filter((group): group is NonNullable<typeof group> => Boolean(group))
|
.filter((group): group is NonNullable<typeof group> => Boolean(group));
|
||||||
);
|
await saveConversationsWithRelatedCache(list, users, groups);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** offset 会话列表单页:请求 + 落库 */
|
/** offset 会话列表单页:请求 + 落库 */
|
||||||
|
|||||||
@@ -43,9 +43,7 @@ import {
|
|||||||
saveUserCache,
|
saveUserCache,
|
||||||
updateMessageStatus,
|
updateMessageStatus,
|
||||||
deleteConversation as deleteConversationFromDb,
|
deleteConversation as deleteConversationFromDb,
|
||||||
saveConversationsCache,
|
saveConversationsWithRelatedCache,
|
||||||
saveUsersCache,
|
|
||||||
saveGroupsCache,
|
|
||||||
} from '../services/database';
|
} from '../services/database';
|
||||||
import { api } from '../services/api';
|
import { api } from '../services/api';
|
||||||
import { vibrateOnMessage } from '../services/messageVibrationService';
|
import { vibrateOnMessage } from '../services/messageVibrationService';
|
||||||
@@ -396,23 +394,16 @@ class MessageManager {
|
|||||||
/** 与会话列表同步写入本地缓存(参与者 / 群 / 列表) */
|
/** 与会话列表同步写入本地缓存(参与者 / 群 / 列表) */
|
||||||
private persistConversationListCache(): void {
|
private persistConversationListCache(): void {
|
||||||
const list = Array.from(this.state.conversations.values());
|
const list = Array.from(this.state.conversations.values());
|
||||||
saveConversationsCache(list).catch(error => {
|
const users = list.flatMap(conv => [
|
||||||
console.error('[MessageManager] 持久化会话列表失败:', error);
|
|
||||||
});
|
|
||||||
saveUsersCache(
|
|
||||||
list.flatMap(conv => [
|
|
||||||
...(conv.participants || []),
|
...(conv.participants || []),
|
||||||
...(conv.last_message?.sender ? [conv.last_message.sender] : []),
|
...(conv.last_message?.sender ? [conv.last_message.sender] : []),
|
||||||
])
|
]);
|
||||||
).catch(error => {
|
const groups = list
|
||||||
console.error('[MessageManager] 持久化会话相关用户失败:', error);
|
|
||||||
});
|
|
||||||
saveGroupsCache(
|
|
||||||
list
|
|
||||||
.map(conv => conv.group)
|
.map(conv => conv.group)
|
||||||
.filter((group): group is NonNullable<ConversationResponse['group']> => Boolean(group))
|
.filter((group): group is NonNullable<ConversationResponse['group']> => Boolean(group));
|
||||||
).catch(error => {
|
|
||||||
console.error('[MessageManager] 持久化会话相关群组失败:', error);
|
saveConversationsWithRelatedCache(list, users, groups).catch(error => {
|
||||||
|
console.error('[MessageManager] 持久化会话列表失败:', error);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user