chore: 更新应用配置和工具类

- 更新AppConfig应用配置
- 更新MainActivity主活动
- 更新MockDataProvider模拟数据
- 更新Chapter数据模型
- 更新AndroidManifest配置
This commit is contained in:
iammm0
2026-01-22 17:59:03 +08:00
parent 0f7a7cc7f2
commit 24cd9f4770
5 changed files with 91 additions and 32 deletions

View File

@@ -18,7 +18,8 @@
android:name=".MainActivity" android:name=".MainActivity"
android:exported="true" android:exported="true"
android:label="@string/app_name" android:label="@string/app_name"
android:theme="@style/Theme.Lifeecho" > android:theme="@style/Theme.Lifeecho"
android:windowSoftInputMode="adjustResize" >
<intent-filter> <intent-filter>
<action android:name="android.intent.action.MAIN" /> <action android:name="android.intent.action.MAIN" />

View File

@@ -5,7 +5,11 @@ import android.os.Bundle
import androidx.activity.ComponentActivity import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge import androidx.activity.enableEdgeToEdge
import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.animation.core.tween
import androidx.compose.foundation.clickable import androidx.compose.foundation.clickable
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.interaction.collectIsPressedAsState
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
@@ -21,6 +25,7 @@ import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.statusBars import androidx.compose.foundation.layout.statusBars
import androidx.compose.foundation.layout.windowInsetsPadding import androidx.compose.foundation.layout.windowInsetsPadding
import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.ui.draw.scale
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold import androidx.compose.material3.Scaffold
@@ -29,6 +34,7 @@ import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
@@ -60,9 +66,9 @@ class MainActivity : ComponentActivity() {
// 设置系统栏透明 // 设置系统栏透明
WindowCompat.setDecorFitsSystemWindows(window, false) WindowCompat.setDecorFitsSystemWindows(window, false)
// 设置状态栏和导航栏完全透明 // 设置状态栏和导航栏完全透明(使用 WindowInsetsController 在 LaunchedEffect 中处理)
window.statusBarColor = android.graphics.Color.TRANSPARENT // 注意:在 API 30+ 中,直接设置 statusBarColor 和 navigationBarColor 已弃用
window.navigationBarColor = android.graphics.Color.TRANSPARENT // 我们通过 WindowInsetsController 来管理系统栏外观
setContent { setContent {
val darkMode = com.huaga.life_echo.ui.settings.AppSettings.rememberDarkMode() val darkMode = com.huaga.life_echo.ui.settings.AppSettings.rememberDarkMode()
@@ -184,9 +190,30 @@ fun BottomNavItem(
val iconColor = if (isSelected) LightPurple else MaterialTheme.colorScheme.onSurfaceVariant val iconColor = if (isSelected) LightPurple else MaterialTheme.colorScheme.onSurfaceVariant
val textColor = if (isSelected) LightPurple else MaterialTheme.colorScheme.onSurfaceVariant val textColor = if (isSelected) LightPurple else MaterialTheme.colorScheme.onSurfaceVariant
// 选中状态的缩放动画
val scale by animateFloatAsState(
targetValue = if (isSelected) 1.1f else 1f,
animationSpec = tween(durationMillis = 200, easing = androidx.compose.animation.core.FastOutSlowInEasing),
label = "nav_item_scale"
)
// 点击时的缩放动画
val interactionSource = remember { MutableInteractionSource() }
val isPressed by interactionSource.collectIsPressedAsState()
val pressScale by animateFloatAsState(
targetValue = if (isPressed) 0.9f else 1f,
animationSpec = tween(durationMillis = 100),
label = "nav_item_press_scale"
)
Column( Column(
modifier = Modifier modifier = Modifier
.clickable { onClick() } .clickable(
interactionSource = interactionSource,
indication = null, // 移除默认的点击波纹效果,使用自定义动画
onClick = onClick
)
.scale(scale * pressScale) // 应用缩放动画
.padding(horizontal = 16.dp, vertical = 4.dp), .padding(horizontal = 16.dp, vertical = 4.dp),
horizontalAlignment = Alignment.CenterHorizontally, horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center verticalArrangement = Arrangement.Center

View File

@@ -1,9 +1,11 @@
package com.huaga.life_echo.config package com.huaga.life_echo.config
object AppConfig { object AppConfig {
// API 基础 URL(可以从 BuildConfig 或环境变量读取) // API 基础 URL - 内网地址,用于同一局域网下的物理机测试
const val BASE_URL = "https://lifecho.worldsplats.com" // Android 模拟器使用 10.0.2.2 访问 localhost // 当前主机IP: 192.168.10.9,端口: 8000
const val WS_BASE_URL = "https://lifecho.worldsplats.com" // 如果IP地址变化请修改此处
const val BASE_URL = "http://192.168.10.9:8000"
const val WS_BASE_URL = "ws://192.168.10.9:8000"
// 生产环境应该从配置文件或环境变量读取 // 生产环境应该从配置文件或环境变量读取
// const val BASE_URL = BuildConfig.API_BASE_URL // const val BASE_URL = BuildConfig.API_BASE_URL

View File

@@ -12,6 +12,7 @@ data class Chapter(
val status: String, // draft, partial, completed val status: String, // draft, partial, completed
val updatedAt: Long, val updatedAt: Long,
val category: String, val category: String,
val pageCount: Int? = null val pageCount: Int? = null,
val isNew: Boolean = false
) )

View File

@@ -1,7 +1,19 @@
package com.huaga.life_echo.data.mock package com.huaga.life_echo.data.mock
import com.huaga.life_echo.network.models.* import android.os.Build
import kotlinx.serialization.Serializable import androidx.annotation.RequiresApi
import com.huaga.life_echo.network.models.BookDto
import com.huaga.life_echo.network.models.ChapterContentDto
import com.huaga.life_echo.network.models.ChapterDto
import com.huaga.life_echo.network.models.ConversationDetailDto
import com.huaga.life_echo.network.models.ConversationListItemDto
import com.huaga.life_echo.network.models.FAQDto
import com.huaga.life_echo.network.models.MessageDto
import com.huaga.life_echo.network.models.OrderDto
import com.huaga.life_echo.network.models.PlanBenefitDto
import com.huaga.life_echo.network.models.PlanDto
import com.huaga.life_echo.network.models.QuotaCheckDto
import com.huaga.life_echo.network.models.UserProfileDto
/** /**
* Mock数据提供者 * Mock数据提供者
@@ -89,47 +101,57 @@ object MockDataProvider {
} }
// 获取Mock章节列表 // 获取Mock章节列表
@RequiresApi(Build.VERSION_CODES.O)
fun getMockChapters(): List<ChapterDto> { fun getMockChapters(): List<ChapterDto> {
val now = java.time.Instant.now().toString()
return listOf( return listOf(
ChapterDto( ChapterDto(
id = "chapter_001", id = "chapter_001",
title = "童年与家庭", title = "童年与家庭",
content = "我出生在一个普通的农村家庭,父母都是勤劳朴实的农民。\n\n父亲是村里的木匠,手艺精湛,邻里乡亲都愿意找他帮忙。", content = "我出生在一个普通的农村家庭,父母都是勤劳朴实的农民。\n\n父亲是村里的木匠,手艺精湛,邻里乡亲都愿意找他帮忙。",
orderIndex = 1, order_index = 1,
status = "completed", status = "completed",
category = "childhood", category = "childhood",
pageCount = 3, images = emptyList(),
updatedAt = System.currentTimeMillis() - 86400000 updated_at = now,
is_new = false,
source_segments = emptyList()
), ),
ChapterDto( ChapterDto(
id = "chapter_002", id = "chapter_002",
title = "上学的日子", title = "上学的日子",
content = "上学的日子总是充满欢声笑语,虽然条件艰苦,但学习的快乐让我忘记了生活的艰辛。", content = "上学的日子总是充满欢声笑语,虽然条件艰苦,但学习的快乐让我忘记了生活的艰辛。",
orderIndex = 2, order_index = 2,
status = "partial", status = "partial",
category = "education", category = "education",
pageCount = 2, images = emptyList(),
updatedAt = System.currentTimeMillis() - 43200000 updated_at = now,
is_new = false,
source_segments = emptyList()
), ),
ChapterDto( ChapterDto(
id = "chapter_003", id = "chapter_003",
title = "工作与事业", title = "工作与事业",
content = "工作是我人生中重要的转折点,让我学会了承担责任,也让我明白了生活的意义。", content = "工作是我人生中重要的转折点,让我学会了承担责任,也让我明白了生活的意义。",
orderIndex = 3, order_index = 3,
status = "pending", status = "pending",
category = "career", category = "career",
pageCount = null, images = emptyList(),
updatedAt = System.currentTimeMillis() updated_at = now,
is_new = true,
source_segments = emptyList()
), ),
ChapterDto( ChapterDto(
id = "chapter_004", id = "chapter_004",
title = "爱情与婚姻", title = "爱情与婚姻",
content = "爱情是人生中最美好的经历之一,它让我懂得了什么是真正的幸福。", content = "爱情是人生中最美好的经历之一,它让我懂得了什么是真正的幸福。",
orderIndex = 4, order_index = 4,
status = "pending", status = "pending",
category = "family", category = "family",
pageCount = null, images = emptyList(),
updatedAt = System.currentTimeMillis() updated_at = now,
is_new = true,
source_segments = emptyList()
) )
) )
} }
@@ -138,17 +160,17 @@ object MockDataProvider {
fun getMockBookInfo(): BookDto { fun getMockBookInfo(): BookDto {
return BookDto( return BookDto(
id = "book_001", id = "book_001",
userId = "user_001",
title = "这一生", title = "这一生",
subtitle = "我的回忆录", total_pages = 5,
totalPages = 5, total_words = 5000,
totalWords = 5000, cover_image_url = null,
updatedAt = System.currentTimeMillis(), has_update = true,
lastUpdatedAt = System.currentTimeMillis() - 120000 // 2分钟前 last_update_chapter_id = "chapter_003"
) )
} }
// 获取Mock章节内容 // 获取Mock章节内容
@RequiresApi(Build.VERSION_CODES.O)
fun getMockChapterContent(id: String): ChapterContentDto { fun getMockChapterContent(id: String): ChapterContentDto {
val chapters = getMockChapters() val chapters = getMockChapters()
val chapter = chapters.find { it.id == id } ?: chapters[0] val chapter = chapters.find { it.id == id } ?: chapters[0]
@@ -157,11 +179,17 @@ object MockDataProvider {
id = chapter.id, id = chapter.id,
title = chapter.title, title = chapter.title,
content = chapter.content, content = chapter.content,
orderIndex = chapter.orderIndex, orderIndex = chapter.order_index,
status = chapter.status, status = chapter.status,
category = chapter.category, category = chapter.category,
pageCount = chapter.pageCount, pageCount = null,
updatedAt = chapter.updatedAt ?: System.currentTimeMillis(), updatedAt = chapter.updated_at?.let {
try {
java.time.Instant.parse(it).toEpochMilli()
} catch (e: Exception) {
System.currentTimeMillis()
}
} ?: System.currentTimeMillis(),
quotes = if (chapter.category == "childhood") { quotes = if (chapter.category == "childhood") {
listOf("\"日子虽然清苦, 但那时候的快乐是最纯粹的。\"") listOf("\"日子虽然清苦, 但那时候的快乐是最纯粹的。\"")
} else { } else {