diff --git a/.idea/deploymentTargetSelector.xml b/.idea/deploymentTargetSelector.xml index 95b2c3c..f45fe14 100644 --- a/.idea/deploymentTargetSelector.xml +++ b/.idea/deploymentTargetSelector.xml @@ -60,7 +60,7 @@ - + diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 346428d..67117ba 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -31,6 +31,11 @@ android:theme="@style/Theme.Telewatch" tools:ignore="WearStandaloneAppFlag" tools:targetApi="31"> + Unit) { Spacer(modifier = Modifier.height(16.dp)) // 不同意和同意按钮 - Row( - horizontalArrangement = Arrangement.Center, + Box( modifier = Modifier - .fillMaxWidth() - .padding(bottom = 64.dp, start = 16.dp, end = 16.dp) + .padding(bottom = 4.dp, start = 16.dp, end = 16.dp) + .fillMaxSize(), + contentAlignment = Alignment.Center ) { Button( - onClick = { set(false) }, - modifier = Modifier.weight(1f), + onClick = { set(true) }, + modifier = Modifier.fillMaxWidth(), colors = ButtonDefaults.buttonColors( - containerColor = Color(0xFF3E4D58), // 按钮背景颜色 + containerColor = Color(0xFF3A7FBE), // 按钮背景颜色 contentColor = Color.White // 按钮文字颜色 ) ) { - Text(text = stringResource(id = R.string.disagree)) + Text(text = stringResource(id = R.string.agree)) } - - Spacer(modifier = Modifier.width(8.dp)) - + } + Box( + modifier = Modifier + .padding(bottom = 16.dp, start = 16.dp, end = 16.dp) + .fillMaxSize(), + contentAlignment = Alignment.Center + ) { Button( - onClick = { set(true) }, - modifier = Modifier.weight(1f), + onClick = { set(false) }, + modifier = Modifier.fillMaxWidth(), colors = ButtonDefaults.buttonColors( - containerColor = Color(0xFF3A7FBE), // 按钮背景颜色 + containerColor = Color(0xFF3E4D58), // 按钮背景颜色 contentColor = Color.White // 按钮文字颜色 ) ) { - Text(text = stringResource(id = R.string.agree)) + Text(text = stringResource(id = R.string.disagree)) } } + + Spacer(modifier = Modifier.height(42.dp)) +// Row( +// horizontalArrangement = Arrangement.Center, +// modifier = Modifier +// .fillMaxWidth() +// .padding(bottom = 64.dp, start = 16.dp, end = 16.dp) +// ) { +// Button( +// onClick = { set(false) }, +// modifier = Modifier.weight(1f), +// colors = ButtonDefaults.buttonColors( +// containerColor = Color(0xFF3E4D58), // 按钮背景颜色 +// contentColor = Color.White // 按钮文字颜色 +// ) +// ) { +// Text(text = stringResource(id = R.string.disagree)) +// } +// +// Spacer(modifier = Modifier.width(8.dp)) +// +// Button( +// onClick = { set(true) }, +// modifier = Modifier.weight(1f), +// colors = ButtonDefaults.buttonColors( +// containerColor = Color(0xFF3A7FBE), // 按钮背景颜色 +// contentColor = Color.White // 按钮文字颜色 +// ) +// ) { +// Text(text = stringResource(id = R.string.agree)) +// } +// } } } diff --git a/app/src/main/java/com/gohj99/telewatch/ChatActivity.kt b/app/src/main/java/com/gohj99/telewatch/ChatActivity.kt index 6a7db4f..d9c36b9 100644 --- a/app/src/main/java/com/gohj99/telewatch/ChatActivity.kt +++ b/app/src/main/java/com/gohj99/telewatch/ChatActivity.kt @@ -133,7 +133,7 @@ class ChatActivity : ComponentActivity() { } } - private suspend fun init(lastRun: Boolean = false) { + private suspend fun init(parameter: String? = null) { tgApi = TgApiManager.tgApi // 接收传递的 Chat 对象 @@ -362,6 +362,11 @@ class ChatActivity : ComponentActivity() { // 处理没有可用浏览器的情况 Toast.makeText(this, getString(R.string.No_app_to_handle_this_url), Toast.LENGTH_SHORT).show() } + }, + reInit = { + lifecycleScope.launch { + init() + } } ) } @@ -369,12 +374,12 @@ class ChatActivity : ComponentActivity() { } } if (chatObject == null) { - if (lastRun) { + if (parameter == "lastRun") { throw IllegalStateException("Unable to create private chat") } else { - tgApi!!.CreatePrivateChat(chat!!.id) + tgApi!!.createPrivateChat(chat!!.id) lifecycleScope.launch(Dispatchers.IO) { - init(true) + init("lastRun") } } } diff --git a/app/src/main/java/com/gohj99/telewatch/GoToAnnouncementActivity.kt b/app/src/main/java/com/gohj99/telewatch/GoToAnnouncementActivity.kt new file mode 100644 index 0000000..6958bbf --- /dev/null +++ b/app/src/main/java/com/gohj99/telewatch/GoToAnnouncementActivity.kt @@ -0,0 +1,162 @@ +/* + * Copyright (c) 2024 gohj99. Lorem ipsum dolor sit amet, consectetur adipiscing elit. + * Morbi non lorem porttitor neque feugiat blandit. Ut vitae ipsum eget quam lacinia accumsan. + * Etiam sed turpis ac ipsum condimentum fringilla. Maecenas magna. + * Proin dapibus sapien vel ante. Aliquam erat volutpat. Pellentesque sagittis ligula eget metus. + * Vestibulum commodo. Ut rhoncus gravida arcu. + */ + +package com.gohj99.telewatch + +import android.content.Context +import android.content.Intent +import android.os.Bundle +import androidx.activity.ComponentActivity +import androidx.activity.compose.setContent +import androidx.activity.enableEdgeToEdge +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.verticalScroll +import androidx.compose.material3.Button +import androidx.compose.material3.ButtonDefaults +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import com.gohj99.telewatch.ui.theme.TelewatchTheme +import com.gohj99.telewatch.ui.verticalRotaryScroll + +class GoToAnnouncementActivity : ComponentActivity() { + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + enableEdgeToEdge() + + val settingsSharedPref = getSharedPreferences("app_settings", Context.MODE_PRIVATE) + if (settingsSharedPref.getBoolean("Skip_GoToAnnouncementActivity", false)) { + startActivity( + Intent( + this@GoToAnnouncementActivity, + AnnouncementActivity::class.java + ) + ) + finish() + } else { + setContent { + TelewatchTheme { + SplashAnnouncementActivityScreen { isSkip -> + with(settingsSharedPref.edit()) { + putBoolean("Skip_GoToAnnouncementActivity", isSkip) + commit() + startActivity( + Intent( + this@GoToAnnouncementActivity, + AnnouncementActivity::class.java + ) + ) + finish() + } + } + } + } + } + } +} + +@Composable +fun SplashAnnouncementActivityScreen(set: (Boolean) -> Unit) { + val scrollState = rememberScrollState() + LaunchedEffect(Unit) { + scrollState.scrollTo(80) + } + + Column( + modifier = Modifier + .fillMaxSize() + .verticalScroll(scrollState) + .verticalRotaryScroll(scrollState), + verticalArrangement = Arrangement.Center, + horizontalAlignment = Alignment.CenterHorizontally + ) { + // 标题 + Text( + text = stringResource(id = R.string.GoToAnnouncementActivity_title), + fontSize = 20.sp, + fontWeight = FontWeight.Bold, + color = Color.White, + textAlign = TextAlign.Center, + modifier = Modifier.padding(top = 86.dp) + ) + + // 主要说明部分 + Text( + text = stringResource(id = R.string.GoToAnnouncementActivity_description), + fontSize = 16.sp, + color = Color.White, + textAlign = TextAlign.Center, + modifier = Modifier.padding(16.dp) + ) + + Spacer(modifier = Modifier.height(16.dp)) + + // 不提醒继续和继续按钮 + Box( + modifier = Modifier + .padding(bottom = 4.dp, start = 16.dp, end = 16.dp) + .fillMaxSize(), + contentAlignment = Alignment.Center + ) { + Button( + onClick = { set(true) }, + modifier = Modifier.fillMaxWidth(), + colors = ButtonDefaults.buttonColors( + containerColor = Color(0xFF3A7FBE), // 按钮背景颜色 + contentColor = Color.White // 按钮文字颜色 + ) + ) { + Text(text = stringResource(id = R.string.don_remind_me_again)) + } + } + Box( + modifier = Modifier + .padding(bottom = 16.dp, start = 16.dp, end = 16.dp) + .fillMaxSize(), + contentAlignment = Alignment.Center + ) { + Button( + onClick = { set(false) }, + modifier = Modifier.fillMaxWidth(), + colors = ButtonDefaults.buttonColors( + containerColor = Color(0xFF3E4D58), // 按钮背景颜色 + contentColor = Color.White // 按钮文字颜色 + ) + ) { + Text(text = stringResource(id = R.string.agree)) + } + } + + Spacer(modifier = Modifier.height(42.dp)) + } +} + +@Preview(showBackground = true) +@Composable +fun SplashGoToAnnouncementActivityPreview() { + TelewatchTheme { + SplashAnnouncementActivityScreen { /*TODO*/ } + } +} diff --git a/app/src/main/java/com/gohj99/telewatch/GoToCheckUpdateActivity.kt b/app/src/main/java/com/gohj99/telewatch/GoToCheckUpdateActivity.kt index 77438ad..24d3bcd 100644 --- a/app/src/main/java/com/gohj99/telewatch/GoToCheckUpdateActivity.kt +++ b/app/src/main/java/com/gohj99/telewatch/GoToCheckUpdateActivity.kt @@ -15,14 +15,13 @@ import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.activity.enableEdgeToEdge import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.width import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll import androidx.compose.material3.Button @@ -114,37 +113,43 @@ fun SplashGoToCheckUpdateScreen(set: (Boolean) -> Unit) { Spacer(modifier = Modifier.height(16.dp)) - // 不同意和同意按钮 - Row( - horizontalArrangement = Arrangement.Center, + // 不提醒继续和继续按钮 + Box( modifier = Modifier - .fillMaxWidth() - .padding(bottom = 64.dp, start = 16.dp, end = 16.dp) + .padding(bottom = 4.dp, start = 16.dp, end = 16.dp) + .fillMaxSize(), + contentAlignment = Alignment.Center ) { Button( - onClick = { set(false) }, - modifier = Modifier.weight(1f), + onClick = { set(true) }, + modifier = Modifier.fillMaxWidth(), colors = ButtonDefaults.buttonColors( - containerColor = Color(0xFF3E4D58), // 按钮背景颜色 + containerColor = Color(0xFF3A7FBE), // 按钮背景颜色 contentColor = Color.White // 按钮文字颜色 ) ) { - Text(text = stringResource(id = R.string.agree)) + Text(text = stringResource(id = R.string.don_remind_me_again)) } - - Spacer(modifier = Modifier.width(8.dp)) - + } + Box( + modifier = Modifier + .padding(bottom = 16.dp, start = 16.dp, end = 16.dp) + .fillMaxSize(), + contentAlignment = Alignment.Center + ) { Button( - onClick = { set(true) }, - modifier = Modifier.weight(1f), + onClick = { set(false) }, + modifier = Modifier.fillMaxWidth(), colors = ButtonDefaults.buttonColors( - containerColor = Color(0xFF3A7FBE), // 按钮背景颜色 + containerColor = Color(0xFF3E4D58), // 按钮背景颜色 contentColor = Color.White // 按钮文字颜色 ) ) { - Text(text = stringResource(id = R.string.don_remind_me_again)) + Text(text = stringResource(id = R.string.agree)) } } + + Spacer(modifier = Modifier.height(42.dp)) } } diff --git a/app/src/main/java/com/gohj99/telewatch/MainActivity.kt b/app/src/main/java/com/gohj99/telewatch/MainActivity.kt index 3449a17..960945b 100644 --- a/app/src/main/java/com/gohj99/telewatch/MainActivity.kt +++ b/app/src/main/java/com/gohj99/telewatch/MainActivity.kt @@ -22,6 +22,7 @@ import androidx.compose.foundation.Image import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.runtime.Composable +import androidx.compose.runtime.MutableState import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.setValue @@ -49,6 +50,11 @@ object TgApiManager { var tgApi: TgApi? = null } +object chatsListManager { + @SuppressLint("StaticFieldLeak") + var chatsList: MutableState> = mutableStateOf(listOf()) +} + class MainActivity : ComponentActivity() { private var isLoggedIn: Boolean = false private var exceptionState by mutableStateOf(null) @@ -260,6 +266,7 @@ class MainActivity : ComponentActivity() { topTitle = topTitle, chatsFoldersList = chatsFoldersList ) + chatsListManager.chatsList = chatsList TgApiManager.tgApi?.loadChats(15) TgApiManager.tgApi?.getContacts(contacts) launch(Dispatchers.Main) { diff --git a/app/src/main/java/com/gohj99/telewatch/SettingActivity.kt b/app/src/main/java/com/gohj99/telewatch/SettingActivity.kt index 7cb3268..9cdcfbb 100644 --- a/app/src/main/java/com/gohj99/telewatch/SettingActivity.kt +++ b/app/src/main/java/com/gohj99/telewatch/SettingActivity.kt @@ -139,7 +139,7 @@ class SettingActivity : ComponentActivity() { startActivity( Intent( this, - AnnouncementActivity::class.java + GoToAnnouncementActivity::class.java ) ) } diff --git a/app/src/main/java/com/gohj99/telewatch/SwitchAccountActivity.kt b/app/src/main/java/com/gohj99/telewatch/SwitchAccountActivity.kt index 4871b86..f699b5b 100644 --- a/app/src/main/java/com/gohj99/telewatch/SwitchAccountActivity.kt +++ b/app/src/main/java/com/gohj99/telewatch/SwitchAccountActivity.kt @@ -16,14 +16,13 @@ import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.activity.enableEdgeToEdge import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.width import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll import androidx.compose.material3.Button @@ -124,36 +123,42 @@ fun SplashSettingLazyColumnScreen(account: String, set: (Boolean) -> Unit) { Spacer(modifier = Modifier.height(16.dp)) // 不同意和同意按钮 - Row( - horizontalArrangement = Arrangement.Center, + Box( modifier = Modifier - .fillMaxWidth() - .padding(bottom = 64.dp, start = 16.dp, end = 16.dp) + .padding(bottom = 4.dp, start = 16.dp, end = 16.dp) + .fillMaxSize(), + contentAlignment = Alignment.Center ) { Button( - onClick = { set(false) }, - modifier = Modifier.weight(1f), + onClick = { set(true) }, + modifier = Modifier.fillMaxWidth(), colors = ButtonDefaults.buttonColors( - containerColor = Color(0xFF3E4D58), // 按钮背景颜色 + containerColor = Color(0xFF3A7FBE), // 按钮背景颜色 contentColor = Color.White // 按钮文字颜色 ) ) { - Text(text = stringResource(id = R.string.disagree)) + Text(text = stringResource(id = R.string.agree)) } - - Spacer(modifier = Modifier.width(8.dp)) - + } + Box( + modifier = Modifier + .padding(bottom = 16.dp, start = 16.dp, end = 16.dp) + .fillMaxSize(), + contentAlignment = Alignment.Center + ) { Button( - onClick = { set(true) }, - modifier = Modifier.weight(1f), + onClick = { set(false) }, + modifier = Modifier.fillMaxWidth(), colors = ButtonDefaults.buttonColors( - containerColor = Color(0xFF3A7FBE), // 按钮背景颜色 + containerColor = Color(0xFF3E4D58), // 按钮背景颜色 contentColor = Color.White // 按钮文字颜色 ) ) { - Text(text = stringResource(id = R.string.agree)) + Text(text = stringResource(id = R.string.disagree)) } } + + Spacer(modifier = Modifier.height(42.dp)) } } diff --git a/app/src/main/java/com/gohj99/telewatch/telegram/TgApi.kt b/app/src/main/java/com/gohj99/telewatch/telegram/TgApi.kt index 77dc7dd..a59b68a 100644 --- a/app/src/main/java/com/gohj99/telewatch/telegram/TgApi.kt +++ b/app/src/main/java/com/gohj99/telewatch/telegram/TgApi.kt @@ -457,7 +457,7 @@ class TgApi( val chatId = newChat.id //println(newChat.lastMessage) - //println(newMessageText) + //println(update) //println(newChat.positions.firstOrNull()?.isPinned ?: false) var isPinned = newChat.positions.firstOrNull()?.isPinned ?: false @@ -468,11 +468,13 @@ class TgApi( var isPrivateChat = false var chatTitle = newChat.title var lastMessage = handleAllMessages(newChat.lastMessage) + var havePositions = true // 异步获取聊天标题 CoroutineScope(Dispatchers.IO).launch { try { val chatResult = sendRequest(TdApi.GetChat(chatId)) if (chatResult.constructor == TdApi.Chat.CONSTRUCTOR) { + if (chatResult.positions.isEmpty()) havePositions = false isPinned = chatResult.positions.firstOrNull()?.isPinned ?: false chatTitle = chatResult.title lastMessage = handleAllMessages(chatResult.lastMessage) @@ -514,21 +516,104 @@ class TgApi( add(0, updatedChat) // 将更新后的聊天添加到顶部 } else { // 如果不存在该聊天,添加到列表末尾 - add( - Chat( - id = chatId, - title = chatTitle, // 使用从 TdApi 获取的标题 - message = lastMessage, - isPinned = isPinned, - isRead = isRead, - isBot = isBot, - isChannel = isChannel, - isGroup = isGroup, - isPrivateChat = isPrivateChat + if (havePositions) { + add( + Chat( + id = chatId, + title = chatTitle, // 使用从 TdApi 获取的标题 + message = lastMessage, + isPinned = isPinned, + isRead = isRead, + isBot = isBot, + isChannel = isChannel, + isGroup = isGroup, + isPrivateChat = isPrivateChat + ) ) - ) + } + + } + } + } + } + } + + // 强制加载消息 + private fun addNewChat(chatId: Long){ + // 异步获取聊天标题 + CoroutineScope(Dispatchers.IO).launch { + try { + val chatResult = sendRequest(TdApi.GetChat(chatId)) + if (chatResult.constructor == TdApi.Chat.CONSTRUCTOR) { + + var isBot = false + var isChannel = false + var isGroup = false + var isPrivateChat = false + var havePositions = true + + if (chatResult.positions.isEmpty()) havePositions = false + val isPinned = chatResult.positions.firstOrNull()?.isPinned ?: false + val chatTitle = chatResult.title + val lastMessage = handleAllMessages(chatResult.lastMessage) + val isRead = chatResult.isMarkedAsUnread + when (val messageType = chatResult.type) { + is TdApi.ChatTypeSupergroup -> { + if (messageType.isChannel) { + isChannel = true + } else { + isGroup = true + } + } + is TdApi.ChatTypeBasicGroup -> { + isGroup = true + } + is TdApi.ChatTypePrivate -> { + isPrivateChat = true + val userResult = sendRequest(TdApi.GetUser(chatResult.id)) + if (userResult.type is TdApi.UserTypeBot) { + isBot = true + } + } + } + + // 加入聊天列表 + withContext(Dispatchers.Main) { + chatsList.value = chatsList.value.toMutableList().apply { + // 查找现有的聊天并更新 + val existingChatIndex = indexOfFirst { it.id == chatId } + if (existingChatIndex >= 0) { + // 如果存在该聊天,更新并移动到顶部 + val updatedChat = get(existingChatIndex).copy( + title = chatTitle, + message = lastMessage + ) + removeAt(existingChatIndex) // 移除旧的聊天 + add(0, updatedChat) // 将更新后的聊天添加到顶部 + } else { + // 如果不存在该聊天,添加到列表末尾 + if (havePositions) { + add( + Chat( + id = chatId, + title = chatTitle, // 使用从 TdApi 获取的标题 + message = lastMessage, + isPinned = isPinned, + isRead = isRead, + isBot = isBot, + isChannel = isChannel, + isGroup = isGroup, + isPrivateChat = isPrivateChat + ) + ) + } + + } + } } } + } catch (e: Exception) { + println("GetChat request failed (handleNewChat): ${e.message}") } } } @@ -666,6 +751,95 @@ class TgApi( } } + // 按用户名搜索公共聊天 + suspend fun searchPublicChat( + query: String, + searchList: MutableState> + ) { + println("查询中") + val searchResult = sendRequest(TdApi.SearchPublicChats(query)) + searchResult.let { + if (it is TdApi.Chats) { + // 搜索成功 + println("搜索成功") + //println(searchResult) + searchList.value = emptyList() + searchList.value = withContext(Dispatchers.IO) { + searchResult.chatIds.map { id -> + var isPinned = false + var isRead = false + var isBot = false + var isChannel = false + var isGroup = false + var isPrivateChat = false + var chatTitle = "error" + var lastMessage = "" + try { + val chatResult = sendRequest(TdApi.GetChat(id)) + if (chatResult.constructor == TdApi.Chat.CONSTRUCTOR) { + println(chatResult) + isPinned = chatResult.positions.firstOrNull()?.isPinned ?: false + chatTitle = chatResult.title + lastMessage = handleAllMessages(chatResult.lastMessage) + isRead = chatResult.isMarkedAsUnread + when (val messageType = chatResult.type) { + is TdApi.ChatTypeSupergroup -> { + if (messageType.isChannel) { + isChannel = true + } else { + isGroup = true + } + } + + is TdApi.ChatTypeBasicGroup -> { + isGroup = true + } + + is TdApi.ChatTypePrivate -> { + isPrivateChat = true + val userResult = + sendRequest(TdApi.GetUser(chatResult.id)) + if (userResult.type is TdApi.UserTypeBot) { + isBot = true + } + } + } + } + } catch (e: Exception) { + println("GetChat request failed (handleNewChat): ${e.message}") + } + Chat( + id = id, + title = chatTitle, + message = lastMessage, + isPinned = isPinned, + isRead = isRead, + isBot = isBot, + isChannel = isChannel, + isGroup = isGroup, + isPrivateChat = isPrivateChat + ) + } + } + } + } + } + + // 发送加入聊天请求 + fun joinChat(chatId: Long, reInit: () -> Unit) { + client.send(TdApi.JoinChat(chatId)) { result -> + if (result is TdApi.Ok) { + // 加入聊天成功 + //println("Joined the chat successfully") + addNewChat(chatId) + reInit() + } else { + // 加入聊天失败 + println("Failed to join chat") + } + } + } + // 获取lastReadOutboxMessageId fun getLastReadOutboxMessageId(): MutableState { return lastReadOutboxMessageId @@ -815,7 +989,7 @@ class TgApi( return null } - suspend fun CreatePrivateChat(userId: Long) { + suspend fun createPrivateChat(userId: Long) { try { sendRequest(TdApi.CreatePrivateChat(userId, false)) } catch (e: Exception) { @@ -849,7 +1023,7 @@ class TgApi( // 加载聊天列表 suspend fun loadChats(limit: Int = 15){ - val loadChats = TdApi.LoadChats(TdApi.ChatListMain(), limit) + val loadChats = TdApi.LoadChats(TdApi.ChatListFolder(0), limit) try { val result = sendRequest(loadChats) println("LoadChats result: $result") diff --git a/app/src/main/java/com/gohj99/telewatch/ui/AnnouncementScreen.kt b/app/src/main/java/com/gohj99/telewatch/ui/AnnouncementScreen.kt index 4121b47..e02f6f5 100644 --- a/app/src/main/java/com/gohj99/telewatch/ui/AnnouncementScreen.kt +++ b/app/src/main/java/com/gohj99/telewatch/ui/AnnouncementScreen.kt @@ -8,6 +8,11 @@ package com.gohj99.telewatch.ui +import android.content.Intent +import android.content.pm.PackageManager +import android.content.pm.ResolveInfo +import android.net.Uri +import android.widget.Toast import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row @@ -20,6 +25,7 @@ import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.text.selection.SelectionContainer import androidx.compose.foundation.verticalScroll import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text @@ -27,6 +33,7 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color +import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextOverflow @@ -35,6 +42,7 @@ import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import com.gohj99.telewatch.Announcement import com.gohj99.telewatch.R +import com.gohj99.telewatch.ui.main.LinkText import com.gohj99.telewatch.ui.main.MainCard import com.google.gson.JsonObject @@ -48,6 +56,8 @@ fun SplashAnnouncementScreen( modifier = Modifier .fillMaxSize() ) { + val context = LocalContext.current + if (jsonObject == null) { // 包含 Row 的 Box Box( @@ -109,15 +119,41 @@ fun SplashAnnouncementScreen( Spacer(modifier = Modifier.height(35.dp)) // 添加一个高度为 8dp 的 Spacer MainCard( column = { - Text( - text = jsonObject["content"]?.asString ?: "Error", - color = Color.White, - style = MaterialTheme.typography.titleMedium - ) + SelectionContainer { + LinkText( + text = jsonObject["content"]?.asString ?: "Error", + color = Color.White, + style = MaterialTheme.typography.titleMedium, + onLinkClick = { url -> + val intent = Intent(Intent.ACTION_VIEW, Uri.parse(url)) + val packageManager: PackageManager = context.packageManager + val activities: List = packageManager.queryIntentActivities(intent, 0) + + if (activities.isNotEmpty()) { + context.startActivity(intent) + } else { + // 处理没有可用浏览器的情况 + Toast.makeText(context, context.getString(R.string.No_app_to_handle_this_url), Toast.LENGTH_SHORT).show() + } + } + ) + } }, item = "content", color = Color(0xFF2C323A) ) + Box( + modifier = Modifier.fillMaxSize(), + contentAlignment = Alignment.Center + ) { + Text( + text = jsonObject["created_at"]?.asString ?: "", + color = Color.White, + style = MaterialTheme.typography.titleMedium, + modifier = Modifier + .padding(top = 12.dp) + ) + } Spacer(modifier = Modifier.height(50.dp)) } } diff --git a/app/src/main/java/com/gohj99/telewatch/ui/chat/ChatScreen.kt b/app/src/main/java/com/gohj99/telewatch/ui/chat/ChatScreen.kt index b93df72..f0ff889 100644 --- a/app/src/main/java/com/gohj99/telewatch/ui/chat/ChatScreen.kt +++ b/app/src/main/java/com/gohj99/telewatch/ui/chat/ChatScreen.kt @@ -70,6 +70,8 @@ import androidx.compose.ui.unit.sp import coil.compose.rememberAsyncImagePainter import com.gohj99.telewatch.R import com.gohj99.telewatch.TgApiManager +import com.gohj99.telewatch.chatsListManager +import com.gohj99.telewatch.ui.CustomButton import com.gohj99.telewatch.ui.main.Chat import com.gohj99.telewatch.ui.main.LinkText import com.gohj99.telewatch.ui.main.SplashLoadingScreen @@ -131,7 +133,8 @@ fun SplashChatScreen( lastReadOutboxMessageId: MutableState, lastReadInboxMessageId: MutableState, listState: LazyListState = rememberLazyListState(), - onLinkClick: (String) -> Unit + onLinkClick: (String) -> Unit, + reInit: (String) -> Unit ) { var isFloatingVisible by remember { mutableStateOf(true) } var inputText by remember { mutableStateOf(TextFieldValue("")) } @@ -139,6 +142,7 @@ fun SplashChatScreen( val keyboardController = LocalSoftwareKeyboardController.current var isLongPressed by remember { mutableStateOf(false) } var selectMessage by remember { mutableStateOf(TdApi.Message()) } + var notJoin = false // 获取context val context = LocalContext.current @@ -146,6 +150,9 @@ fun SplashChatScreen( val settingsSharedPref = context.getSharedPreferences("app_settings", Context.MODE_PRIVATE) val showUnknownMessageType = settingsSharedPref.getBoolean("show_unknown_message_type", false) + //println(chatsListManager.chatsList.value) + if (!chatsListManager.chatsList.value.any { it.id == chatId }) notJoin = true + LaunchedEffect(listState) { var previousIndex = listState.firstVisibleItemIndex var previousScrollOffset = listState.firstVisibleItemScrollOffset @@ -248,6 +255,10 @@ fun SplashChatScreen( ) ) } + }, + onLongPress = { + selectMessage = message + isLongPressed = true } ) } @@ -614,54 +625,83 @@ fun SplashChatScreen( ) ) + // 消息发送部分 var showKeyboard by remember { mutableStateOf(false) } val chatPermissions: TdApi.ChatPermissions? = chatObject.permissions - if (chatPermissions == null) { + if (notJoin) { showKeyboard = true } else { - if (chatPermissions.canSendBasicMessages) { + if (chatPermissions == null) { showKeyboard = true + } else { + if (chatPermissions.canSendBasicMessages) { + showKeyboard = true + } } } if (showKeyboard) { if (isFloatingVisible) { - Row( - modifier = Modifier - .fillMaxWidth() - .align(Alignment.BottomCenter) - .padding(bottom = 4.dp) - .alpha(1f), - horizontalArrangement = Arrangement.SpaceEvenly, - verticalAlignment = Alignment.CenterVertically - ) { - IconButton( - onClick = { - textFieldFocusRequester.requestFocus() // 将焦点移动到隐藏的 TextField - keyboardController?.show() // 显示输入法 - }, + if (notJoin) { + Row( modifier = Modifier - .size(84.dp) + .fillMaxWidth() + .align(Alignment.BottomCenter) + .padding(bottom = 28.dp), + horizontalArrangement = Arrangement.SpaceEvenly, + verticalAlignment = Alignment.CenterVertically ) { - Image( - painter = painterResource(id = R.drawable.ic_custom_keyboard), - contentDescription = null, - modifier = Modifier.size(82.dp) + CustomButton( + onClick = { + TgApiManager.tgApi?.joinChat( + chatId = chatId, + reInit = { + notJoin = false + //reInit("joined") + } + ) + }, + text = stringResource(id = R.string.join_in) ) } - - IconButton( - onClick = { - sendCallback(inputText.text) - inputText = TextFieldValue("") - }, + } else { + Row( modifier = Modifier - .size(45.dp) + .fillMaxWidth() + .align(Alignment.BottomCenter) + .padding(bottom = 4.dp) + .alpha(1f), + horizontalArrangement = Arrangement.SpaceEvenly, + verticalAlignment = Alignment.CenterVertically ) { - Image( - painter = painterResource(id = R.drawable.ic_custom_send), - contentDescription = null, - modifier = Modifier.size(45.dp) - ) + IconButton( + onClick = { + textFieldFocusRequester.requestFocus() // 将焦点移动到隐藏的 TextField + keyboardController?.show() // 显示输入法 + }, + modifier = Modifier + .size(84.dp) + ) { + Image( + painter = painterResource(id = R.drawable.ic_custom_keyboard), + contentDescription = null, + modifier = Modifier.size(82.dp) + ) + } + + IconButton( + onClick = { + sendCallback(inputText.text) + inputText = TextFieldValue("") + }, + modifier = Modifier + .size(45.dp) + ) { + Image( + painter = painterResource(id = R.drawable.ic_custom_send), + contentDescription = null, + modifier = Modifier.size(45.dp) + ) + } } } } else { @@ -828,7 +868,8 @@ fun SplashChatScreenPreview() { chatObject = TdApi.Chat(), lastReadOutboxMessageId = mutableLongStateOf(0L), lastReadInboxMessageId = mutableLongStateOf(0L), - onLinkClick = {} + onLinkClick = {}, + reInit = {} ) } } diff --git a/app/src/main/java/com/gohj99/telewatch/ui/chat/LongPressBox.kt b/app/src/main/java/com/gohj99/telewatch/ui/chat/LongPressBox.kt index d0123cc..cca2a79 100644 --- a/app/src/main/java/com/gohj99/telewatch/ui/chat/LongPressBox.kt +++ b/app/src/main/java/com/gohj99/telewatch/ui/chat/LongPressBox.kt @@ -16,7 +16,9 @@ import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.foundation.verticalScroll import androidx.compose.material3.Text import androidx.compose.material3.TextField import androidx.compose.runtime.Composable @@ -37,6 +39,7 @@ import androidx.compose.ui.window.Dialog import com.gohj99.telewatch.R import com.gohj99.telewatch.ui.main.MainCard import com.gohj99.telewatch.ui.theme.TelewatchTheme +import com.gohj99.telewatch.ui.verticalRotaryScroll import kotlinx.coroutines.launch @Composable @@ -68,7 +71,12 @@ fun LongPressBox( .padding(16.dp), contentAlignment = Alignment.Center ) { - Column { + val scrollState = rememberScrollState() + Column( + modifier = Modifier + .verticalScroll(scrollState) + .verticalRotaryScroll(scrollState) + ) { LPMainCard( text = stringResource(id = R.string.DeleteMessage), callback = { diff --git a/app/src/main/java/com/gohj99/telewatch/ui/main/ItemsLazyColumn.kt b/app/src/main/java/com/gohj99/telewatch/ui/main/ItemsLazyColumn.kt index 63ddc54..a7b1184 100644 --- a/app/src/main/java/com/gohj99/telewatch/ui/main/ItemsLazyColumn.kt +++ b/app/src/main/java/com/gohj99/telewatch/ui/main/ItemsLazyColumn.kt @@ -273,31 +273,17 @@ fun ChatView( chatFolderInfo: TdApi.ChatFolder? = null, contactsSet: Set = emptySet(), // 确保类型为 Long includedChatIdsSet: Set = emptySet(), // 确保类型为 Long - excludedChatIdsSet: Set = emptySet() // 确保类型为 Long + excludedChatIdsSet: Set = emptySet(), // 确保类型为 Long + notJoin: Boolean = false ) { // 使用 derivedStateOf 来确保不必要的重渲染 val isMatchingSearchText by remember(searchText.value) { derivedStateOf { matchingString(searchText.value, chat.title) } } - if (chatFolderInfo == null) { - if (pinnedView == null) { - MainCard( - column = { - Text( - text = chat.title, - color = Color.White, - style = MaterialTheme.typography.titleMedium - ) - if (chat.message.isNotEmpty()) { - MessageView(message = chat.message) - } - }, - item = chat, - callback = { callback(chat) } - ) - } else { - if (chat.isPinned == pinnedView && isMatchingSearchText) { + if (isMatchingSearchText) { + if (chatFolderInfo == null) { + if (pinnedView == null) { MainCard( column = { Text( @@ -312,44 +298,61 @@ fun ChatView( item = chat, callback = { callback(chat) } ) + } else { + if (chat.isPinned == pinnedView) { + MainCard( + column = { + Text( + text = chat.title, + color = Color.White, + style = MaterialTheme.typography.titleMedium + ) + if (chat.message.isNotEmpty()) { + MessageView(message = chat.message) + } + }, + item = chat, + callback = { callback(chat) } + ) + } } - } - } else { - if (isMatchingSearchText && (chat.id in chatFolderInfo.pinnedChatIds.map { it } == pinnedView)) { + } else { + if ((chat.id in chatFolderInfo.pinnedChatIds.map { it } == pinnedView)) { - // 基于过滤条件设置显示会话 - val isShow by remember(chat.id, includedChatIdsSet, excludedChatIdsSet, contactsSet) { - derivedStateOf { - when { - chat.id in excludedChatIdsSet -> false - chat.id in includedChatIdsSet -> true - chat.isChannel && chatFolderInfo.includeChannels -> true - chat.isGroup && chatFolderInfo.includeGroups -> true - chat.isPrivateChat -> when { - chat.isBot -> chatFolderInfo.includeBots - chat.id in contactsSet -> chatFolderInfo.includeContacts - else -> chatFolderInfo.includeNonContacts + // 基于过滤条件设置显示会话 + val isShow by remember(chat.id, includedChatIdsSet, excludedChatIdsSet, contactsSet) { + derivedStateOf { + when { + chat.id in excludedChatIdsSet -> false + chat.id in includedChatIdsSet -> true + chat.isChannel && chatFolderInfo.includeChannels -> true + chat.isGroup && chatFolderInfo.includeGroups -> true + chat.isPrivateChat -> when { + chat.isBot -> chatFolderInfo.includeBots + chat.id in contactsSet -> chatFolderInfo.includeContacts + else -> chatFolderInfo.includeNonContacts + } + else -> false } - else -> false } } - } - if (isShow) { - MainCard( - column = { - Text( - text = chat.title, - color = Color.White, - style = MaterialTheme.typography.titleMedium - ) - if (chat.message.isNotEmpty()) { - MessageView(message = chat.message) - } - }, - item = chat, - callback = { callback(chat) } - ) + if (isShow) { + MainCard( + column = { + Text( + text = chat.title, + color = Color.White, + style = MaterialTheme.typography.titleMedium + ) + if (chat.message.isNotEmpty()) { + MessageView(message = chat.message) + } + }, + item = chat, + callback = { callback(chat) } + ) + } } } } diff --git a/app/src/main/java/com/gohj99/telewatch/ui/main/MainCard.kt b/app/src/main/java/com/gohj99/telewatch/ui/main/MainCard.kt index 3634da0..ad5bd7d 100644 --- a/app/src/main/java/com/gohj99/telewatch/ui/main/MainCard.kt +++ b/app/src/main/java/com/gohj99/telewatch/ui/main/MainCard.kt @@ -46,7 +46,7 @@ fun LinkText( // Append the link with a different style pushStringAnnotation(tag = "URL", annotation = result.value) - withStyle(style = SpanStyle(color = Color(0xFF66D3FE), textDecoration = TextDecoration.Underline)) { + withStyle(style = SpanStyle(color = Color(0xFF2397D3), textDecoration = TextDecoration.Underline)) { append(result.value) } pop() diff --git a/app/src/main/java/com/gohj99/telewatch/ui/main/MainScreen.kt b/app/src/main/java/com/gohj99/telewatch/ui/main/MainScreen.kt index e8998db..13276fd 100644 --- a/app/src/main/java/com/gohj99/telewatch/ui/main/MainScreen.kt +++ b/app/src/main/java/com/gohj99/telewatch/ui/main/MainScreen.kt @@ -55,11 +55,13 @@ fun MainScreen( topTitle: MutableState, chatsFoldersList: MutableState> ) { + val search = stringResource(id = R.string.Global_Search) val contact = stringResource(id = R.string.Contacts) val home = stringResource(id = R.string.HOME) val setting = stringResource(id = R.string.Settings) var showMenu by remember { mutableStateOf(false) } val lastPages = listOf( + search, contact, setting, ) @@ -147,6 +149,12 @@ fun MainScreen( ) } + search -> { + SearchLazyColumn( + callback = chatPage + ) + } + contact -> { ContactsLazyColumn( itemsList = contacts.value, diff --git a/app/src/main/java/com/gohj99/telewatch/ui/main/SearchScreen.kt b/app/src/main/java/com/gohj99/telewatch/ui/main/SearchScreen.kt new file mode 100644 index 0000000..ec610de --- /dev/null +++ b/app/src/main/java/com/gohj99/telewatch/ui/main/SearchScreen.kt @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2024 gohj99. Lorem ipsum dolor sit amet, consectetur adipiscing elit. + * Morbi non lorem porttitor neque feugiat blandit. Ut vitae ipsum eget quam lacinia accumsan. + * Etiam sed turpis ac ipsum condimentum fringilla. Maecenas magna. + * Proin dapibus sapien vel ante. Aliquam erat volutpat. Pellentesque sagittis ligula eget metus. + * Vestibulum commodo. Ut rhoncus gravida arcu. + */ + +package com.gohj99.telewatch.ui.main + +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.items +import androidx.compose.foundation.lazy.rememberLazyListState +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.saveable.rememberSaveable +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.dp +import com.gohj99.telewatch.R +import com.gohj99.telewatch.TgApiManager +import com.gohj99.telewatch.ui.SearchBar +import com.gohj99.telewatch.ui.verticalRotaryScroll + +@Composable +fun SearchLazyColumn(callback: (Chat) -> Unit) { + val listState = rememberLazyListState() + val searchText = rememberSaveable { mutableStateOf("") } + val searchList = rememberSaveable { mutableStateOf(listOf()) } + + LaunchedEffect(searchText.value) { + if (searchText.value != ""){ + TgApiManager.tgApi!!.searchPublicChat( + query = searchText.value, + searchList = searchList + ) + } + } + + LazyColumn( + state = listState, + modifier = Modifier + .fillMaxSize() + .padding(horizontal = 16.dp) + .verticalRotaryScroll(listState) + ) { + item { + Spacer(modifier = Modifier.height(8.dp)) + } + + item { + // 搜索框 + SearchBar( + query = searchText.value, + onQueryChange = { searchText.value = it }, + placeholder = stringResource(id = R.string.Search), + modifier = Modifier + ) + Spacer(modifier = Modifier.height(8.dp)) + } + + items(searchList.value, key = { it.id }) { item -> + ChatView(item, callback, searchText) + } + + item { + Spacer(modifier = Modifier.height(50.dp)) + } + } +} diff --git a/app/src/main/java/com/gohj99/telewatch/ui/setting/SettingLazyColumn.kt b/app/src/main/java/com/gohj99/telewatch/ui/setting/SettingLazyColumn.kt index 08ab87b..9a1c21a 100644 --- a/app/src/main/java/com/gohj99/telewatch/ui/setting/SettingLazyColumn.kt +++ b/app/src/main/java/com/gohj99/telewatch/ui/setting/SettingLazyColumn.kt @@ -210,6 +210,9 @@ fun SettingProgressBarView( onClick = { if (parameterValue > minValue) { parameterValue -= base + parameterValue = BigDecimal(parameterValue.toString()) + .setScale(decimalPlaces, RoundingMode.HALF_UP) + .toFloat() callback(parameterValue) } }, @@ -249,6 +252,9 @@ fun SettingProgressBarView( onClick = { if (parameterValue < maxValue) { parameterValue += base + parameterValue = BigDecimal(parameterValue.toString()) + .setScale(decimalPlaces, RoundingMode.HALF_UP) + .toFloat() callback(parameterValue) } }, diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index f232203..a400fbb 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -125,4 +125,8 @@ Don\'t remind me again Bekanntmachung Keine App, die diese URL verarbeiten kann + Globale Suche + Erinnerung zur Ankündigungsansicht + Für diese Funktion ist Zugriff auf den API-Server des Autors erforderlich + dazu kommen \ No newline at end of file diff --git a/app/src/main/res/values-eo/strings.xml b/app/src/main/res/values-eo/strings.xml index 6eadf61..e11a4cf 100644 --- a/app/src/main/res/values-eo/strings.xml +++ b/app/src/main/res/values-eo/strings.xml @@ -125,4 +125,8 @@ Ne rememorigu min Anonco Neniu aplikaĵo por trakti ĉi tiun URL + Tutmonda Serĉo + Anonco Vidi Rememorigilon + Ĉi tiu funkcio postulas aliron al la API-servilo de la aŭtoro + aliĝu \ No newline at end of file diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index cb122a6..6fcdbcf 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -125,4 +125,8 @@ Ne me le rappelle plus Annonce Aucune application pour gérer cette URL + Recherche globale + Annonce Voir Rappel + Cette fonctionnalité nécessite un accès au serveur API de l\'auteur + se joindre à \ No newline at end of file diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml index 63e4c93..6dd97bb 100644 --- a/app/src/main/res/values-ja/strings.xml +++ b/app/src/main/res/values-ja/strings.xml @@ -125,4 +125,8 @@ 二度と思い出さないでください 発表 この URL を処理するアプリはありません + グローバル検索 + お知らせのリマインダーを表示 + この機能には、作成者の API サーバーへのアクセスが必要です + 参加する \ No newline at end of file diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index ce8d89e..a6538cf 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -125,4 +125,8 @@ Не напоминай мне больше Объявление Нет приложения для обработки этого URL. + Глобальный поиск + Напоминание о просмотре объявления + Для этой функции требуется доступ к API-серверу автора. + присоединиться \ No newline at end of file diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index 8effa12..573dd02 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -125,4 +125,8 @@ 不要再提醒我 公告 没有应用程序可以处理此网址 + 全球搜索 + 公告查看提醒 + 此功能需要访问作者的 API 服务器 + 加入 \ No newline at end of file diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml index 62ad321..cf730e9 100644 --- a/app/src/main/res/values-zh-rTW/strings.xml +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -125,4 +125,8 @@ 不要再提醒我 公告 沒有應用程式可以處理此網址 + 全球搜尋 + 公告查看提醒 + 此功能需要存取作者的 API 伺服器 + 加入 \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index c77089e..45a1bcc 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -125,4 +125,8 @@ Don\'t remind me again Announcement No app to handle this url + Global Search + Announcement View Reminder + This feature requires access to the author\'s API server + join in \ No newline at end of file