| | |
| | | import android.annotation.SuppressLint |
| | | import android.app.Application |
| | | import android.app.PendingIntent |
| | | import android.bluetooth.BluetoothAdapter |
| | | import android.bluetooth.BluetoothDevice |
| | | import android.content.Context |
| | | import android.content.Intent |
| | | import android.content.IntentFilter |
| | | import android.location.Geocoder |
| | | import android.net.ConnectivityManager |
| | | import android.net.wifi.WifiManager |
| | | import android.os.Build |
| | | import androidx.lifecycle.MutableLiveData |
| | | import androidx.multidex.MultiDex |
| | |
| | | import com.gyf.cactus.callback.CactusCallback |
| | | import com.gyf.cactus.ext.cactus |
| | | import com.hjq.language.MultiLanguages |
| | | import com.hjq.language.OnLanguageListener |
| | | import com.example.firstapp.core.Core |
| | | import com.example.firstapp.database.repository.ReminderRepository |
| | | import com.example.firstapp.database.repository.CodeRepository |
| | | import com.example.firstapp.database.repository.KeywordRepository |
| | | import com.example.firstapp.database.repository.MsgRepository |
| | | import com.example.firstapp.database.service.RetrofitClient |
| | | import com.example.firstapp.receiver.CactusReceiver |
| | | import com.example.firstapp.service.BluetoothScanService |
| | | import com.example.firstapp.service.HttpServerService |
| | | import com.example.firstapp.utils.ACTION_START |
| | | import com.example.firstapp.utils.AppInfo |
| | | import com.example.firstapp.utils.CactusSave |
| | | import com.example.firstapp.utils.FRONT_CHANNEL_ID |
| | | import com.example.firstapp.utils.FRONT_CHANNEL_NAME |
| | | import com.example.firstapp.utils.FRONT_NOTIFY_ID |
| | | import com.example.firstapp.utils.FRPC_LIB_VERSION |
| | | import com.example.firstapp.utils.HistoryUtils |
| | | import com.example.firstapp.utils.Log |
| | | import com.example.firstapp.utils.SettingUtils |
| | | import com.example.firstapp.utils.SharedPreference |
| | | |
| | | import com.example.firstapp.utils.tinker.TinkerLoadLibrary |
| | | import com.king.location.LocationClient |
| | | import com.xuexiang.xutil.file.FileUtils |
| | | import frpclib.Frpclib |
| | | import io.reactivex.Observable |
| | | import io.reactivex.disposables.Disposable |
| | | import io.reactivex.schedulers.Schedulers |
| | | import kotlinx.coroutines.CoroutineScope |
| | | import kotlinx.coroutines.SupervisorJob |
| | | import java.io.BufferedWriter |
| | |
| | | import java.text.SimpleDateFormat |
| | | import java.util.Date |
| | | import java.util.Locale |
| | | import java.util.TimeZone |
| | | import java.util.concurrent.TimeUnit |
| | | |
| | | @Suppress("DEPRECATION") |
| | | class App : Application(), CactusCallback, Configuration.Provider by Core { |
| | |
| | | val database by lazy { AppDatabase.getInstance(this) } |
| | | val msgRepository by lazy { MsgRepository(database.msgDao()) } |
| | | val codeRepository by lazy { CodeRepository(database.codeDao()) } |
| | | val reminderRepository by lazy { ReminderRepository(database.reminderDao()) } |
| | | val keywordRepository by lazy { KeywordRepository(RetrofitClient.apiService,database.keywordDao()) } |
| | | |
| | | |
| | | companion object { |
| | | const val TAG: String = "SmsForwarder" |
| | | |
对比新文件 |
| | |
| | | import android.view.LayoutInflater |
| | | import android.view.ViewGroup |
| | | import androidx.recyclerview.widget.DiffUtil |
| | | import androidx.recyclerview.widget.ListAdapter |
| | | import androidx.recyclerview.widget.RecyclerView |
| | | import com.example.firstapp.database.entity.Reminder |
| | | import com.example.firstapp.databinding.ItemReminderBinding |
| | | import com.sun.mail.imap.protocol.FetchResponse.getItem |
| | | |
| | | class ReminderAdapter(private val onDelete: (Reminder) -> Unit) : |
| | | ListAdapter<Reminder, ReminderAdapter.ReminderViewHolder>(ReminderDiffCallback()) { |
| | | |
| | | class ReminderViewHolder(private val binding: ItemReminderBinding) : |
| | | RecyclerView.ViewHolder(binding.root) { |
| | | |
| | | fun bind(reminder: Reminder, onDelete: (Reminder) -> Unit) { |
| | | binding.textNickname.text = reminder.nickname |
| | | binding.textKeywords.text = reminder.keywords |
| | | binding.btnDelete.setOnClickListener { onDelete(reminder) } |
| | | } |
| | | } |
| | | |
| | | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ReminderViewHolder { |
| | | return ReminderViewHolder( |
| | | ItemReminderBinding.inflate( |
| | | LayoutInflater.from(parent.context), parent, false |
| | | ) |
| | | ) |
| | | } |
| | | |
| | | override fun onBindViewHolder(holder: ReminderViewHolder, position: Int) { |
| | | holder.bind(getItem(position), onDelete) |
| | | } |
| | | } |
| | | |
| | | class ReminderDiffCallback : DiffUtil.ItemCallback<Reminder>() { |
| | | override fun areItemsTheSame(oldItem: Reminder, newItem: Reminder) = oldItem.id == newItem.id |
| | | override fun areContentsTheSame(oldItem: Reminder, newItem: Reminder) = oldItem == newItem |
| | | } |
| | |
| | | import com.example.firstapp.database.repository.CodeRepository |
| | | import com.example.firstapp.database.repository.KeywordRepository |
| | | import com.example.firstapp.database.repository.MsgRepository |
| | | import com.example.firstapp.database.repository.ReminderRepository |
| | | |
| | | import kotlinx.coroutines.launch |
| | | |
| | |
| | | val msg: MsgRepository by lazy { (app as App).msgRepository } |
| | | val code: CodeRepository by lazy { (app as App).codeRepository } |
| | | val keyword: KeywordRepository by lazy { (app as App).keywordRepository } |
| | | val reminder: ReminderRepository by lazy { (app as App).reminderRepository } |
| | | |
| | | fun init(app: Application) { |
| | | this.app = app |
| | |
| | | package com.example.firstapp |
| | | |
| | | |
| | | import android.content.Context |
| | | import androidx.room.Database |
| | | import androidx.room.Room |
| | |
| | | import com.example.firstapp.database.dao.CodeDao |
| | | import com.example.firstapp.database.dao.KeywordDao |
| | | import com.example.firstapp.database.dao.MsgDao |
| | | import com.example.firstapp.database.dao.ReminderDao |
| | | import com.example.firstapp.database.entity.Code |
| | | import com.example.firstapp.database.entity.KeywordEntity |
| | | import com.example.firstapp.database.entity.Msg |
| | | import com.example.firstapp.database.entity.Reminder |
| | | import com.example.firstapp.utils.DATABASE_NAME |
| | | import com.example.firstapp.utils.SettingUtils |
| | | import com.example.firstapp.utils.TAG_LIST |
| | |
| | | |
| | | |
| | | @Database( |
| | | entities = [ Msg::class, Code::class, KeywordEntity::class], |
| | | // views = [LogsDetail::class], |
| | | entities = [ Msg::class, Code::class, KeywordEntity::class, Reminder::class], |
| | | version = 20, |
| | | exportSchema = false |
| | | ) |
| | |
| | | abstract fun msgDao(): MsgDao |
| | | abstract fun codeDao(): CodeDao |
| | | abstract fun keywordDao(): KeywordDao |
| | | abstract fun reminderDao(): ReminderDao |
| | | |
| | | companion object { |
| | | @Volatile |
| | |
| | | `isEnabled` INTEGER NOT NULL |
| | | ) |
| | | """) |
| | | // database.execSQL(""" |
| | | // CREATE TABLE IF NOT EXISTS `reminders` ( |
| | | // id INTEGER PRIMARY KEY AUTOINCREMENT, |
| | | // type TEXT NOT NULL, |
| | | // nickname TEXT NOT NULL, |
| | | // keywords TEXT NOT NULL, |
| | | // ); |
| | | // """) |
| | | |
| | | } |
| | | } |
| | |
| | | import com.example.firstapp.database.entity.KeywordConfig |
| | | import com.example.firstapp.database.entity.KeywordEntity |
| | | |
| | | @Dao |
| | | interface KeywordDao { |
| | | @Query("SELECT * FROM keywords") |
| | | fun getAllKeywords(): List<KeywordEntity> |
| | | |
| | | //@Dao |
| | | //interface KeywordDao { |
| | | // @Query("SELECT * FROM keywords") |
| | | // fun getAllKeywords(): List<KeywordEntity> |
| | | // |
| | | // @Insert(onConflict = OnConflictStrategy.REPLACE) |
| | | // suspend fun insertAll(keywords: List<KeywordEntity>) |
| | | // |
| | | // @Query("DELETE FROM keywords") |
| | | // suspend fun deleteAll() |
| | | // |
| | | // @Update |
| | | // suspend fun update(keyword: KeywordEntity) |
| | | // |
| | | // @Query("SELECT * FROM keywords WHERE isEnabled = 1") |
| | | // fun getEnabledKeywords(): List<KeywordConfig> |
| | | //// |
| | | //// @Query("DELETE FROM keywords") |
| | | //// suspend fun deleteAll() |
| | | //// |
| | | //// @Update |
| | | //// suspend fun update(keyword: KeywordEntity) |
| | | //// |
| | | //// @Query("SELECT * FROM keywords WHERE isEnabled = 1") |
| | | //// fun getEnabledKeywords(): List<KeywordConfig> |
| | | //} |
| | | @Dao |
| | | interface KeywordDao { |
| | | @Insert(onConflict = OnConflictStrategy.REPLACE) |
| | | fun insertAll(keywords: List<KeywordEntity>) |
| | | |
| | | @Query("SELECT * FROM keywords") |
| | | fun getAllKeywords(): List<KeywordEntity> |
| | | } |
对比新文件 |
| | |
| | | package com.example.firstapp.database.dao |
| | | import androidx.room.* |
| | | import com.example.firstapp.database.entity.Reminder |
| | | import kotlinx.coroutines.flow.Flow |
| | | |
| | | @Dao |
| | | interface ReminderDao { |
| | | |
| | | @Query("SELECT * FROM reminders ORDER BY type") |
| | | fun getAllReminders(): Flow<List<Reminder>> |
| | | |
| | | @Insert |
| | | fun insert(reminder: Reminder) |
| | | |
| | | @Delete |
| | | fun delete(reminder: Reminder) |
| | | } |
| | |
| | | val type: String, |
| | | val keyword: String, |
| | | val isEnable: Boolean |
| | | ){ |
| | | fun toEntity(): KeywordEntity { |
| | | return KeywordEntity( |
| | | id = id, // 确保与@Entity类字段匹配 |
| | | type = type, |
| | | keyword = keyword, |
| | | isEnabled = isEnable // 注意字段名是否一致(isEnabled vs isEnable) |
| | | ) |
| | | } |
| | | } |
对比新文件 |
| | |
| | | package com.example.firstapp.database.entity |
| | | |
| | | import androidx.room.Entity |
| | | import androidx.room.PrimaryKey |
| | | |
| | | |
| | | @Entity(tableName = "reminders") |
| | | data class Reminder( |
| | | @PrimaryKey(autoGenerate = true) val id: Long = 0, |
| | | val type: String, |
| | | val nickname: String, |
| | | val keywords: String |
| | | ) |
| | |
| | | if (response.status == 1) { |
| | | // 保存到本地数据库作为缓存 |
| | | saveToLocal(response.data) |
| | | response.data |
| | | keywordDao.getAllKeywords() |
| | | } else { |
| | | // 如果接口请求失败,使用本地缓存 |
| | | keywordDao.getAllKeywords() |
| | |
| | | } |
| | | } |
| | | |
| | | private suspend fun saveToLocal(keywords: List<KeywordEntity>) { |
| | | true |
| | | //keywordDao.insertAll(keywords.map { it.toEntity() }) |
| | | private suspend fun saveToLocal(keywords: List<KeywordConfig>) { |
| | | // keywords.map { it.toEntity() } |
| | | // keywordDao.insertAll(keywords) |
| | | val keywordEntities = keywords.map { it.toEntity() } |
| | | keywordDao.insertAll(keywordEntities) |
| | | } |
| | | |
| | | } |
| | | |
对比新文件 |
| | |
| | | package com.example.firstapp.database.repository |
| | | |
| | | import com.example.firstapp.database.dao.ReminderDao |
| | | import androidx.annotation.WorkerThread |
| | | import com.example.firstapp.database.entity.Reminder |
| | | import kotlinx.coroutines.flow.Flow |
| | | |
| | | class ReminderRepository(private val reminderDao: ReminderDao) { |
| | | |
| | | val allReminders: Flow<List<Reminder>> = reminderDao.getAllReminders() |
| | | |
| | | @WorkerThread |
| | | fun insert(reminder: Reminder) { |
| | | reminderDao.insert(reminder) |
| | | } |
| | | |
| | | @WorkerThread |
| | | fun delete(reminder: Reminder) { |
| | | reminderDao.delete(reminder) |
| | | } |
| | | } |
| | |
| | | interface ApiService { |
| | | |
| | | @GET("keywords") |
| | | suspend fun getKeywords():ApiResponse<List<KeywordEntity>> //异步挂起 |
| | | suspend fun getKeywords():ApiResponse<List<KeywordConfig>> //异步挂起 |
| | | } |
| | | |
| | | // 创建Retrofit实例(单例) |
| | |
| | | Log.d("SmsReceiver", "Received SMS msgId: ${msgId}") |
| | | |
| | | // 这里我要写个数组,并创建个对象存放一些内容,如这个对象的属性有匹配内容,正则表达式,并循环遍历 |
| | | val ruleList = listOf( |
| | | val ruleList = mutableListOf( |
| | | Rule("快递","京东","\\d{6}"), |
| | | Rule("快递","菜鸟驿站","\\d{1,2}-\\d{1,2}-\\d{4}") |
| | | ) |
| | |
| | | // 获取最新的关键词配置 |
| | | val keywords = Core.keyword.getKeywords() |
| | | Log.d("keywords", keywords.toString()) |
| | | println(keywords) |
| | | // 保存匹配的短信 |
| | | //saveMessage(content) |
| | | keywords.forEach { keyword -> |
| | | ruleList.add( |
| | | Rule( |
| | | keyword.type, |
| | | keyword.keyword, |
| | | "\\d{1,2}-\\d{1,2}-\\d{4}" |
| | | ) |
| | | ) |
| | | } |
| | | |
| | | |
| | | // kotlin 怎么创建一个类 |
| | | Log.d("RuleList", ruleList.toString()) |
| | | for (rule in ruleList) { |
| | | val code = rule.extractCodeFromMessage(messageBody.toString()) |
| | | |
| | |
| | | Log.d("SmsReceiver", "Received SMS code: 没有匹配到内容") |
| | | } |
| | | } |
| | | } |
| | | |
| | | |
| | | // kotlin 怎么创建一个类 |
| | | // for (rule in ruleList) { |
| | | // val code = rule.extractCodeFromMessage(messageBody.toString()) |
| | | // |
| | | // if (code!==null) { |
| | | // Log.d("SmsReceiver", "Received SMS code: ${code}") |
| | | // |
| | | // |
| | | // // 获取当前时间 |
| | | // val currentTime = LocalDateTime.now() |
| | | // // 加2小时 |
| | | // val futureTime = currentTime.plusHours(2) |
| | | // // 定义时间格式 |
| | | // val formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss") |
| | | // // 转换为字符串 |
| | | // val overtime = futureTime.format(formatter) |
| | | // // 封装成一个Code对象,并保存在数据库中 |
| | | // val code = Code(0, rule.type,1, rule.content,1, 1, msgId, code, overtime) |
| | | // Core.code.insert(code) |
| | | // Log.d("SMS_DEBUG", "新短信已保存到数据库") |
| | | // // 发送广播通知数据已更新 |
| | | // //"com.example.firstapp.DATA_UPDATED" 是一个自定义的广播 Action,相当于一个标识符或者说是一个频道名称。这个名称是我们自己定义的,通常使用应用的包名作为前缀,以避免与其他应用的广播冲突。 |
| | | // val updateIntent = Intent("com.example.firstapp.DATA_UPDATED") |
| | | // context.sendBroadcast(updateIntent) |
| | | // Log.d("SMS_DEBUG", "发送数据更新广播") |
| | | // }else{ |
| | | // Log.d("SmsReceiver", "Received SMS code: 没有匹配到内容") |
| | | // } |
| | | // } |
| | | |
| | | } |
| | | } |
| | |
| | | package com.example.firstapp.ui.reminder |
| | | |
| | | import ReminderAdapter |
| | | import android.os.Bundle |
| | | import android.view.LayoutInflater |
| | | import android.view.View |
| | | import android.view.ViewGroup |
| | | import android.widget.ArrayAdapter |
| | | import android.widget.Toast |
| | | import androidx.fragment.app.Fragment |
| | | import androidx.fragment.app.viewModels |
| | | import androidx.navigation.fragment.findNavController |
| | | import androidx.recyclerview.widget.LinearLayoutManager |
| | | import com.example.firstapp.App |
| | | import com.example.firstapp.database.entity.Reminder |
| | | import com.example.firstapp.databinding.FragmentReminderSettingsBinding |
| | | |
| | | class ReminderSettingsFragment : Fragment() { |
| | | |
| | | private var _binding: FragmentReminderSettingsBinding? = null |
| | | private val binding get() = _binding!! |
| | | |
| | | private val reminderViewModel: ReminderViewModel by viewModels { |
| | | ReminderViewModelFactory((requireActivity().application as App).reminderRepository) |
| | | } |
| | | |
| | | private lateinit var adapter: ReminderAdapter |
| | | |
| | | override fun onCreateView( |
| | | inflater: LayoutInflater, |
| | |
| | | override fun onViewCreated(view: View, savedInstanceState: Bundle?) { |
| | | super.onViewCreated(view, savedInstanceState) |
| | | |
| | | // 返回按钮点击事件 |
| | | binding.btnBack.setOnClickListener { |
| | | setupSpinner() |
| | | setupRecyclerView() |
| | | setupClickListeners() |
| | | observeReminders() |
| | | } |
| | | |
| | | private fun setupSpinner() { |
| | | val types = arrayOf("驿站", "财务", "其他") |
| | | val adapter = ArrayAdapter(requireContext(), android.R.layout.simple_spinner_item, types) |
| | | adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item) |
| | | binding.spinnerType.adapter = adapter |
| | | } |
| | | |
| | | private fun setupRecyclerView() { |
| | | adapter = ReminderAdapter { reminder -> |
| | | reminderViewModel.deleteReminder(reminder) |
| | | } |
| | | binding.recyclerReminders.apply { |
| | | layoutManager = LinearLayoutManager(context) |
| | | this.adapter = this@ReminderSettingsFragment.adapter |
| | | } |
| | | } |
| | | |
| | | private fun setupClickListeners() { |
| | | binding.btnClose.setOnClickListener { |
| | | findNavController().navigateUp() |
| | | } |
| | | |
| | | // 添加提醒按钮点击事件 |
| | | binding.btnAddReminder.setOnClickListener { |
| | | val reminderText = binding.editQuickReminder.text.toString() |
| | | if (reminderText.isNotEmpty()) { |
| | | // TODO: 保存提醒到数据库 |
| | | Toast.makeText(context, "提醒已添加", Toast.LENGTH_SHORT).show() |
| | | binding.editQuickReminder.text.clear() |
| | | } else { |
| | | Toast.makeText(context, "请输入提醒内容", Toast.LENGTH_SHORT).show() |
| | | val type = binding.spinnerType.selectedItem.toString() |
| | | val nickname = binding.editNickname.text.toString() |
| | | val keywords = binding.editKeywords.text.toString() |
| | | |
| | | if (nickname.isBlank() || keywords.isBlank()) { |
| | | Toast.makeText(context, "请填写完整信息", Toast.LENGTH_SHORT).show() |
| | | return@setOnClickListener |
| | | } |
| | | |
| | | reminderViewModel.insertReminder( |
| | | Reminder( |
| | | type = type, |
| | | nickname = nickname, |
| | | keywords = keywords |
| | | ) |
| | | ) |
| | | |
| | | binding.editNickname.text.clear() |
| | | binding.editKeywords.text.clear() |
| | | } |
| | | } |
| | | |
| | | private fun observeReminders() { |
| | | reminderViewModel.allReminders.observe(viewLifecycleOwner) { reminders -> |
| | | adapter.submitList(reminders) |
| | | } |
| | | } |
| | | |
对比新文件 |
| | |
| | | package com.example.firstapp.ui.reminder |
| | | |
| | | import androidx.lifecycle.* |
| | | import com.example.firstapp.database.entity.Reminder |
| | | import com.example.firstapp.database.repository.ReminderRepository |
| | | import kotlinx.coroutines.launch |
| | | |
| | | class ReminderViewModel(private val repository: ReminderRepository) : ViewModel() { |
| | | |
| | | // 使用 Flow 获取所有提醒 |
| | | val allReminders: LiveData<List<Reminder>> = repository.allReminders.asLiveData() |
| | | |
| | | // 插入新提醒 |
| | | fun insertReminder(reminder: Reminder) = viewModelScope.launch { |
| | | repository.insert(reminder) |
| | | } |
| | | |
| | | // 删除提醒 |
| | | fun deleteReminder(reminder: Reminder) = viewModelScope.launch { |
| | | repository.delete(reminder) |
| | | } |
| | | } |
| | | |
| | | // ViewModel Factory |
| | | class ReminderViewModelFactory(private val repository: ReminderRepository) : ViewModelProvider.Factory { |
| | | override fun <T : ViewModel> create(modelClass: Class<T>): T { |
| | | if (modelClass.isAssignableFrom(ReminderViewModel::class.java)) { |
| | | @Suppress("UNCHECKED_CAST") |
| | | return ReminderViewModel(repository) as T |
| | | } |
| | | throw IllegalArgumentException("Unknown ViewModel class") |
| | | } |
| | | } |
| | |
| | | <RelativeLayout |
| | | android:layout_width="match_parent" |
| | | android:layout_height="?attr/actionBarSize" |
| | | android:background="#FFFFFF" |
| | | android:elevation="4dp"> |
| | | |
| | | <!-- 返回按钮 --> |
| | | <ImageButton |
| | | android:id="@+id/btn_back" |
| | | android:layout_width="48dp" |
| | | android:layout_height="48dp" |
| | | android:layout_centerVertical="true" |
| | | android:background="?attr/selectableItemBackgroundBorderless" |
| | | android:src="@android:drawable/ic_menu_close_clear_cancel" |
| | | android:contentDescription="返回" /> |
| | | android:background="#FFFFFF"> |
| | | |
| | | <TextView |
| | | android:layout_width="wrap_content" |
| | | android:layout_height="wrap_content" |
| | | android:layout_centerInParent="true" |
| | | android:text="标题" |
| | | android:text="新增短信提醒" |
| | | android:textSize="18sp" |
| | | android:textColor="#000000" /> |
| | | |
| | | <!-- 关闭按钮 --> |
| | | <ImageButton |
| | | android:id="@+id/btn_close" |
| | | android:layout_width="48dp" |
| | | android:layout_height="48dp" |
| | | android:layout_alignParentEnd="true" |
| | | android:layout_centerVertical="true" |
| | | android:background="?attr/selectableItemBackgroundBorderless" |
| | | android:src="@android:drawable/ic_menu_close_clear_cancel" /> |
| | | </RelativeLayout> |
| | | |
| | | <!-- 快速提醒输入框 --> |
| | | <EditText |
| | | android:id="@+id/edit_quick_reminder" |
| | | <!-- 提醒类型选择 --> |
| | | <Spinner |
| | | android:id="@+id/spinner_type" |
| | | android:layout_width="match_parent" |
| | | android:layout_height="wrap_content" |
| | | android:layout_margin="16dp" |
| | | android:background="@android:drawable/edit_text" |
| | | android:hint="快速提醒" |
| | | android:padding="12dp" /> |
| | | android:padding="12dp" |
| | | android:background="@android:drawable/btn_dropdown" /> |
| | | |
| | | <!-- 添加提醒按钮 --> |
| | | <!-- 昵称输入框 --> |
| | | <EditText |
| | | android:id="@+id/edit_nickname" |
| | | android:layout_width="match_parent" |
| | | android:layout_height="wrap_content" |
| | | android:layout_marginHorizontal="16dp" |
| | | android:hint="昵称" |
| | | android:padding="12dp" |
| | | android:background="@android:drawable/edit_text" /> |
| | | |
| | | <!-- 关键词输入框 --> |
| | | <EditText |
| | | android:id="@+id/edit_keywords" |
| | | android:layout_width="match_parent" |
| | | android:layout_height="wrap_content" |
| | | android:layout_margin="16dp" |
| | | android:hint="关键词" |
| | | android:padding="12dp" |
| | | android:background="@android:drawable/edit_text" /> |
| | | |
| | | <!-- 已添加列表标题 --> |
| | | <Button |
| | | android:id="@+id/btn_add_reminder" |
| | | android:layout_width="match_parent" |
| | | android:layout_height="wrap_content" |
| | | android:layout_marginHorizontal="16dp" |
| | | android:layout_marginTop="16dp" |
| | | android:layout_margin="16dp" |
| | | android:backgroundTint="#03A9F4" |
| | | android:text="添加到提醒" |
| | | android:text="确定新增" |
| | | android:textColor="#FFFFFF" /> |
| | | |
| | | <TextView |
| | | android:layout_width="match_parent" |
| | | android:layout_height="wrap_content" |
| | | android:padding="16dp" |
| | | android:text="已添加列表" |
| | | android:textStyle="bold" /> |
| | | |
| | | <!-- 已添加列表 --> |
| | | <androidx.recyclerview.widget.RecyclerView |
| | | android:id="@+id/recycler_reminders" |
| | | android:layout_width="match_parent" |
| | | android:layout_height="221dp" |
| | | android:layout_weight="1" |
| | | android:padding="8dp" /> |
| | | |
| | | <!-- 确定新增按钮 --> |
| | | |
| | | </LinearLayout> |
对比新文件 |
| | |
| | | <?xml version="1.0" encoding="utf-8"?> |
| | | <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" |
| | | android:layout_width="match_parent" |
| | | android:layout_height="wrap_content" |
| | | android:padding="12dp" |
| | | android:background="@android:color/white"> |
| | | |
| | | <LinearLayout |
| | | android:layout_width="match_parent" |
| | | android:layout_height="wrap_content" |
| | | android:layout_toStartOf="@id/btn_delete" |
| | | android:orientation="vertical"> |
| | | |
| | | <TextView |
| | | android:id="@+id/text_nickname" |
| | | android:layout_width="wrap_content" |
| | | android:layout_height="wrap_content" |
| | | android:textSize="16sp" |
| | | android:textColor="#000000" /> |
| | | |
| | | <TextView |
| | | android:id="@+id/text_keywords" |
| | | android:layout_width="wrap_content" |
| | | android:layout_height="wrap_content" |
| | | android:layout_marginTop="4dp" |
| | | android:textSize="14sp" |
| | | android:textColor="#666666" /> |
| | | </LinearLayout> |
| | | |
| | | <ImageButton |
| | | android:id="@+id/btn_delete" |
| | | android:layout_width="24dp" |
| | | android:layout_height="24dp" |
| | | android:layout_alignParentEnd="true" |
| | | android:layout_centerVertical="true" |
| | | android:background="@null" |
| | | android:src="@android:drawable/ic_delete" /> |
| | | |
| | | </RelativeLayout> |