diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 2051a5d..e80cc69 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -25,6 +25,9 @@
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.DefenseApplication">
+
diff --git a/app/src/main/java/com/example/defenseapplication/adapter/LinkedUserAdapter.kt b/app/src/main/java/com/example/defenseapplication/adapter/LinkedUserAdapter.kt
index 3820287..49d3e03 100644
--- a/app/src/main/java/com/example/defenseapplication/adapter/LinkedUserAdapter.kt
+++ b/app/src/main/java/com/example/defenseapplication/adapter/LinkedUserAdapter.kt
@@ -14,6 +14,7 @@ data class LinkedUser(
)
class LinkedUserAdapter(
+ private val deleteText: String,
private val onItemClick: (LinkedUser, Int) -> Unit,
private val onDeleteClick: (LinkedUser, Int) -> Unit
) : RecyclerView.Adapter() {
@@ -43,6 +44,7 @@ class LinkedUserAdapter(
}
override fun onBindViewHolder(holder: LinkedUserViewHolder, position: Int) {
+
holder.bind(items[position], position)
}
@@ -58,7 +60,8 @@ class LinkedUserAdapter(
binding.tvPhone.text = "手机号码:${item.phone}"
binding.tvIdCard.text = "身份证号:${item.idCard}"
binding.tvTime.text = item.time
-
+ //设置删除按钮的文字
+ binding.tvDeleteAction.text = deleteText
binding.llContent.setOnClickListener {
onItemClick(item, position)
}
diff --git a/app/src/main/java/com/example/defenseapplication/home/PersonalFragment.kt b/app/src/main/java/com/example/defenseapplication/home/PersonalFragment.kt
index a74256a..78a85d7 100644
--- a/app/src/main/java/com/example/defenseapplication/home/PersonalFragment.kt
+++ b/app/src/main/java/com/example/defenseapplication/home/PersonalFragment.kt
@@ -50,10 +50,13 @@ class PersonalFragment : Fragment() {
binding.itemSwitchFamily.setOnClickListener {
showFamilySwitchDialog()
}
+ //用户管理点击事件跳转关联用户页面
binding.itemUserManage.setOnClickListener {
- val intent= Intent(requireContext(), LinkedUserActivity::class.java)
+ val intent = Intent(requireContext(), LinkedUserActivity::class.java)
+ intent.putExtra(LinkedUserActivity.EXTRA_MODE, LinkedUserActivity.MODE_PERSONAL)
startActivity(intent)
}
+ // 密码管理点击事件
binding.itemPwdManage.setOnClickListener {
val intent= Intent(requireContext(), PasswordManagementActivity::class.java)
startActivity(intent)
diff --git a/app/src/main/java/com/example/defenseapplication/liveVideo/LinkedUserActivity.kt b/app/src/main/java/com/example/defenseapplication/liveVideo/LinkedUserActivity.kt
index 8d4387f..ae260ac 100644
--- a/app/src/main/java/com/example/defenseapplication/liveVideo/LinkedUserActivity.kt
+++ b/app/src/main/java/com/example/defenseapplication/liveVideo/LinkedUserActivity.kt
@@ -2,6 +2,7 @@ package com.example.defenseapplication.liveVideo
import android.content.Intent
import android.os.Bundle
+import android.view.View
import androidx.appcompat.app.AppCompatActivity
import androidx.recyclerview.widget.ItemTouchHelper
import androidx.recyclerview.widget.LinearLayoutManager
@@ -18,10 +19,14 @@ class LinkedUserActivity : AppCompatActivity() {
private lateinit var binding: LinkedUserActivityBinding
private lateinit var adapter: LinkedUserAdapter
private val userList = mutableListOf()
+ private var mode: Int = MODE_SETTINGS
companion object {
const val REQUEST_CODE_SEARCH = 1001
const val EXTRA_SEARCH_RESULT = "search_result"
+ const val EXTRA_MODE = "extra_mode"
+ const val MODE_SETTINGS = 0
+ const val MODE_PERSONAL = 1
}
override fun onCreate(savedInstanceState: Bundle?) {
@@ -29,6 +34,8 @@ class LinkedUserActivity : AppCompatActivity() {
binding = LinkedUserActivityBinding.inflate(layoutInflater)
setContentView(binding.root)
+ mode = intent.getIntExtra(EXTRA_MODE, MODE_SETTINGS)
+
ImmersionBar.with(this)
.statusBarDarkFont(true)
.titleBar(binding.topBar)
@@ -37,10 +44,13 @@ class LinkedUserActivity : AppCompatActivity() {
initView()
initData()
initListener()
+ setupModeUI()
}
private fun initView() {
+ val deleteText = if (mode == MODE_SETTINGS) getString(R.string.unlink) else getString(R.string.delete)
adapter = LinkedUserAdapter(
+ deleteText = deleteText,
onItemClick = { user, position ->
val intent = Intent(this, UserDetailsActivity::class.java).apply {
putExtra("name", user.name)
@@ -131,11 +141,16 @@ class LinkedUserActivity : AppCompatActivity() {
currentSwipeHeld = true
val dialog = CustomDialogFragmentText()
- dialog.setTitle("解除关联")
- dialog.setMessage("确定要解除与 ${user.name} 的关联吗?")
+ if (mode == MODE_SETTINGS) {
+ dialog.setTitle(getString(R.string.tip))
+ dialog.setMessage(getString(R.string.unlink_confirm_message))
+ } else {
+ dialog.setTitle(getString(R.string.tip))
+ dialog.setMessage(getString(R.string.confirm_delete_user))
+ }
dialog.setShowInput(false)
- dialog.setPositiveText("确定")
- dialog.setNegativeText("取消")
+ dialog.setPositiveText(getString(R.string.confirm))
+ dialog.setNegativeText(getString(R.string.cancel))
dialog.setOnConfirmListener {
userList.removeAt(position)
adapter.removeItem(position)
@@ -185,6 +200,21 @@ class LinkedUserActivity : AppCompatActivity() {
val intent = Intent(this, AddLinkedUserActivity::class.java)
startActivity(intent)
}
+
+ binding.fabAdd.setOnClickListener {
+ val intent = Intent(this, com.example.defenseapplication.personal.InvitationCodeActivity::class.java)
+ startActivity(intent)
+ }
+ }
+
+ private fun setupModeUI() {
+ if (mode == MODE_SETTINGS) {
+ binding.btnAddLinkedUser.visibility = View.VISIBLE
+ binding.fabAdd.visibility = View.GONE
+ } else {
+ binding.btnAddLinkedUser.visibility = View.GONE
+ binding.fabAdd.visibility = View.VISIBLE
+ }
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
diff --git a/app/src/main/java/com/example/defenseapplication/liveVideo/SettingsActivity.kt b/app/src/main/java/com/example/defenseapplication/liveVideo/SettingsActivity.kt
index 00bd7b4..2d40e8f 100644
--- a/app/src/main/java/com/example/defenseapplication/liveVideo/SettingsActivity.kt
+++ b/app/src/main/java/com/example/defenseapplication/liveVideo/SettingsActivity.kt
@@ -74,9 +74,11 @@ class SettingsActivity : BaseActivity() {
val intent = Intent(this, DeviceInfoActivity::class.java)
startActivity(intent)
}
+ // 关联用户
binding.itemRelatedUsers.setOnClickListener {
val intent = Intent(this, LinkedUserActivity::class.java)
- startActivity( intent)
+ intent.putExtra(LinkedUserActivity.EXTRA_MODE, LinkedUserActivity.MODE_SETTINGS)
+ startActivity( intent)
}
binding.itemWifiManage.setOnClickListener {
val intent = Intent(this, WiFiManagementActivity::class.java)
diff --git a/app/src/main/java/com/example/defenseapplication/personal/InvitationCodeActivity.kt b/app/src/main/java/com/example/defenseapplication/personal/InvitationCodeActivity.kt
new file mode 100644
index 0000000..08201ff
--- /dev/null
+++ b/app/src/main/java/com/example/defenseapplication/personal/InvitationCodeActivity.kt
@@ -0,0 +1,191 @@
+package com.example.defenseapplication.personal
+
+import android.graphics.Bitmap
+import android.graphics.Canvas
+import android.graphics.Color
+import android.graphics.Paint
+import android.os.Bundle
+
+import android.view.LayoutInflater
+import android.view.View
+import android.widget.RadioButton
+import android.widget.RadioGroup
+import androidx.appcompat.app.AppCompatActivity
+import com.google.android.material.bottomsheet.BottomSheetDialog
+import androidx.core.content.ContextCompat
+import com.example.defenseapplication.R
+import com.example.defenseapplication.databinding.DialogExpireTimeBinding
+import com.example.defenseapplication.databinding.InvitationCodeActivityBinding
+import com.google.zxing.BarcodeFormat
+import com.google.zxing.EncodeHintType
+import com.google.zxing.qrcode.QRCodeWriter
+import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel
+import com.gyf.immersionbar.ImmersionBar
+import java.util.Hashtable
+
+//邀请码页面
+class InvitationCodeActivity : AppCompatActivity() {
+
+ private lateinit var binding: InvitationCodeActivityBinding
+ private var expireTimeInMillis: Long = 24 * 60 * 60 * 1000 // 默认24小时
+ private var selectedExpireOption: Int = 0 // 0: 24h, 1: 7d,默认选中24h
+
+ companion object {
+ const val EXPIRE_24H = 24 * 60 * 60 * 1000L
+ const val EXPIRE_7D = 7 * 24 * 60 * 60 * 1000L
+ }
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ binding = InvitationCodeActivityBinding.inflate(layoutInflater)
+ setContentView(binding.root)
+
+ ImmersionBar.with(this)
+ .statusBarDarkFont(true)
+ .titleBar(binding.topBar)
+ .init()
+
+ initListener()
+ // 默认显示时效为24h
+ binding.tvExpireTime.text = getString(R.string.expire_24h)
+ // 默认显示灰色占位区域,二维码不可见
+ hideQrCode()
+ }
+
+ private fun initListener() {
+ binding.ivBack.setOnClickListener {
+ finish()
+ }
+
+ binding.llExpireTime.setOnClickListener {
+ showExpireTimeDialog()
+ }
+
+ binding.llWechatShare.setOnClickListener {
+ // 微信分享功能
+ shareToWeChat()
+ }
+ }
+
+ private fun showExpireTimeDialog() {
+ val dialogBinding = DialogExpireTimeBinding.inflate(LayoutInflater.from(this))
+
+ val dialog = BottomSheetDialog(this, R.style.BottomSheetDialog)
+ dialog.setContentView(dialogBinding.root)
+
+ // 设置选中状态
+ when (selectedExpireOption) {
+ 0 -> dialogBinding.rb24h.isChecked = true
+ 1 -> dialogBinding.rb7d.isChecked = true
+ }
+
+ dialogBinding.radioGroup.setOnCheckedChangeListener { _, checkedId ->
+ when (checkedId) {
+ R.id.rb24h -> selectedExpireOption = 0
+ R.id.rb7d -> selectedExpireOption = 1
+ }
+ }
+
+ dialogBinding.tvCancel.setOnClickListener {
+ dialog.dismiss()
+ }
+
+ dialogBinding.tvConfirm.setOnClickListener {
+ when (selectedExpireOption) {
+ 0 -> {
+ expireTimeInMillis = EXPIRE_24H
+ binding.tvExpireTime.text = getString(R.string.expire_24h)
+ }
+ 1 -> {
+ expireTimeInMillis = EXPIRE_7D
+ binding.tvExpireTime.text = getString(R.string.expire_7d)
+ }
+ }
+ // 选择后显示二维码并生成
+ showQrCode()
+ generateQRCode()
+ dialog.dismiss()
+ }
+
+ dialog.show()
+ }
+
+ private fun hideQrCode() {
+ // 隐藏二维码,显示灰色占位区域
+ binding.ivQrCode.visibility = View.GONE
+ binding.ivQrLogo.visibility = View.GONE
+ binding.vQrPlaceholder.visibility = View.VISIBLE
+ }
+
+ private fun showQrCode() {
+ // 显示二维码,隐藏灰色占位区域
+ binding.vQrPlaceholder.visibility = View.GONE
+ binding.ivQrCode.visibility = View.VISIBLE
+ binding.ivQrLogo.visibility = View.VISIBLE
+ }
+
+ private fun generateQRCode() {
+ val content = generateInviteCode()
+ val qrBitmap = createQRCodeWithLogo(content, 400, 400)
+ binding.ivQrCode.setImageBitmap(qrBitmap)
+ }
+
+ private fun generateInviteCode(): String {
+ // 生成包含邀请信息的JSON字符串
+ val timestamp = System.currentTimeMillis()
+ val expireTime = timestamp + expireTimeInMillis
+ return "{\"type\":\"invite\",\"code\":\"INV${timestamp}\",\"expire\":$expireTime}"
+ }
+
+ private fun createQRCodeWithLogo(content: String, width: Int, height: Int): Bitmap? {
+ return try {
+ val hints = Hashtable()
+ hints[EncodeHintType.CHARACTER_SET] = "UTF-8"
+ hints[EncodeHintType.ERROR_CORRECTION] = ErrorCorrectionLevel.H
+
+ val writer = QRCodeWriter()
+ val bitMatrix = writer.encode(content, BarcodeFormat.QR_CODE, width, height, hints)
+
+ val qrBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)
+ val canvas = Canvas(qrBitmap)
+
+ // 绘制白色背景
+ canvas.drawColor(Color.WHITE)
+
+ // 绘制二维码
+ val paint = Paint(Paint.ANTI_ALIAS_FLAG)
+ paint.color = Color.BLACK
+
+ val cellWidth = width.toFloat() / bitMatrix.width
+ val cellHeight = height.toFloat() / bitMatrix.height
+
+ for (x in 0 until bitMatrix.width) {
+ for (y in 0 until bitMatrix.height) {
+ if (bitMatrix.get(x, y)) {
+ canvas.drawRect(
+ x * cellWidth,
+ y * cellHeight,
+ (x + 1) * cellWidth,
+ (y + 1) * cellHeight,
+ paint
+ )
+ }
+ }
+ }
+
+ qrBitmap
+ } catch (e: Exception) {
+ e.printStackTrace()
+ null
+ }
+ }
+
+ private fun shareToWeChat() {
+ // 微信分享实现
+ // 这里需要集成微信SDK
+ }
+
+ override fun onDestroy() {
+ super.onDestroy()
+ }
+}
diff --git a/app/src/main/java/com/example/defenseapplication/view/FamilySwitchDialog.kt b/app/src/main/java/com/example/defenseapplication/view/FamilySwitchDialog.kt
index 0567437..ea92540 100644
--- a/app/src/main/java/com/example/defenseapplication/view/FamilySwitchDialog.kt
+++ b/app/src/main/java/com/example/defenseapplication/view/FamilySwitchDialog.kt
@@ -47,7 +47,7 @@ class FamilySwitchDialog(
val familyList = listOf(
FamilyItem("1", context.getString(R.string.my_family)),
- FamilyItem("2", context.getString(R.string.zhangsan_family))
+ FamilyItem("2", "张三的家庭")
)
adapter = FamilySwitchAdapter(familyList) { familyItem ->
diff --git a/app/src/main/res/drawable/add_img.png b/app/src/main/res/drawable/add_img.png
new file mode 100644
index 0000000..47134ad
Binary files /dev/null and b/app/src/main/res/drawable/add_img.png differ
diff --git a/app/src/main/res/drawable/bg_radio_button_selector.xml b/app/src/main/res/drawable/bg_radio_button_selector.xml
new file mode 100644
index 0000000..7695b5f
--- /dev/null
+++ b/app/src/main/res/drawable/bg_radio_button_selector.xml
@@ -0,0 +1,21 @@
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/bg_white_rounded.xml b/app/src/main/res/drawable/bg_white_rounded.xml
new file mode 100644
index 0000000..9cf9a8d
--- /dev/null
+++ b/app/src/main/res/drawable/bg_white_rounded.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
diff --git a/app/src/main/res/drawable/logo.png b/app/src/main/res/drawable/logo.png
new file mode 100644
index 0000000..c3977b7
Binary files /dev/null and b/app/src/main/res/drawable/logo.png differ
diff --git a/app/src/main/res/drawable/text_color_selector.xml b/app/src/main/res/drawable/text_color_selector.xml
new file mode 100644
index 0000000..f8eba85
--- /dev/null
+++ b/app/src/main/res/drawable/text_color_selector.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/vx.png b/app/src/main/res/drawable/vx.png
new file mode 100644
index 0000000..ebeb065
Binary files /dev/null and b/app/src/main/res/drawable/vx.png differ
diff --git a/app/src/main/res/layout/dialog_expire_time.xml b/app/src/main/res/layout/dialog_expire_time.xml
new file mode 100644
index 0000000..29a84a9
--- /dev/null
+++ b/app/src/main/res/layout/dialog_expire_time.xml
@@ -0,0 +1,72 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/invitation_code_activity.xml b/app/src/main/res/layout/invitation_code_activity.xml
new file mode 100644
index 0000000..2ded2b2
--- /dev/null
+++ b/app/src/main/res/layout/invitation_code_activity.xml
@@ -0,0 +1,172 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/item_linked_user.xml b/app/src/main/res/layout/item_linked_user.xml
index 1c23c42..75cbd8a 100644
--- a/app/src/main/res/layout/item_linked_user.xml
+++ b/app/src/main/res/layout/item_linked_user.xml
@@ -16,6 +16,7 @@
app:layout_constraintTop_toTopOf="parent">
-
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/strike_position_activity.xml b/app/src/main/res/layout/strike_position_activity.xml
index 554d5be..3b42b14 100644
--- a/app/src/main/res/layout/strike_position_activity.xml
+++ b/app/src/main/res/layout/strike_position_activity.xml
@@ -85,7 +85,7 @@
android:layout_width="match_parent"
android:layout_height="40dp"
android:layout_margin="16dp"
- android:layout_marginBottom="20dp"
+ android:layout_marginBottom="40dp"
android:background="@drawable/rounded_blue_bg"
android:text="@string/submit"
android:textColor="@color/white"
diff --git a/app/src/main/res/values-zh/strings.xml b/app/src/main/res/values-zh/strings.xml
index d06a73f..bfa0d2c 100644
--- a/app/src/main/res/values-zh/strings.xml
+++ b/app/src/main/res/values-zh/strings.xml
@@ -398,4 +398,16 @@
密码错误
未设置操作密码
确认重置
+ 用户状态
+ 联系人姓名
+ 身份证号
+ MAC地址
+ 邀请码
+ 邀请码有效期
+ 二维码邀请
+ 邀请二维码24小时内有效,仅可接受一次;手动撤销或重新生成将使原邀请二维码失效
+ 其他邀请方式
+ 微信好友
+ 24小时
+ 7天
\ 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 67c3766..608cd6d 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -103,8 +103,6 @@
Add User
Admin
Member
- Ordinary Member
- Zhang San Family
Phone Number
Enter nickname
@@ -244,10 +242,6 @@
Please scan the QR code on the device or manual
- 用户状态
- 联系人姓名
- 身份证号
- MAC地址
Workshop
Parents Home
Smart Hanging Defense
@@ -408,4 +402,16 @@
Please enter new password
Please re-enter new password
Confirm Reset
+ User Status
+ Contact Name
+ ID Card Number
+ MAC Address
+ Invite Code
+ Invite Code Expiry
+ QR Code Scan Invite
+ Invite QR code is valid for 24 hours; can only be accepted once; manual revocation or regenerating will invalidate the previous invite QR code
+ Other Invite Methods
+ WeChat Friend
+ 24h
+ 7d
\ No newline at end of file
diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml
index 9b74115..7cebb25 100644
--- a/app/src/main/res/values/themes.xml
+++ b/app/src/main/res/values/themes.xml
@@ -19,4 +19,11 @@
- @anim/slide_up
- @anim/slide_down
+
+
\ No newline at end of file