Compare commits
14 Commits
d30c025874
...
ef4dfb0307
| Author | SHA1 | Date | |
|---|---|---|---|
| ef4dfb0307 | |||
| 086f1226a1 | |||
| 5cf30411c1 | |||
| 76e4949dd7 | |||
| 4a16010bd6 | |||
| b55d9a4b38 | |||
| 6a1cfaeda9 | |||
| f57975ef1e | |||
| 548d501a44 | |||
| a997190480 | |||
| 631f9831c3 | |||
| b2c3ed9015 | |||
| 6bd31327db | |||
| 7e362038b3 |
48
.kotlin/errors/errors-1780537656129.log
Normal file
@@ -0,0 +1,48 @@
|
||||
kotlin version: 2.2.10
|
||||
error message: java.nio.file.AccessDeniedException: C:\Users\Administrator\AppData\Local\kotlin\daemon\kotlin-daemon-client-tsmarker7700090853507788345.tmp
|
||||
|
||||
error message: Daemon compilation failed: Could not connect to Kotlin compile daemon
|
||||
java.lang.RuntimeException: Could not connect to Kotlin compile daemon
|
||||
at org.jetbrains.kotlin.compilerRunner.GradleKotlinCompilerWork.compileWithDaemon(GradleKotlinCompilerWork.kt:214)
|
||||
at org.jetbrains.kotlin.compilerRunner.GradleKotlinCompilerWork.compileWithDaemonOrFallbackImpl(GradleKotlinCompilerWork.kt:159)
|
||||
at org.jetbrains.kotlin.compilerRunner.GradleKotlinCompilerWork.run(GradleKotlinCompilerWork.kt:111)
|
||||
at org.jetbrains.kotlin.compilerRunner.GradleCompilerRunnerWithWorkers$GradleKotlinCompilerWorkAction.execute(GradleCompilerRunnerWithWorkers.kt:74)
|
||||
at org.gradle.workers.internal.DefaultWorkerServer.execute(DefaultWorkerServer.java:68)
|
||||
at org.gradle.workers.internal.NoIsolationWorkerFactory$1$1.create(NoIsolationWorkerFactory.java:64)
|
||||
at org.gradle.workers.internal.NoIsolationWorkerFactory$1$1.create(NoIsolationWorkerFactory.java:61)
|
||||
at org.gradle.internal.classloader.ClassLoaderUtils.executeInClassloader(ClassLoaderUtils.java:102)
|
||||
at org.gradle.workers.internal.NoIsolationWorkerFactory$1.lambda$execute$0(NoIsolationWorkerFactory.java:61)
|
||||
at org.gradle.workers.internal.AbstractWorker$1.call(AbstractWorker.java:44)
|
||||
at org.gradle.workers.internal.AbstractWorker$1.call(AbstractWorker.java:41)
|
||||
at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:209)
|
||||
at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:204)
|
||||
at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:66)
|
||||
at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:59)
|
||||
at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:166)
|
||||
at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:59)
|
||||
at org.gradle.internal.operations.DefaultBuildOperationRunner.call(DefaultBuildOperationRunner.java:53)
|
||||
at org.gradle.workers.internal.AbstractWorker.executeWrappedInBuildOperation(AbstractWorker.java:41)
|
||||
at org.gradle.workers.internal.NoIsolationWorkerFactory$1.execute(NoIsolationWorkerFactory.java:58)
|
||||
at org.gradle.workers.internal.DefaultWorkerExecutor.lambda$submitWork$0(DefaultWorkerExecutor.java:176)
|
||||
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:317)
|
||||
at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.runExecution(DefaultConditionalExecutionQueue.java:194)
|
||||
at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.access$700(DefaultConditionalExecutionQueue.java:127)
|
||||
at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner$1.run(DefaultConditionalExecutionQueue.java:169)
|
||||
at org.gradle.internal.Factories$1.create(Factories.java:30)
|
||||
at org.gradle.internal.work.DefaultWorkerLeaseService.lambda$withLocksAcquired$0(DefaultWorkerLeaseService.java:269)
|
||||
at org.gradle.internal.work.ResourceLockStatistics$1.measure(ResourceLockStatistics.java:42)
|
||||
at org.gradle.internal.work.DefaultWorkerLeaseService.withLocksAcquired(DefaultWorkerLeaseService.java:267)
|
||||
at org.gradle.internal.work.DefaultWorkerLeaseService.withLocks(DefaultWorkerLeaseService.java:259)
|
||||
at org.gradle.internal.work.DefaultWorkerLeaseService.runAsWorkerThread(DefaultWorkerLeaseService.java:127)
|
||||
at org.gradle.internal.work.DefaultWorkerLeaseService.runAsWorkerThread(DefaultWorkerLeaseService.java:132)
|
||||
at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.runBatch(DefaultConditionalExecutionQueue.java:164)
|
||||
at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.run(DefaultConditionalExecutionQueue.java:133)
|
||||
at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:572)
|
||||
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:317)
|
||||
at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64)
|
||||
at org.gradle.internal.concurrent.AbstractManagedExecutor$1.run(AbstractManagedExecutor.java:47)
|
||||
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1144)
|
||||
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:642)
|
||||
at java.base/java.lang.Thread.run(Thread.java:1583)
|
||||
|
||||
|
||||
48
.kotlin/errors/errors-1780537656460.log
Normal file
@@ -0,0 +1,48 @@
|
||||
kotlin version: 2.2.10
|
||||
error message: java.nio.file.AccessDeniedException: C:\Users\Administrator\AppData\Local\kotlin\daemon\kotlin-daemon-client-tsmarker12680940025563006602.tmp
|
||||
|
||||
error message: Daemon compilation failed: Could not connect to Kotlin compile daemon
|
||||
java.lang.RuntimeException: Could not connect to Kotlin compile daemon
|
||||
at org.jetbrains.kotlin.compilerRunner.GradleKotlinCompilerWork.compileWithDaemon(GradleKotlinCompilerWork.kt:214)
|
||||
at org.jetbrains.kotlin.compilerRunner.GradleKotlinCompilerWork.compileWithDaemonOrFallbackImpl(GradleKotlinCompilerWork.kt:159)
|
||||
at org.jetbrains.kotlin.compilerRunner.GradleKotlinCompilerWork.run(GradleKotlinCompilerWork.kt:111)
|
||||
at org.jetbrains.kotlin.compilerRunner.GradleCompilerRunnerWithWorkers$GradleKotlinCompilerWorkAction.execute(GradleCompilerRunnerWithWorkers.kt:74)
|
||||
at org.gradle.workers.internal.DefaultWorkerServer.execute(DefaultWorkerServer.java:68)
|
||||
at org.gradle.workers.internal.NoIsolationWorkerFactory$1$1.create(NoIsolationWorkerFactory.java:64)
|
||||
at org.gradle.workers.internal.NoIsolationWorkerFactory$1$1.create(NoIsolationWorkerFactory.java:61)
|
||||
at org.gradle.internal.classloader.ClassLoaderUtils.executeInClassloader(ClassLoaderUtils.java:102)
|
||||
at org.gradle.workers.internal.NoIsolationWorkerFactory$1.lambda$execute$0(NoIsolationWorkerFactory.java:61)
|
||||
at org.gradle.workers.internal.AbstractWorker$1.call(AbstractWorker.java:44)
|
||||
at org.gradle.workers.internal.AbstractWorker$1.call(AbstractWorker.java:41)
|
||||
at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:209)
|
||||
at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:204)
|
||||
at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:66)
|
||||
at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:59)
|
||||
at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:166)
|
||||
at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:59)
|
||||
at org.gradle.internal.operations.DefaultBuildOperationRunner.call(DefaultBuildOperationRunner.java:53)
|
||||
at org.gradle.workers.internal.AbstractWorker.executeWrappedInBuildOperation(AbstractWorker.java:41)
|
||||
at org.gradle.workers.internal.NoIsolationWorkerFactory$1.execute(NoIsolationWorkerFactory.java:58)
|
||||
at org.gradle.workers.internal.DefaultWorkerExecutor.lambda$submitWork$0(DefaultWorkerExecutor.java:176)
|
||||
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:317)
|
||||
at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.runExecution(DefaultConditionalExecutionQueue.java:194)
|
||||
at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.access$700(DefaultConditionalExecutionQueue.java:127)
|
||||
at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner$1.run(DefaultConditionalExecutionQueue.java:169)
|
||||
at org.gradle.internal.Factories$1.create(Factories.java:30)
|
||||
at org.gradle.internal.work.DefaultWorkerLeaseService.lambda$withLocksAcquired$0(DefaultWorkerLeaseService.java:269)
|
||||
at org.gradle.internal.work.ResourceLockStatistics$1.measure(ResourceLockStatistics.java:42)
|
||||
at org.gradle.internal.work.DefaultWorkerLeaseService.withLocksAcquired(DefaultWorkerLeaseService.java:267)
|
||||
at org.gradle.internal.work.DefaultWorkerLeaseService.withLocks(DefaultWorkerLeaseService.java:259)
|
||||
at org.gradle.internal.work.DefaultWorkerLeaseService.runAsWorkerThread(DefaultWorkerLeaseService.java:127)
|
||||
at org.gradle.internal.work.DefaultWorkerLeaseService.runAsWorkerThread(DefaultWorkerLeaseService.java:132)
|
||||
at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.runBatch(DefaultConditionalExecutionQueue.java:164)
|
||||
at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.run(DefaultConditionalExecutionQueue.java:133)
|
||||
at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:572)
|
||||
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:317)
|
||||
at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64)
|
||||
at org.gradle.internal.concurrent.AbstractManagedExecutor$1.run(AbstractManagedExecutor.java:47)
|
||||
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1144)
|
||||
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:642)
|
||||
at java.base/java.lang.Thread.run(Thread.java:1583)
|
||||
|
||||
|
||||
48
.kotlin/errors/errors-1781138120653.log
Normal file
@@ -0,0 +1,48 @@
|
||||
kotlin version: 2.2.10
|
||||
error message: java.nio.file.AccessDeniedException: C:\Users\Administrator\AppData\Local\kotlin\daemon\kotlin-daemon-client-tsmarker3894271637508823813.tmp
|
||||
|
||||
error message: Daemon compilation failed: Could not connect to Kotlin compile daemon
|
||||
java.lang.RuntimeException: Could not connect to Kotlin compile daemon
|
||||
at org.jetbrains.kotlin.compilerRunner.GradleKotlinCompilerWork.compileWithDaemon(GradleKotlinCompilerWork.kt:214)
|
||||
at org.jetbrains.kotlin.compilerRunner.GradleKotlinCompilerWork.compileWithDaemonOrFallbackImpl(GradleKotlinCompilerWork.kt:159)
|
||||
at org.jetbrains.kotlin.compilerRunner.GradleKotlinCompilerWork.run(GradleKotlinCompilerWork.kt:111)
|
||||
at org.jetbrains.kotlin.compilerRunner.GradleCompilerRunnerWithWorkers$GradleKotlinCompilerWorkAction.execute(GradleCompilerRunnerWithWorkers.kt:74)
|
||||
at org.gradle.workers.internal.DefaultWorkerServer.execute(DefaultWorkerServer.java:68)
|
||||
at org.gradle.workers.internal.NoIsolationWorkerFactory$1$1.create(NoIsolationWorkerFactory.java:64)
|
||||
at org.gradle.workers.internal.NoIsolationWorkerFactory$1$1.create(NoIsolationWorkerFactory.java:61)
|
||||
at org.gradle.internal.classloader.ClassLoaderUtils.executeInClassloader(ClassLoaderUtils.java:102)
|
||||
at org.gradle.workers.internal.NoIsolationWorkerFactory$1.lambda$execute$0(NoIsolationWorkerFactory.java:61)
|
||||
at org.gradle.workers.internal.AbstractWorker$1.call(AbstractWorker.java:44)
|
||||
at org.gradle.workers.internal.AbstractWorker$1.call(AbstractWorker.java:41)
|
||||
at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:209)
|
||||
at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:204)
|
||||
at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:66)
|
||||
at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:59)
|
||||
at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:166)
|
||||
at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:59)
|
||||
at org.gradle.internal.operations.DefaultBuildOperationRunner.call(DefaultBuildOperationRunner.java:53)
|
||||
at org.gradle.workers.internal.AbstractWorker.executeWrappedInBuildOperation(AbstractWorker.java:41)
|
||||
at org.gradle.workers.internal.NoIsolationWorkerFactory$1.execute(NoIsolationWorkerFactory.java:58)
|
||||
at org.gradle.workers.internal.DefaultWorkerExecutor.lambda$submitWork$0(DefaultWorkerExecutor.java:176)
|
||||
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:317)
|
||||
at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.runExecution(DefaultConditionalExecutionQueue.java:194)
|
||||
at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.access$700(DefaultConditionalExecutionQueue.java:127)
|
||||
at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner$1.run(DefaultConditionalExecutionQueue.java:169)
|
||||
at org.gradle.internal.Factories$1.create(Factories.java:30)
|
||||
at org.gradle.internal.work.DefaultWorkerLeaseService.lambda$withLocksAcquired$0(DefaultWorkerLeaseService.java:269)
|
||||
at org.gradle.internal.work.ResourceLockStatistics$1.measure(ResourceLockStatistics.java:42)
|
||||
at org.gradle.internal.work.DefaultWorkerLeaseService.withLocksAcquired(DefaultWorkerLeaseService.java:267)
|
||||
at org.gradle.internal.work.DefaultWorkerLeaseService.withLocks(DefaultWorkerLeaseService.java:259)
|
||||
at org.gradle.internal.work.DefaultWorkerLeaseService.runAsWorkerThread(DefaultWorkerLeaseService.java:127)
|
||||
at org.gradle.internal.work.DefaultWorkerLeaseService.runAsWorkerThread(DefaultWorkerLeaseService.java:132)
|
||||
at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.runBatch(DefaultConditionalExecutionQueue.java:164)
|
||||
at org.gradle.internal.work.DefaultConditionalExecutionQueue$ExecutionRunner.run(DefaultConditionalExecutionQueue.java:133)
|
||||
at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:572)
|
||||
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:317)
|
||||
at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64)
|
||||
at org.gradle.internal.concurrent.AbstractManagedExecutor$1.run(AbstractManagedExecutor.java:47)
|
||||
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1144)
|
||||
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:642)
|
||||
at java.base/java.lang.Thread.run(Thread.java:1583)
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
android:fullBackupContent="@xml/backup_rules"
|
||||
android:icon="@mipmap/logo"
|
||||
android:label="@string/app_name"
|
||||
android:networkSecurityConfig="@xml/network_security_config"
|
||||
android:roundIcon="@mipmap/ic_launcher_round"
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/Theme.DefenseApplication">
|
||||
@@ -42,6 +43,9 @@
|
||||
<activity
|
||||
android:name=".personal.InvitationCodeActivity"
|
||||
android:exported="false" />
|
||||
<activity
|
||||
android:name=".personal.JoinFamilyInviteActivity"
|
||||
android:exported="false" />
|
||||
<activity
|
||||
android:name=".liveVideo.StrikePositionActivity"
|
||||
android:exported="false" />
|
||||
|
||||
@@ -18,6 +18,8 @@ class AddDeviceAdapter(
|
||||
private val onItemClick: (Device) -> Unit
|
||||
) : RecyclerView.Adapter<AddDeviceAdapter.ViewHolder>() {
|
||||
|
||||
private val defaultIcons = listOf(R.mipmap.img1, R.mipmap.img2, R.mipmap.img3)
|
||||
|
||||
inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
|
||||
val ivIcon: ImageView = itemView.findViewById(R.id.ivDeviceIcon2)
|
||||
val tvName: TextView = itemView.findViewById(R.id.tvDeviceName2)
|
||||
@@ -47,7 +49,9 @@ class AddDeviceAdapter(
|
||||
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
||||
val device = devices[position]
|
||||
holder.tvName.text = device.name
|
||||
holder.ivIcon.setImageResource(R.mipmap.img)
|
||||
|
||||
val iconResId = defaultIcons[position % defaultIcons.size]
|
||||
holder.ivIcon.setImageResource(iconResId)
|
||||
|
||||
// 点击事件
|
||||
holder.itemView.setOnClickListener { onItemClick(device) }
|
||||
|
||||
@@ -3,25 +3,18 @@ package com.ckkj.defense_device.adapter
|
||||
import android.view.LayoutInflater
|
||||
import android.view.ViewGroup
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.bumptech.glide.Glide
|
||||
import com.ckkj.defense_device.R
|
||||
import com.ckkj.defense_device.bean.DeviceBean
|
||||
import com.ckkj.defense_device.databinding.ItemDeviceBinding
|
||||
|
||||
data class DeviceUi(
|
||||
val name: String,
|
||||
val status: String,
|
||||
val deviceId: String = ""
|
||||
) {
|
||||
val isOnline: Boolean
|
||||
get() = status == "1"
|
||||
}
|
||||
|
||||
class DeviceAdapter(
|
||||
private val onItemClick: (DeviceUi) -> Unit = {}
|
||||
private val onItemClick: (DeviceBean) -> Unit = {}
|
||||
) : RecyclerView.Adapter<DeviceAdapter.DeviceViewHolder>() {
|
||||
|
||||
private val items = mutableListOf<DeviceUi>()
|
||||
private val items = mutableListOf<DeviceBean>()
|
||||
|
||||
fun submitList(deviceList: List<DeviceUi>) {
|
||||
fun submitList(deviceList: List<DeviceBean>) {
|
||||
items.clear()
|
||||
items.addAll(deviceList)
|
||||
notifyDataSetChanged()
|
||||
@@ -33,15 +26,25 @@ class DeviceAdapter(
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: DeviceViewHolder, position: Int) {
|
||||
holder.bind(items[position])
|
||||
holder.bind(items[position], position)
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int = items.size
|
||||
|
||||
private val defaultIcons = listOf(R.mipmap.img1, R.mipmap.img2, R.mipmap.img3)
|
||||
|
||||
inner class DeviceViewHolder(private val binding: ItemDeviceBinding) :
|
||||
RecyclerView.ViewHolder(binding.root) {
|
||||
|
||||
fun bind(item: DeviceUi) {
|
||||
fun bind(item: DeviceBean, position: Int) {
|
||||
if (item.deviceImg.isNullOrEmpty()) {
|
||||
val iconResId = defaultIcons[position % defaultIcons.size]
|
||||
binding.ivDeviceIcon.setImageResource(iconResId)
|
||||
} else {
|
||||
Glide.with(binding.root.context)
|
||||
.load(item.deviceImg)
|
||||
.into(binding.ivDeviceIcon)
|
||||
}
|
||||
binding.tvDeviceType.text = item.name
|
||||
when (item.status) {
|
||||
"1" -> {
|
||||
|
||||
@@ -4,7 +4,7 @@ package com.ckkj.defense_device.bean
|
||||
* 统一返回数据基类(根据你的后端实际字段调整)
|
||||
*/
|
||||
data class BaseInfo(
|
||||
val message: String? = null,
|
||||
val msg: String? = null,
|
||||
val code: Int = 0,
|
||||
val data: Any? = null
|
||||
)
|
||||
@@ -27,4 +27,13 @@ data class DeviceBean(
|
||||
val wifiPassword: String? = null,//WiFi密码
|
||||
val workMode: String? = null,//工作模式 0-自动 1-半自动
|
||||
val optionPassword: String? = null, //操作密码
|
||||
)
|
||||
) {
|
||||
val deviceId: String
|
||||
get() = id ?: ""
|
||||
|
||||
val name: String
|
||||
get() = deviceName ?: ""
|
||||
|
||||
val isOnline: Boolean
|
||||
get() = status == "1"
|
||||
}
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
package com.ckkj.defense_device.bean
|
||||
|
||||
|
||||
data class JoinTheFamilyBean(
|
||||
val parentId: String,
|
||||
val inviteCode: String,
|
||||
)
|
||||
@@ -0,0 +1,8 @@
|
||||
package com.ckkj.defense_device.bean
|
||||
|
||||
data class RecommendationCodeBean(
|
||||
val inviteCode: String? = null,
|
||||
val code: String? = null,
|
||||
val expireTime: Long? = null,
|
||||
val expire: Long? = null
|
||||
)
|
||||
@@ -0,0 +1,5 @@
|
||||
package com.ckkj.defense_device.bean
|
||||
|
||||
data class SelectInviterInfoBean(
|
||||
val code: String
|
||||
)
|
||||
@@ -0,0 +1,8 @@
|
||||
package com.ckkj.defense_device.bean
|
||||
|
||||
data class UpdateFamilyUserRequest(
|
||||
val id: String,
|
||||
val optionPassword: String,
|
||||
val optionStatus: String,
|
||||
val status: String,
|
||||
)
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.ckkj.defense_device.home
|
||||
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import androidx.fragment.app.Fragment
|
||||
import com.ckkj.defense_device.R
|
||||
@@ -7,6 +8,10 @@ import com.ckkj.defense_device.base.BaseActivity
|
||||
import com.ckkj.defense_device.databinding.HomeActivityBinding
|
||||
|
||||
class HomeActivity : BaseActivity() {
|
||||
|
||||
companion object {
|
||||
const val EXTRA_REFRESH = "extra_refresh"
|
||||
}
|
||||
// ViewBinding 核心对象
|
||||
private lateinit var binding: HomeActivityBinding
|
||||
|
||||
@@ -49,6 +54,28 @@ class HomeActivity : BaseActivity() {
|
||||
binding.ivProfile.setImageResource(R.mipmap.profile_checked)
|
||||
binding.tvProfile.setTextColor(resources.getColor(R.color.ic_selected))
|
||||
}
|
||||
|
||||
handleRefreshIntent(intent)
|
||||
}
|
||||
|
||||
override fun onNewIntent(intent: Intent?) {
|
||||
super.onNewIntent(intent)
|
||||
if (intent != null) {
|
||||
setIntent(intent)
|
||||
handleRefreshIntent(intent)
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleRefreshIntent(intent: Intent) {
|
||||
if (intent.getBooleanExtra(EXTRA_REFRESH, false)) {
|
||||
intent.removeExtra(EXTRA_REFRESH)
|
||||
switchFragment(homeMenuFragment)
|
||||
binding.ivHome.setImageResource(R.mipmap.home_checked)
|
||||
binding.tvHome.setTextColor(resources.getColor(R.color.ic_selected))
|
||||
binding.ivProfile.setImageResource(R.mipmap.profile)
|
||||
binding.tvProfile.setTextColor(resources.getColor(R.color.ic_normal))
|
||||
homeMenuFragment.refreshHomeData()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -23,13 +23,14 @@ import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.ckkj.defense_device.R
|
||||
import com.ckkj.defense_device.adapter.DeviceAdapter
|
||||
import com.ckkj.defense_device.adapter.DeviceUi
|
||||
import com.ckkj.defense_device.adapter.FamilyAdapter
|
||||
import com.ckkj.defense_device.bean.DeviceBean
|
||||
import com.ckkj.defense_device.bean.FamilyBean
|
||||
import com.ckkj.defense_device.bean.SwitchFamilyRequest
|
||||
import com.ckkj.defense_device.bean.SelectInviterInfoBean
|
||||
import com.ckkj.defense_device.databinding.HomeMenuFragmentBinding
|
||||
import com.ckkj.defense_device.liveVideo.LiveVideoActivity
|
||||
import com.ckkj.defense_device.personal.JoinFamilyInviteActivity
|
||||
import com.ckkj.defense_device.utils.DeviceIdEvent
|
||||
import com.ckkj.defense_device.utils.DeviceUpdateEvent
|
||||
import com.ckkj.defense_device.utils.FamilySwitchEvent
|
||||
@@ -37,6 +38,7 @@ import com.ckkj.defense_device.utils.MessageStatusManager
|
||||
import com.ckkj.defense_device.utils.RetrofitNetwork
|
||||
import com.ckkj.defense_device.utils.UserinfoUtil
|
||||
import com.ckkj.defense_device.view.DefenseDialogs
|
||||
import com.ckkj.defense_device.view.LoadingDialog
|
||||
import com.ckkj.defense_device.view.showDefenseDialog
|
||||
import com.gyf.immersionbar.ImmersionBar
|
||||
import com.maning.mlkitscanner.scan.MNScanManager
|
||||
@@ -45,6 +47,7 @@ import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.json.JSONObject
|
||||
//主页碎片
|
||||
class HomeMenuFragment : Fragment() {
|
||||
// ViewBinding
|
||||
@@ -122,23 +125,86 @@ class HomeMenuFragment : Fragment() {
|
||||
MNScanManager.RESULT_SUCCESS -> {
|
||||
val result = data?.getStringArrayListExtra(MNScanManager.INTENT_KEY_RESULT_SUCCESS)
|
||||
if (!result.isNullOrEmpty()) {
|
||||
ToastUtils.showToast(requireContext(), "扫码成功: $result")
|
||||
val inviteCode = parseInviteCode(result[0])
|
||||
if (inviteCode.isNullOrEmpty()) {
|
||||
Toast.makeText(requireContext(), "无效的邀请码", Toast.LENGTH_SHORT).show()
|
||||
} else {
|
||||
ToastUtils.showToast(requireContext(), "扫码结果为空")
|
||||
fetchInviterInfo(inviteCode)
|
||||
}
|
||||
} else {
|
||||
Toast.makeText(requireContext(), "扫码结果为空", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
MNScanManager.RESULT_FAIL -> {
|
||||
val error = data?.getStringExtra(MNScanManager.INTENT_KEY_RESULT_ERROR)
|
||||
ToastUtils.showToast(requireContext(), "扫码失败: $error")
|
||||
Toast.makeText(requireContext(), "扫码失败: $error", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
MNScanManager.RESULT_CANCLE -> {
|
||||
ToastUtils.showToast(requireContext(), "扫码取消")
|
||||
Toast.makeText(requireContext(), "扫码取消", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun parseInviteCode(scanResult: String): String? {
|
||||
val trimmed = scanResult.trim()
|
||||
if (trimmed.isEmpty()) return null
|
||||
return try {
|
||||
if (trimmed.startsWith("{")) {
|
||||
JSONObject(trimmed).optString("code").takeIf { it.isNotEmpty() }
|
||||
} else {
|
||||
trimmed
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
trimmed
|
||||
}
|
||||
}
|
||||
|
||||
private fun fetchInviterInfo(inviteCode: String) {
|
||||
val loadingDialog = LoadingDialog(requireActivity()).apply { show() }
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
try {
|
||||
val response = RetrofitNetwork.getNetworkService()
|
||||
.selectInviterInfo(SelectInviterInfoBean(code = inviteCode))
|
||||
withContext(Dispatchers.Main) {
|
||||
loadingDialog.dismiss()
|
||||
if (response.code == 200 && response.data != null) {
|
||||
val inviter = response.data
|
||||
val parentId = inviter.resolveParentId()
|
||||
if (parentId.isNullOrEmpty()) {
|
||||
Toast.makeText(
|
||||
requireContext(),
|
||||
getString(R.string.network_error),
|
||||
Toast.LENGTH_SHORT
|
||||
).show()
|
||||
return@withContext
|
||||
}
|
||||
val intent = Intent(requireContext(), JoinFamilyInviteActivity::class.java).apply {
|
||||
putExtra(JoinFamilyInviteActivity.EXTRA_INVITE_CODE, inviteCode)
|
||||
putExtra(JoinFamilyInviteActivity.EXTRA_NICK_NAME, inviter.nickName)
|
||||
putExtra(JoinFamilyInviteActivity.EXTRA_AVATAR, inviter.avatar)
|
||||
putExtra(JoinFamilyInviteActivity.EXTRA_PARENT_ID, parentId)
|
||||
putExtra(JoinFamilyInviteActivity.EXTRA_USER_ID, inviter.userId)
|
||||
}
|
||||
startActivity(intent)
|
||||
} else {
|
||||
Toast.makeText(
|
||||
requireContext(),
|
||||
response.msg.ifBlank { getString(R.string.network_error) },
|
||||
Toast.LENGTH_SHORT
|
||||
).show()
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
withContext(Dispatchers.Main) {
|
||||
loadingDialog.dismiss()
|
||||
Toast.makeText(requireContext(), R.string.network_error, Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val unreadCountChangeListener = object : MessageStatusManager.UnreadCountChangeListener {
|
||||
override fun onUnreadCountChanged(count: Int) {
|
||||
updateUnreadCountUI(count)
|
||||
@@ -200,8 +266,8 @@ class HomeMenuFragment : Fragment() {
|
||||
// 为 LinearLayout 设置渐变背景
|
||||
setGradientBackground(
|
||||
view = binding.gradientLayout,
|
||||
startColor = Color.parseColor("#EBDCED"),
|
||||
endColor = Color.parseColor("#CAF4FF")
|
||||
startColor = resources.getColor(R.color.gradientLayout1),
|
||||
endColor = resources.getColor(R.color.gradientLayout2)
|
||||
)
|
||||
binding.message.setOnClickListener {
|
||||
val intent = Intent(requireContext(), MessageActivity::class.java)
|
||||
@@ -285,6 +351,10 @@ class HomeMenuFragment : Fragment() {
|
||||
}
|
||||
}
|
||||
|
||||
fun refreshHomeData() {
|
||||
fetchFamilyList()
|
||||
}
|
||||
|
||||
private fun fetchFamilyList() {
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
try {
|
||||
@@ -321,18 +391,22 @@ class HomeMenuFragment : Fragment() {
|
||||
Log.d("HomeMenuFragment", "canViewDevice = $canViewDevice")
|
||||
if (canViewDevice) {
|
||||
binding.tvDeviceTitle.visibility = View.VISIBLE
|
||||
binding.swipeRefreshLayout.visibility = View.VISIBLE
|
||||
binding.rvDeviceList.visibility = View.VISIBLE
|
||||
binding.message.visibility = View.VISIBLE
|
||||
binding.addFamily.visibility = View.VISIBLE
|
||||
binding.add.visibility = View.VISIBLE
|
||||
binding.layoutNoPermission.visibility = View.GONE
|
||||
binding.layoutNoNetwork.visibility = View.GONE
|
||||
} else {
|
||||
binding.tvDeviceTitle.visibility = View.GONE
|
||||
binding.swipeRefreshLayout.visibility = View.GONE
|
||||
binding.rvDeviceList.visibility = View.GONE
|
||||
binding.message.visibility = View.GONE
|
||||
binding.addFamily.visibility = View.GONE
|
||||
binding.add.visibility = View.GONE
|
||||
binding.layoutNoPermission.visibility = View.VISIBLE
|
||||
binding.layoutNoNetwork.visibility = View.GONE
|
||||
}
|
||||
}
|
||||
|
||||
@@ -390,9 +464,12 @@ class HomeMenuFragment : Fragment() {
|
||||
hasMore = newDevices.size >= pageSize
|
||||
}
|
||||
Log.d("DeviceList", "deviceBeanList size = ${deviceBeanList.size}")
|
||||
showDeviceContent()
|
||||
updateDeviceList()
|
||||
} else {
|
||||
Toast.makeText(requireContext(), response.msg, Toast.LENGTH_SHORT).show()
|
||||
noNetwork()
|
||||
val errorMsg = response.msg.ifBlank { getString(R.string.network_error) }
|
||||
Toast.makeText(requireContext(), errorMsg, Toast.LENGTH_SHORT).show()
|
||||
if (isLoadMore) {
|
||||
hasMore = false
|
||||
}
|
||||
@@ -401,6 +478,7 @@ class HomeMenuFragment : Fragment() {
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
withContext(Dispatchers.Main) {
|
||||
noNetwork()
|
||||
Toast.makeText(requireContext(), R.string.network_error, Toast.LENGTH_SHORT).show()
|
||||
isLoading = false
|
||||
if (isLoadMore) {
|
||||
@@ -445,21 +523,31 @@ class HomeMenuFragment : Fragment() {
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateDeviceList() {
|
||||
val deviceUiList = deviceBeanList.map {
|
||||
DeviceUi(it.deviceName ?: "", it.status ?: "", it.id ?: "")
|
||||
private fun showDeviceContent() {
|
||||
binding.swipeRefreshLayout.visibility = View.VISIBLE
|
||||
binding.rvDeviceList.visibility = View.VISIBLE
|
||||
binding.layoutNoPermission.visibility = View.GONE
|
||||
binding.layoutNoNetwork.visibility = View.GONE
|
||||
}
|
||||
|
||||
if (deviceUiList.isEmpty()) {
|
||||
private fun noNetwork() {
|
||||
binding.swipeRefreshLayout.visibility = View.GONE
|
||||
binding.rvDeviceList.visibility = View.GONE
|
||||
binding.layoutNoPermission.visibility = View.GONE
|
||||
binding.layoutNoNetwork.visibility = View.VISIBLE
|
||||
}
|
||||
|
||||
private fun updateDeviceList() {
|
||||
if (deviceBeanList.isEmpty()) {
|
||||
deviceAdapter.submitList(listOf(
|
||||
DeviceUi(getString(R.string.no_device), "0")
|
||||
DeviceBean(deviceName = getString(R.string.no_device), status = "0")
|
||||
))
|
||||
} else {
|
||||
deviceAdapter.submitList(deviceUiList)
|
||||
deviceAdapter.submitList(deviceBeanList)
|
||||
}
|
||||
}
|
||||
|
||||
private fun onDeviceClicked(device: DeviceUi) {
|
||||
private fun onDeviceClicked(device: DeviceBean) {
|
||||
if (device.isOnline) {
|
||||
DeviceIdEvent.setDeviceId(device.deviceId)
|
||||
val intent = Intent(requireContext(), LiveVideoActivity::class.java)
|
||||
|
||||
@@ -125,7 +125,7 @@ class MessageActivity : AppCompatActivity() {
|
||||
e.printStackTrace()
|
||||
withContext(Dispatchers.Main) {
|
||||
if (allMessages.isEmpty()) {
|
||||
showEmptyState()
|
||||
noNetwork()
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
@@ -152,6 +152,12 @@ class MessageActivity : AppCompatActivity() {
|
||||
binding.emptyLayout.visibility = View.GONE
|
||||
}
|
||||
|
||||
private fun noNetwork() {
|
||||
binding.rvMessageList.visibility = View.GONE
|
||||
binding.layoutNoNetwork.visibility = View.VISIBLE
|
||||
binding.tvNoMoreData.visibility = View.GONE
|
||||
}
|
||||
|
||||
private fun showNoMoreDataHint() {
|
||||
binding.tvNoMoreData.visibility = View.VISIBLE
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ import com.ckkj.defense_device.utils.LanguageUtil
|
||||
import com.ckkj.defense_device.utils.RetrofitNetwork
|
||||
import com.ckkj.defense_device.utils.UserinfoUtil
|
||||
import com.ckkj.defense_device.utils.ActivityManager
|
||||
import com.ckkj.defense_device.view.CustomDialogFragmentText
|
||||
import com.ckkj.defense_device.view.FamilySwitchDialog
|
||||
import com.ckkj.defense_device.view.LanguageDialog
|
||||
import com.gyf.immersionbar.ImmersionBar
|
||||
@@ -100,6 +101,13 @@ class PersonalFragment : Fragment() {
|
||||
}
|
||||
// 退出登录点击事件
|
||||
binding.btnLogout.setOnClickListener {
|
||||
val dialog = CustomDialogFragmentText()
|
||||
.setTitle(getString(R.string.tip))
|
||||
.setMessage(getString(R.string.logout_confirm))
|
||||
.setShowInput(false)
|
||||
.setNegativeText(getString(R.string.cancel))
|
||||
.setPositiveText(getString(R.string.confirm))
|
||||
.setOnConfirmListener {
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
try {
|
||||
val response = RetrofitNetwork.getNetworkService().logout()
|
||||
@@ -122,6 +130,8 @@ class PersonalFragment : Fragment() {
|
||||
}
|
||||
}
|
||||
}
|
||||
dialog.show(childFragmentManager, "logout_dialog")
|
||||
}
|
||||
fetchCurrentFamily()
|
||||
return binding.root
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package com.ckkj.defense_device.liveVideo
|
||||
import android.os.Bundle
|
||||
import android.text.Editable
|
||||
import android.text.TextWatcher
|
||||
import android.view.View
|
||||
import android.widget.Toast
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
@@ -95,19 +96,33 @@ class AddLinkedUserActivity : AppCompatActivity() {
|
||||
Toast.makeText(this@AddLinkedUserActivity, "暂无家庭成员数据", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
} else {
|
||||
hide()
|
||||
Toast.makeText(this@AddLinkedUserActivity, "请求失败: ${response.msg}", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
android.util.Log.e("AddLinkedUserActivity", "网络请求异常", e)
|
||||
withContext(Dispatchers.Main) {
|
||||
binding.swipeRefresh.isRefreshing = false
|
||||
noNetwork()
|
||||
Toast.makeText(this@AddLinkedUserActivity, "网络请求失败: ${e.message}", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun hide() {
|
||||
binding.searchLayout.visibility = View.GONE
|
||||
binding.rvAddLinkedUser.visibility = View.GONE
|
||||
binding.butting?.visibility = View.GONE
|
||||
binding.layoutNoPermission?.visibility = View.VISIBLE
|
||||
}
|
||||
private fun noNetwork() {
|
||||
binding.searchLayout.visibility = View.GONE
|
||||
binding.rvAddLinkedUser.visibility = View.GONE
|
||||
binding.butting?.visibility = View.GONE
|
||||
binding.layoutNoNetwork?.visibility = View.VISIBLE
|
||||
}
|
||||
|
||||
private fun updateFamilyMemberList(familyMembersList: List<FamilyMembersBean>) {
|
||||
fullUserItemList.clear()
|
||||
familyMembersList.forEach { member ->
|
||||
|
||||
@@ -257,6 +257,7 @@ class LinkedUserActivity : AppCompatActivity() {
|
||||
updateFamilyMembersList(response.data as List<FamilyMembersBean>)
|
||||
}
|
||||
} else {
|
||||
hide()
|
||||
Toast.makeText(this@LinkedUserActivity, response.msg, Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
@@ -264,11 +265,24 @@ class LinkedUserActivity : AppCompatActivity() {
|
||||
e.printStackTrace()
|
||||
withContext(Dispatchers.Main) {
|
||||
binding.swipeRefresh.isRefreshing = false
|
||||
Toast.makeText(this@LinkedUserActivity, "网络请求失败", Toast.LENGTH_SHORT).show()
|
||||
noNetwork()
|
||||
Toast.makeText(this@LinkedUserActivity, R.string.network_request_failed, Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
private fun hide() {
|
||||
binding.searchLayout.visibility = View.GONE
|
||||
binding.rvLinkedUser.visibility = View.GONE
|
||||
binding.butting?.visibility = View.GONE
|
||||
binding.layoutNoPermission?.visibility = View.VISIBLE
|
||||
}
|
||||
private fun noNetwork() {
|
||||
binding.searchLayout.visibility = View.GONE
|
||||
binding.rvLinkedUser.visibility = View.GONE
|
||||
binding.butting?.visibility = View.GONE
|
||||
binding.layoutNoNetwork?.visibility = View.VISIBLE
|
||||
}
|
||||
|
||||
private fun updateDeviceUserList(deviceUserList: List<DeviceUserBean>) {
|
||||
fullUserList.clear()
|
||||
|
||||
@@ -80,7 +80,7 @@ class LiveVideoActivity : BaseActivity() {
|
||||
}
|
||||
|
||||
private fun initVideoPlayer() {
|
||||
val videoUrl = "https://www.w3schools.com/html/movie.mp4"//"https://test-streams.mux.dev/x36xhzz/x36xhzz.m3u8"
|
||||
val videoUrl ="http://220.203.23.195:9090/live/test001.live.flv"
|
||||
|
||||
orientationUtils = OrientationUtils(this, binding.exoPlayContextId)
|
||||
orientationUtils?.isEnable = true
|
||||
|
||||
@@ -7,6 +7,7 @@ import androidx.lifecycle.lifecycleScope
|
||||
import com.ckkj.defense_device.R
|
||||
import com.ckkj.defense_device.bean.DeleteDeviceUserRequest
|
||||
import com.ckkj.defense_device.bean.ObtainInviterInformationRequest
|
||||
import com.ckkj.defense_device.bean.UpdateFamilyUserRequest
|
||||
import com.ckkj.defense_device.bean.VerifyOptionPasswordRequest
|
||||
import com.ckkj.defense_device.personal.PasswordInputDialog
|
||||
import com.ckkj.defense_device.utils.DeviceIdEvent
|
||||
@@ -26,6 +27,7 @@ class UserDetailsActivity : AppCompatActivity() {
|
||||
private var userId: String = ""
|
||||
private var isPasswordVerified: Boolean = false
|
||||
private lateinit var passwordDialog: PasswordInputDialog
|
||||
private var optionPassword: String = ""
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
@@ -87,10 +89,12 @@ class UserDetailsActivity : AppCompatActivity() {
|
||||
binding.swUserStatus.setOnCheckedChangeListener { _, isChecked ->
|
||||
if (!isPasswordVerified) {
|
||||
binding.swUserStatus.isChecked = !isChecked
|
||||
showPasswordDialog {
|
||||
showPasswordDialog(isChecked) {
|
||||
isPasswordVerified = true
|
||||
binding.swUserStatus.isChecked = isChecked
|
||||
}
|
||||
} else {
|
||||
updateFamilyUserStatus(isChecked)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -99,7 +103,7 @@ class UserDetailsActivity : AppCompatActivity() {
|
||||
}
|
||||
}
|
||||
|
||||
private fun showPasswordDialog(onVerified: () -> Unit) {
|
||||
private fun showPasswordDialog(status: Boolean, onVerified: () -> Unit) {
|
||||
passwordDialog = PasswordInputDialog(this).apply {
|
||||
setOnConfirmListener { inputPassword ->
|
||||
lifecycleScope.launch {
|
||||
@@ -109,6 +113,7 @@ class UserDetailsActivity : AppCompatActivity() {
|
||||
withContext(Dispatchers.Main) {
|
||||
if (response.code == 200) {
|
||||
dismiss()
|
||||
updateFamilyUserStatus(status, inputPassword)
|
||||
onVerified()
|
||||
} else {
|
||||
Toast.makeText(
|
||||
@@ -135,6 +140,48 @@ class UserDetailsActivity : AppCompatActivity() {
|
||||
}
|
||||
|
||||
|
||||
private fun updateFamilyUserStatus(status: Boolean) {
|
||||
updateFamilyUserStatus(status, optionPassword)
|
||||
}
|
||||
|
||||
private fun updateFamilyUserStatus(status: Boolean, password: String) {
|
||||
if (userId.isEmpty()) {
|
||||
Toast.makeText(this, "用户ID为空", Toast.LENGTH_SHORT).show()
|
||||
return
|
||||
}
|
||||
|
||||
if (password.isNotEmpty()) {
|
||||
optionPassword = password
|
||||
}
|
||||
|
||||
lifecycleScope.launch {
|
||||
try {
|
||||
val request = UpdateFamilyUserRequest(
|
||||
id = userId,
|
||||
optionPassword = optionPassword,
|
||||
optionStatus = "status",
|
||||
status = if (status) "1" else "0"
|
||||
)
|
||||
val response = RetrofitNetwork.getNetworkService().updateFamilyUser(request)
|
||||
withContext(Dispatchers.Main) {
|
||||
if (response.code == 200) {
|
||||
Toast.makeText(this@UserDetailsActivity, "状态修改成功", Toast.LENGTH_SHORT).show()
|
||||
DeviceUserUpdateEvent.notifyUpdate()
|
||||
} else {
|
||||
Toast.makeText(this@UserDetailsActivity, response.msg ?: "状态修改失败", Toast.LENGTH_SHORT).show()
|
||||
binding.swUserStatus.isChecked = !status
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
withContext(Dispatchers.Main) {
|
||||
Toast.makeText(this@UserDetailsActivity, "网络请求失败", Toast.LENGTH_SHORT).show()
|
||||
binding.swUserStatus.isChecked = !status
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun showDeleteDialog() {
|
||||
val dialog = CustomDialogFragmentText()
|
||||
dialog.setTitle(getString(R.string.tip))
|
||||
@@ -146,7 +193,7 @@ class UserDetailsActivity : AppCompatActivity() {
|
||||
if (isPasswordVerified) {
|
||||
deleteDeviceUser()
|
||||
} else {
|
||||
showPasswordDialog {
|
||||
showPasswordDialog(false) {
|
||||
isPasswordVerified = true
|
||||
deleteDeviceUser()
|
||||
}
|
||||
|
||||
@@ -79,8 +79,7 @@ class VoiceSettingsActivity : AppCompatActivity() {
|
||||
private fun updateDeviceAlertAudio() {
|
||||
deviceId?.let { id ->
|
||||
val newAlertAudio = if (binding.swWarningVoice.isChecked) "1" else "0"
|
||||
// 只有状态发生变化时才请求
|
||||
if (newAlertAudio != originalAlertAudio) {
|
||||
// 点击返回时总是触发网络请求
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
try {
|
||||
val deviceBean = DeviceBean(id = id, alertAudio = newAlertAudio)
|
||||
@@ -89,20 +88,23 @@ class VoiceSettingsActivity : AppCompatActivity() {
|
||||
if (response.code == 200 && response.data != null) {
|
||||
Toast.makeText(this@VoiceSettingsActivity, "修改成功", Toast.LENGTH_SHORT).show()
|
||||
} else {
|
||||
// 仅在状态实际发生变化时才显示错误提示
|
||||
if (newAlertAudio != originalAlertAudio) {
|
||||
Toast.makeText(this@VoiceSettingsActivity, response.msg, Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
finish()
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
withContext(Dispatchers.Main) {
|
||||
// 仅在状态实际发生变化时才显示失败提示
|
||||
if (newAlertAudio != originalAlertAudio) {
|
||||
Toast.makeText(this@VoiceSettingsActivity, "修改失败", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
finish()
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
finish()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -10,6 +10,7 @@ import bean.ForgotRequest
|
||||
import com.ckkj.defense_device.R
|
||||
import com.ckkj.defense_device.databinding.ForgetPasswordActivityBinding
|
||||
import com.ckkj.defense_device.utils.RetrofitNetwork
|
||||
import com.ckkj.defense_device.view.LoadingDialog
|
||||
import com.google.firebase.crashlytics.buildtools.reloc.org.apache.http.util.TextUtils
|
||||
import com.gyf.immersionbar.ImmersionBar
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
@@ -20,6 +21,7 @@ import java.util.regex.Pattern
|
||||
|
||||
class ForgetPasswordActivity : AppCompatActivity() {
|
||||
private lateinit var binding: ForgetPasswordActivityBinding
|
||||
private var isLoading = false
|
||||
private var countDownTimer: CountDownTimer? = null
|
||||
private var isSendingCode = false
|
||||
|
||||
@@ -63,9 +65,11 @@ class ForgetPasswordActivity : AppCompatActivity() {
|
||||
}
|
||||
|
||||
binding.btnNext.setOnClickListener {
|
||||
if (!isLoading) {
|
||||
performResetPassword()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun isPhoneNumberValid(phone: String): Boolean {
|
||||
if (TextUtils.isEmpty(phone)) return false
|
||||
@@ -163,8 +167,11 @@ class ForgetPasswordActivity : AppCompatActivity() {
|
||||
return
|
||||
}
|
||||
|
||||
isLoading = true
|
||||
binding.btnNext.isEnabled = false
|
||||
binding.btnNext.text = "重置中..."
|
||||
val loadingDialog = LoadingDialog(this)
|
||||
.setMessage(getString(R.string.resetting))
|
||||
.apply { show() }
|
||||
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
try {
|
||||
@@ -175,8 +182,9 @@ class ForgetPasswordActivity : AppCompatActivity() {
|
||||
)
|
||||
val response = RetrofitNetwork.getNetworkService().forgotPassword(forgotRequest)
|
||||
withContext(Dispatchers.Main) {
|
||||
isLoading = false
|
||||
loadingDialog.dismiss()
|
||||
binding.btnNext.isEnabled = true
|
||||
binding.btnNext.text = "确定"
|
||||
|
||||
if (response.code == 200) {
|
||||
Toast.makeText(this@ForgetPasswordActivity, R.string.reset_success, Toast.LENGTH_SHORT).show()
|
||||
@@ -187,8 +195,9 @@ class ForgetPasswordActivity : AppCompatActivity() {
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
withContext(Dispatchers.Main) {
|
||||
isLoading = false
|
||||
loadingDialog.dismiss()
|
||||
binding.btnNext.isEnabled = true
|
||||
binding.btnNext.text = "确定"
|
||||
Toast.makeText(this@ForgetPasswordActivity, R.string.network_error, Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import android.graphics.Color
|
||||
import android.graphics.drawable.GradientDrawable
|
||||
import android.os.Bundle
|
||||
import android.os.CountDownTimer
|
||||
import android.util.Log
|
||||
import android.view.View
|
||||
import android.widget.Toast
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
@@ -194,6 +195,7 @@ class LoginActivity : AppCompatActivity() {
|
||||
try {
|
||||
val response = RetrofitNetwork.getNetworkService().getCode(phone)
|
||||
withContext(Dispatchers.Main) {
|
||||
Log.d("VerificationCode", "code = ${response.code}, msg = ${response.msg}")
|
||||
if (response.code == 200) {
|
||||
Toast.makeText(this@LoginActivity, getString(R.string.code_sent_to, phone), Toast.LENGTH_SHORT).show()
|
||||
startCountDown()
|
||||
|
||||
@@ -11,6 +11,7 @@ import bean.RegisterRequest
|
||||
import com.ckkj.defense_device.R
|
||||
import com.ckkj.defense_device.databinding.RegisterActivityBinding
|
||||
import com.ckkj.defense_device.utils.RetrofitNetwork
|
||||
import com.ckkj.defense_device.view.LoadingDialog
|
||||
import com.gyf.immersionbar.ImmersionBar
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
@@ -158,7 +159,9 @@ class RegisterActivity : AppCompatActivity() {
|
||||
|
||||
isLoading = true
|
||||
binding.btnNext.isEnabled = false
|
||||
binding.btnNext.text = getString(R.string.registering)
|
||||
val loadingDialog = LoadingDialog(this)
|
||||
.setMessage(getString(R.string.registering))
|
||||
.apply { show() }
|
||||
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
try {
|
||||
@@ -174,8 +177,8 @@ class RegisterActivity : AppCompatActivity() {
|
||||
val response = RetrofitNetwork.getNetworkService().register(registerRequest)
|
||||
withContext(Dispatchers.Main) {
|
||||
isLoading = false
|
||||
loadingDialog.dismiss()
|
||||
binding.btnNext.isEnabled = true
|
||||
binding.btnNext.text = getString(R.string.next_step)
|
||||
|
||||
if (response.code == 200) {
|
||||
Toast.makeText(this@RegisterActivity, R.string.register_success, Toast.LENGTH_SHORT).show()
|
||||
@@ -190,8 +193,8 @@ class RegisterActivity : AppCompatActivity() {
|
||||
} catch (e: Exception) {
|
||||
withContext(Dispatchers.Main) {
|
||||
isLoading = false
|
||||
loadingDialog.dismiss()
|
||||
binding.btnNext.isEnabled = true
|
||||
binding.btnNext.text = getString(R.string.next_step)
|
||||
Toast.makeText(this@RegisterActivity, R.string.network_error, Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,32 +1,45 @@
|
||||
package com.ckkj.defense_device.personal
|
||||
|
||||
import android.Manifest
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageManager
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.Canvas
|
||||
import android.graphics.Color
|
||||
import android.graphics.Paint
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.os.Environment
|
||||
import android.util.Log
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.widget.Toast
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import com.google.android.material.bottomsheet.BottomSheetDialog
|
||||
import androidx.core.content.ContextCompat
|
||||
import com.ckkj.defense_device.R
|
||||
import com.ckkj.defense_device.bean.RecommendationCodeBean
|
||||
import com.ckkj.defense_device.bean.SelectInviterInfoBean
|
||||
import com.ckkj.defense_device.bean.VerifyOptionPasswordRequest
|
||||
import com.ckkj.defense_device.databinding.DialogExpireTimeBinding
|
||||
import com.ckkj.defense_device.databinding.InvitationCodeActivityBinding
|
||||
import com.ckkj.defense_device.utils.RetrofitNetwork
|
||||
import com.ckkj.defense_device.view.LoadingDialog
|
||||
import com.google.gson.Gson
|
||||
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 com.maning.mlkitscanner.scan.MNScanManager
|
||||
import com.maning.mlkitscanner.scan.callback.act.MNScanCallback
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.json.JSONObject
|
||||
import java.io.File
|
||||
import java.io.FileOutputStream
|
||||
import java.util.Hashtable
|
||||
@@ -44,7 +57,24 @@ class InvitationCodeActivity : AppCompatActivity() {
|
||||
private var isLoading = false // 是否正在加载
|
||||
private var hasGeneratedQrCode = false // 是否已经生成过二维码
|
||||
|
||||
private val requestPermissionsLauncher = registerForActivityResult(
|
||||
ActivityResultContracts.RequestMultiplePermissions()
|
||||
) { permissions ->
|
||||
val cameraGranted = permissions[Manifest.permission.CAMERA] ?: false
|
||||
val storageGranted = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
permissions[Manifest.permission.READ_MEDIA_IMAGES] ?: false
|
||||
} else {
|
||||
permissions[Manifest.permission.READ_EXTERNAL_STORAGE] ?: false
|
||||
}
|
||||
if (cameraGranted && storageGranted) {
|
||||
startScan()
|
||||
} else {
|
||||
Toast.makeText(this, R.string.permission_denied, Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val TAG = "InvitationCodeActivity"
|
||||
const val EXPIRE_24H = 24 * 60 * 60 * 1000L
|
||||
const val EXPIRE_7D = 7 * 24 * 60 * 60 * 1000L
|
||||
}
|
||||
@@ -90,15 +120,136 @@ class InvitationCodeActivity : AppCompatActivity() {
|
||||
|
||||
// 撤销邀请按钮
|
||||
binding.btnCancelInvite.setOnClickListener {
|
||||
showPasswordDialog {
|
||||
cancelInvitation()
|
||||
if (generatedInviteCode.isEmpty()) {
|
||||
ToastUtils.showError(this, getString(R.string.qr_code_expired))
|
||||
return@setOnClickListener
|
||||
}
|
||||
showPasswordDialog { password, dialog ->
|
||||
cancelInvitation(password, dialog)
|
||||
}
|
||||
}
|
||||
|
||||
// 生成/重新生成按钮
|
||||
binding.btnRegenerate.setOnClickListener {
|
||||
showPasswordDialog {
|
||||
generateOrRegenerateInvitation()
|
||||
showPasswordDialog { password, dialog ->
|
||||
generateOrRegenerateInvitation(password, dialog)
|
||||
}
|
||||
}
|
||||
binding.sys.setOnClickListener {
|
||||
checkPermissionsAndScan()
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkPermissionsAndScan() {
|
||||
val cameraPermission = ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA)
|
||||
val storagePermission = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
ContextCompat.checkSelfPermission(this, Manifest.permission.READ_MEDIA_IMAGES)
|
||||
} else {
|
||||
ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)
|
||||
}
|
||||
if (cameraPermission == PackageManager.PERMISSION_GRANTED &&
|
||||
storagePermission == PackageManager.PERMISSION_GRANTED
|
||||
) {
|
||||
startScan()
|
||||
} else {
|
||||
val permissionsToRequest = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
arrayOf(
|
||||
Manifest.permission.CAMERA,
|
||||
Manifest.permission.READ_MEDIA_IMAGES
|
||||
)
|
||||
} else {
|
||||
arrayOf(
|
||||
Manifest.permission.CAMERA,
|
||||
Manifest.permission.WRITE_EXTERNAL_STORAGE
|
||||
)
|
||||
}
|
||||
requestPermissionsLauncher.launch(permissionsToRequest)
|
||||
}
|
||||
}
|
||||
|
||||
private fun startScan() {
|
||||
MNScanManager.startScan(this, object : MNScanCallback {
|
||||
override fun onActivityResult(resultCode: Int, data: Intent?) {
|
||||
when (resultCode) {
|
||||
MNScanManager.RESULT_SUCCESS -> {
|
||||
val result = data?.getStringArrayListExtra(MNScanManager.INTENT_KEY_RESULT_SUCCESS)
|
||||
if (!result.isNullOrEmpty()) {
|
||||
val inviteCode = parseInviteCode(result[0])
|
||||
if (inviteCode.isNullOrEmpty()) {
|
||||
Toast.makeText(this@InvitationCodeActivity, "无效的邀请码", Toast.LENGTH_SHORT).show()
|
||||
} else {
|
||||
fetchInviterInfo(inviteCode)
|
||||
}
|
||||
} else {
|
||||
Toast.makeText(this@InvitationCodeActivity, "扫码结果为空", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
MNScanManager.RESULT_FAIL -> {
|
||||
val error = data?.getStringExtra(MNScanManager.INTENT_KEY_RESULT_ERROR)
|
||||
Toast.makeText(this@InvitationCodeActivity, "扫码失败: $error", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
MNScanManager.RESULT_CANCLE -> {
|
||||
Toast.makeText(this@InvitationCodeActivity, "扫码取消", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun parseInviteCode(scanResult: String): String? {
|
||||
val trimmed = scanResult.trim()
|
||||
if (trimmed.isEmpty()) return null
|
||||
return try {
|
||||
if (trimmed.startsWith("{")) {
|
||||
JSONObject(trimmed).optString("code").takeIf { it.isNotEmpty() }
|
||||
} else {
|
||||
trimmed
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
trimmed
|
||||
}
|
||||
}
|
||||
|
||||
private fun fetchInviterInfo(inviteCode: String) {
|
||||
val loadingDialog = LoadingDialog(this).apply { show() }
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
try {
|
||||
val response = RetrofitNetwork.getNetworkService()
|
||||
.selectInviterInfo(SelectInviterInfoBean(code = inviteCode))
|
||||
withContext(Dispatchers.Main) {
|
||||
loadingDialog.dismiss()
|
||||
if (response.code == 200 && response.data != null) {
|
||||
val inviter = response.data
|
||||
val parentId = inviter.resolveParentId()
|
||||
if (parentId.isNullOrEmpty()) {
|
||||
Toast.makeText(
|
||||
this@InvitationCodeActivity,
|
||||
getString(R.string.network_error),
|
||||
Toast.LENGTH_SHORT
|
||||
).show()
|
||||
return@withContext
|
||||
}
|
||||
val intent = Intent(this@InvitationCodeActivity, JoinFamilyInviteActivity::class.java).apply {
|
||||
putExtra(JoinFamilyInviteActivity.EXTRA_INVITE_CODE, inviteCode)
|
||||
putExtra(JoinFamilyInviteActivity.EXTRA_NICK_NAME, inviter.nickName)
|
||||
putExtra(JoinFamilyInviteActivity.EXTRA_AVATAR, inviter.avatar)
|
||||
putExtra(JoinFamilyInviteActivity.EXTRA_PARENT_ID, parentId)
|
||||
putExtra(JoinFamilyInviteActivity.EXTRA_USER_ID, inviter.userId)
|
||||
}
|
||||
startActivity(intent)
|
||||
} else {
|
||||
Toast.makeText(
|
||||
this@InvitationCodeActivity,
|
||||
response.msg.ifBlank { getString(R.string.network_error) },
|
||||
Toast.LENGTH_SHORT
|
||||
).show()
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
withContext(Dispatchers.Main) {
|
||||
loadingDialog.dismiss()
|
||||
Toast.makeText(this@InvitationCodeActivity, R.string.network_error, Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -106,14 +257,56 @@ class InvitationCodeActivity : AppCompatActivity() {
|
||||
/**
|
||||
* 生成或重新生成邀请码
|
||||
*/
|
||||
private fun generateOrRegenerateInvitation() {
|
||||
// 根据当前选择的时效生成邀请码
|
||||
private fun generateOrRegenerateInvitation(password: String, passwordDialog: PasswordInputDialog) {
|
||||
if (isLoading) return
|
||||
isLoading = true
|
||||
val loadingDialog = LoadingDialog(this).apply { show() }
|
||||
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
try {
|
||||
val response = RetrofitNetwork.getNetworkService()
|
||||
.generateRecommendationCode(VerifyOptionPasswordRequest(password))
|
||||
Log.d(TAG, "生成推荐码响应: code=${response.code}, msg=${response.msg}, data=${response.data}")
|
||||
withContext(Dispatchers.Main) {
|
||||
isLoading = false
|
||||
loadingDialog.dismiss()
|
||||
if (response.code == 200) {
|
||||
val parsed = parseRecommendationCode(response.data)
|
||||
if (parsed != null) {
|
||||
passwordDialog.dismiss()
|
||||
generatedInviteCode = parsed.first
|
||||
expireTimestamp = parsed.second
|
||||
qrCodeContent =
|
||||
"{\"type\":\"invite\",\"code\":\"$generatedInviteCode\",\"expire\":$expireTimestamp}"
|
||||
Log.d(
|
||||
TAG,
|
||||
"推荐码生成成功: Code=$generatedInviteCode, expireTimestamp=$expireTimestamp, qrContent=$qrCodeContent"
|
||||
)
|
||||
generateQRCode()
|
||||
showQrCode()
|
||||
// 更新按钮文字为"重新生成"
|
||||
binding.btnRegenerate.text = getString(R.string.regenerate)
|
||||
hasGeneratedQrCode = true
|
||||
ToastUtils.showSuccess(this, getString(R.string.operation_success))
|
||||
ToastUtils.showSuccess(this@InvitationCodeActivity, getString(R.string.operation_success))
|
||||
} else {
|
||||
Log.w(TAG, "推荐码解析失败, raw data=${response.data}")
|
||||
passwordDialog.showError(getString(R.string.network_error))
|
||||
}
|
||||
} else {
|
||||
Log.w(TAG, "生成推荐码失败: code=${response.code}, msg=${response.msg}")
|
||||
passwordDialog.showError(
|
||||
response.msg.ifEmpty { getString(R.string.password_error) }
|
||||
)
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "生成推荐码异常", e)
|
||||
withContext(Dispatchers.Main) {
|
||||
isLoading = false
|
||||
loadingDialog.dismiss()
|
||||
passwordDialog.showError(getString(R.string.network_error))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun showExpireTimeDialog() {
|
||||
@@ -151,9 +344,6 @@ class InvitationCodeActivity : AppCompatActivity() {
|
||||
binding.tvExpireTime.text = getString(R.string.expire_7d)
|
||||
}
|
||||
}
|
||||
// 显示二维码并生成
|
||||
showQrCode()
|
||||
generateQRCode()
|
||||
expireTimeDialog?.dismiss()
|
||||
}
|
||||
|
||||
@@ -173,22 +363,28 @@ class InvitationCodeActivity : AppCompatActivity() {
|
||||
}
|
||||
|
||||
private fun generateQRCode() {
|
||||
// 检查二维码是否过期,如果过期则生成新的邀请码
|
||||
val isExpired = expireTimestamp > 0 && System.currentTimeMillis() > expireTimestamp
|
||||
val content = if (qrCodeContent.isNotEmpty() && !isExpired) qrCodeContent else generateInviteCode()
|
||||
val qrBitmap = createQRCodeWithLogo(content, 400, 400)
|
||||
if (qrCodeContent.isEmpty()) return
|
||||
val qrBitmap = createQRCodeWithLogo(qrCodeContent, 400, 400)
|
||||
binding.ivQrCode.setImageBitmap(qrBitmap)
|
||||
}
|
||||
|
||||
private fun generateInviteCode(): String {
|
||||
val timestamp = System.currentTimeMillis()
|
||||
expireTimestamp = timestamp + expireTimeInMillis
|
||||
generatedInviteCode = "INV${timestamp}"
|
||||
qrCodeContent = "{\"type\":\"invite\",\"code\":\"$generatedInviteCode\",\"expire\":$expireTimestamp}"
|
||||
// 输出日志,方便调试验证
|
||||
android.util.Log.d("InvitationCode", "生成的二维码内容: $qrCodeContent")
|
||||
android.util.Log.d("InvitationCode", "推荐码: $generatedInviteCode, 过期时间戳: $expireTimestamp")
|
||||
return qrCodeContent
|
||||
private fun parseRecommendationCode(data: Any?): Pair<String, Long>? {
|
||||
if (data == null) return null
|
||||
return when (data) {
|
||||
is String -> {
|
||||
if (data.isEmpty()) null
|
||||
else Pair(data, System.currentTimeMillis() + expireTimeInMillis)
|
||||
}
|
||||
else -> {
|
||||
val bean = Gson().fromJson(Gson().toJson(data), RecommendationCodeBean::class.java)
|
||||
val code = bean.inviteCode?.takeIf { it.isNotEmpty() }
|
||||
?: bean.code?.takeIf { it.isNotEmpty() }
|
||||
?: return null
|
||||
val expire = bean.expireTime ?: bean.expire
|
||||
?: (System.currentTimeMillis() + expireTimeInMillis)
|
||||
Pair(code, expire)
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
* 这段代码生成带Logo的二维码:
|
||||
@@ -415,55 +611,61 @@ class InvitationCodeActivity : AppCompatActivity() {
|
||||
/**
|
||||
* 撤销邀请
|
||||
*/
|
||||
private fun cancelInvitation() {
|
||||
// 撤销邀请逻辑
|
||||
private fun cancelInvitation(password: String, passwordDialog: PasswordInputDialog) {
|
||||
if (isLoading) return
|
||||
if (generatedInviteCode.isEmpty()) {
|
||||
passwordDialog.showError(getString(R.string.qr_code_expired))
|
||||
return
|
||||
}
|
||||
isLoading = true
|
||||
val loadingDialog = LoadingDialog(this).apply { show() }
|
||||
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
try {
|
||||
val response = RetrofitNetwork.getNetworkService()
|
||||
.revokeInvitation(VerifyOptionPasswordRequest(password))
|
||||
Log.d(TAG, "撤销邀请响应: code=${response.code}, msg=${response.msg}")
|
||||
withContext(Dispatchers.Main) {
|
||||
isLoading = false
|
||||
loadingDialog.dismiss()
|
||||
if (response.code == 200) {
|
||||
passwordDialog.dismiss()
|
||||
hideQrCode()
|
||||
generatedInviteCode = ""
|
||||
qrCodeContent = ""
|
||||
expireTimestamp = 0
|
||||
hasGeneratedQrCode = false
|
||||
// 恢复按钮文字为"生成邀请码"
|
||||
binding.btnRegenerate.text = getString(R.string.generate_invite_code)
|
||||
// 显示提示
|
||||
ToastUtils.showSuccess(this, getString(R.string.operation_success))
|
||||
ToastUtils.showSuccess(this@InvitationCodeActivity, getString(R.string.operation_success))
|
||||
} else {
|
||||
passwordDialog.showError(
|
||||
response.msg.ifEmpty { getString(R.string.password_error) }
|
||||
)
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "撤销邀请异常", e)
|
||||
withContext(Dispatchers.Main) {
|
||||
isLoading = false
|
||||
loadingDialog.dismiss()
|
||||
passwordDialog.showError(getString(R.string.network_error))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 显示密码输入对话框
|
||||
* @param onSuccess 验证成功后的回调
|
||||
*/
|
||||
private fun showPasswordDialog(onSuccess: () -> Unit) {
|
||||
private fun showPasswordDialog(onConfirm: (String, PasswordInputDialog) -> Unit) {
|
||||
val dialog = PasswordInputDialog(this)
|
||||
dialog.setTitle(getString(R.string.input_op_pwd))
|
||||
dialog.setOnConfirmListener { password ->
|
||||
verifyPassword(password, dialog, onSuccess)
|
||||
onConfirm(password, dialog)
|
||||
}
|
||||
dialog.show()
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证操作密码
|
||||
*/
|
||||
private fun verifyPassword(password: String, dialog: PasswordInputDialog, onSuccess: () -> Unit) {
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
try {
|
||||
val response = RetrofitNetwork.getNetworkService()
|
||||
.verifyOptionPassword(VerifyOptionPasswordRequest(password))
|
||||
withContext(Dispatchers.Main) {
|
||||
if (response.code == 200) {
|
||||
dialog.dismiss()
|
||||
onSuccess.invoke()
|
||||
} else {
|
||||
dialog.showError(getString(R.string.password_error))
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
withContext(Dispatchers.Main) {
|
||||
dialog.showError(getString(R.string.network_error))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
|
||||
@@ -0,0 +1,123 @@
|
||||
package com.ckkj.defense_device.personal
|
||||
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import android.widget.Toast
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import com.bumptech.glide.Glide
|
||||
import com.bumptech.glide.request.RequestOptions
|
||||
import com.ckkj.defense_device.R
|
||||
import com.ckkj.defense_device.bean.JoinTheFamilyBean
|
||||
import com.ckkj.defense_device.databinding.JoinFamilyInviteActivityBinding
|
||||
import com.ckkj.defense_device.home.HomeActivity
|
||||
import com.ckkj.defense_device.utils.RetrofitNetwork
|
||||
import com.ckkj.defense_device.view.LoadingDialog
|
||||
import com.gyf.immersionbar.ImmersionBar
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
// 邀请加入家庭
|
||||
class JoinFamilyInviteActivity : AppCompatActivity() {
|
||||
|
||||
private lateinit var binding: JoinFamilyInviteActivityBinding
|
||||
private var isLoading = false
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
binding = JoinFamilyInviteActivityBinding.inflate(layoutInflater)
|
||||
setContentView(binding.root)
|
||||
|
||||
ImmersionBar.with(this)
|
||||
.statusBarDarkFont(true)
|
||||
.titleBar(binding.topBar)
|
||||
.init()
|
||||
|
||||
binding.ivBack.setOnClickListener { finish() }
|
||||
binding.btnJoinNow.setOnClickListener { joinFamily() }
|
||||
displayInviterInfo()
|
||||
}
|
||||
|
||||
private fun joinFamily() {
|
||||
if (isLoading) return
|
||||
|
||||
val parentId = intent.getStringExtra(EXTRA_USER_ID).orEmpty()
|
||||
val inviteCode = intent.getStringExtra(EXTRA_INVITE_CODE).orEmpty()
|
||||
if (parentId.isEmpty() || inviteCode.isEmpty()) {
|
||||
Log.e(TAG, "加入家庭参数无效: parentId=$parentId, inviteCode=$inviteCode")
|
||||
Toast.makeText(this, R.string.network_error, Toast.LENGTH_SHORT).show()
|
||||
return
|
||||
}
|
||||
|
||||
Log.e(TAG, "加入家庭请求: parentId=$parentId, inviteCode=$inviteCode")
|
||||
isLoading = true
|
||||
val loadingDialog = LoadingDialog(this).apply { show() }
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
try {
|
||||
val response = RetrofitNetwork.getNetworkService()
|
||||
.joinTheFamily(JoinTheFamilyBean(parentId = parentId, inviteCode = inviteCode))
|
||||
Log.e(TAG, "加入家庭响应: code=${response.code}, msg=${response.msg}, data=${response.data}")
|
||||
withContext(Dispatchers.Main) {
|
||||
isLoading = false
|
||||
loadingDialog.dismiss()
|
||||
if (response.code == 200) {
|
||||
Log.e(TAG, "加入家庭成功,返回首页刷新")
|
||||
ToastUtils.showSuccess(this@JoinFamilyInviteActivity, getString(R.string.operation_success))
|
||||
val homeIntent = Intent(this@JoinFamilyInviteActivity, HomeActivity::class.java).apply {
|
||||
flags = Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP
|
||||
putExtra(HomeActivity.EXTRA_REFRESH, true)
|
||||
}
|
||||
startActivity(homeIntent)
|
||||
finish()
|
||||
} else {
|
||||
Log.e(TAG, "加入家庭失败: code=${response.code}, msg=${response.msg}")
|
||||
Toast.makeText(
|
||||
this@JoinFamilyInviteActivity,
|
||||
response.msg.ifBlank { getString(R.string.network_error) },
|
||||
Toast.LENGTH_SHORT
|
||||
).show()
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "加入家庭请求异常", e)
|
||||
withContext(Dispatchers.Main) {
|
||||
isLoading = false
|
||||
loadingDialog.dismiss()
|
||||
Toast.makeText(this@JoinFamilyInviteActivity, R.string.network_error, Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun displayInviterInfo() {
|
||||
val nickName = intent.getStringExtra(EXTRA_NICK_NAME).orEmpty()
|
||||
val avatar = intent.getStringExtra(EXTRA_AVATAR)
|
||||
|
||||
binding.tvNickname.text = nickName.ifEmpty { getString(R.string.nickname_placeholder) }
|
||||
binding.tvInviteMessage.text = getString(
|
||||
R.string.invite_join_family_message,
|
||||
nickName.ifEmpty { getString(R.string.nickname_placeholder) }
|
||||
)
|
||||
|
||||
val requestOptions = RequestOptions()
|
||||
.placeholder(R.mipmap.img)
|
||||
.error(R.mipmap.img)
|
||||
|
||||
Glide.with(this)
|
||||
.load(avatar)
|
||||
.apply(requestOptions)
|
||||
.circleCrop()
|
||||
.into(binding.ivAvatar)
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val TAG = "JoinFamilyInviteActivity"
|
||||
const val EXTRA_INVITE_CODE = "invite_code"
|
||||
const val EXTRA_NICK_NAME = "nick_name"
|
||||
const val EXTRA_AVATAR = "avatar"
|
||||
const val EXTRA_PARENT_ID = "parent_id"
|
||||
const val EXTRA_USER_ID = "user_id"
|
||||
}
|
||||
}
|
||||
@@ -138,7 +138,7 @@ object ApiConfig {
|
||||
*/
|
||||
private fun buildFakeErrorResponse(request: Request, msg: String, code: Int = 1): Response {
|
||||
val baseInfo = BaseInfo(
|
||||
message = msg,
|
||||
msg = msg,
|
||||
code = code,
|
||||
data = null,
|
||||
)
|
||||
|
||||
@@ -14,11 +14,15 @@ import com.ckkj.defense_device.bean.DeleteBean
|
||||
import com.ckkj.defense_device.bean.DeleteDeviceUserRequest
|
||||
import com.ckkj.defense_device.bean.DeviceAlarmResponse
|
||||
import com.ckkj.defense_device.bean.FamilyMembersBean
|
||||
import com.ckkj.defense_device.bean.InviterInfoBean
|
||||
import com.ckkj.defense_device.bean.JoinTheFamilyBean
|
||||
import com.ckkj.defense_device.bean.MessageBean
|
||||
import com.ckkj.defense_device.bean.MessageListResponse
|
||||
import com.ckkj.defense_device.bean.ObtainInviterInformationBean
|
||||
import com.ckkj.defense_device.bean.ObtainInviterInformationRequest
|
||||
import com.ckkj.defense_device.bean.SelectInviterInfoBean
|
||||
import com.ckkj.defense_device.bean.SwitchFamilyRequest
|
||||
import com.ckkj.defense_device.bean.UpdateFamilyUserRequest
|
||||
import com.ckkj.defense_device.bean.UpdatePassword
|
||||
import com.ckkj.defense_device.bean.UpdateUserInfo
|
||||
import com.ckkj.defense_device.bean.UploadResponse
|
||||
@@ -191,7 +195,7 @@ interface ApiService {
|
||||
|
||||
|
||||
/**
|
||||
* 获取邀请人信息
|
||||
* 获取家庭成员信息
|
||||
*/
|
||||
@POST("/app/obtainInviterInformation")
|
||||
suspend fun obtainInviterInformation(@Body request: ObtainInviterInformationRequest): GetCodeBean<ObtainInviterInformationBean>
|
||||
@@ -250,8 +254,22 @@ interface ApiService {
|
||||
/**
|
||||
* 修改家庭用户状态
|
||||
*/
|
||||
//@POST("/app/updateFamilyUser")
|
||||
@POST("/app/updateFamilyUser")
|
||||
suspend fun updateFamilyUser(@Body request: UpdateFamilyUserRequest): GetCodeBean<Any>
|
||||
|
||||
|
||||
/**
|
||||
* 获取邀请人信息
|
||||
*/
|
||||
@POST("/app/selectInviterInfo")
|
||||
suspend fun selectInviterInfo(@Body request: SelectInviterInfoBean): GetCodeBean<InviterInfoBean>
|
||||
|
||||
|
||||
/**
|
||||
* 加入xxx家庭
|
||||
*/
|
||||
@POST("/app/joinTheFamily")
|
||||
suspend fun joinTheFamily(@Body request: JoinTheFamilyBean): GetCodeBean<Any>
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@ object RetrofitNetwork {
|
||||
|
||||
private const val DEFAULT_TIMEOUT = 30L
|
||||
const val BASE_URL = "https://stem-boozy-margarine.ngrok-free.dev"
|
||||
//const val BASE_URL = "http://service.reinkun.com:8001"
|
||||
|
||||
private var retrofit: Retrofit? = null
|
||||
private val gson = Gson()
|
||||
|
||||
@@ -5,5 +5,5 @@
|
||||
<stroke
|
||||
android:width="1dp"
|
||||
android:color="@color/green" />
|
||||
<corners android:radius="8dp" />
|
||||
<corners android:radius="25dp" />
|
||||
</shape>
|
||||
@@ -2,5 +2,5 @@
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
<solid android:color="@color/green" />
|
||||
<corners android:radius="8dp" />
|
||||
<corners android:radius="25dp" />
|
||||
</shape>
|
||||
@@ -164,6 +164,8 @@
|
||||
android:background="@drawable/rounded_blue_bg"
|
||||
android:paddingHorizontal="12dp"
|
||||
android:maxWidth="120dp"
|
||||
android:elevation="0dp"
|
||||
android:stateListAnimator="@null"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
@@ -223,6 +225,8 @@
|
||||
android:layout_marginTop="40dp"
|
||||
android:text="@string/login"
|
||||
android:textSize="18sp"
|
||||
android:elevation="0dp"
|
||||
android:stateListAnimator="@null"
|
||||
android:background="@drawable/rounded_blue_bg"
|
||||
android:textColor="@color/white"
|
||||
app:layout_constraintTop_toBottomOf="@+id/smsRowLayout"
|
||||
|
||||
@@ -123,6 +123,8 @@
|
||||
android:textColor="@color/white"
|
||||
android:textSize="16dp"
|
||||
android:textStyle="bold"
|
||||
android:elevation="0dp"
|
||||
android:stateListAnimator="@null"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
|
||||
@@ -80,6 +80,8 @@
|
||||
android:background="@drawable/rounded_blue_bg"
|
||||
android:text="@string/select_wifi"
|
||||
android:textColor="@color/white"
|
||||
android:elevation="0dp"
|
||||
android:stateListAnimator="@null"
|
||||
android:textSize="14sp" />
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
@@ -88,8 +88,41 @@
|
||||
android:paddingBottom="16dp"/>
|
||||
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
|
||||
|
||||
<!-- 空页面 -->
|
||||
<LinearLayout
|
||||
android:id="@+id/layoutNoPermission"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:gravity="center"
|
||||
android:orientation="vertical"
|
||||
android:visibility="gone">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="244dp"
|
||||
android:layout_height="131dp"
|
||||
android:src="@mipmap/default_page"/>
|
||||
|
||||
</LinearLayout>
|
||||
<LinearLayout
|
||||
android:id="@+id/layoutNoNetwork"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:gravity="center"
|
||||
android:orientation="vertical"
|
||||
android:paddingHorizontal="32dp"
|
||||
android:background="@color/white"
|
||||
android:visibility="gone">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="244dp"
|
||||
android:layout_height="131dp"
|
||||
android:src="@mipmap/no_network_img_name" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<!-- 底部按钮 -->
|
||||
<LinearLayout
|
||||
android:id="@+id/butting"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingHorizontal="16dp"
|
||||
@@ -102,6 +135,8 @@
|
||||
android:text="@string/confirm"
|
||||
android:textColor="@color/white"
|
||||
android:textSize="14dp"
|
||||
android:elevation="0dp"
|
||||
android:stateListAnimator="@null"
|
||||
android:background="@drawable/rounded_blue_bg" />
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
@@ -105,6 +105,8 @@
|
||||
android:textAllCaps="false"
|
||||
android:textColor="@color/white"
|
||||
android:textSize="16sp"
|
||||
android:elevation="0dp"
|
||||
android:stateListAnimator="@null"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/etConfirmPassword" />
|
||||
|
||||
@@ -287,6 +287,8 @@
|
||||
android:textColor="@color/white"
|
||||
android:textSize="14dp"
|
||||
android:textStyle="bold"
|
||||
android:elevation="0dp"
|
||||
android:stateListAnimator="@null"
|
||||
android:background="@drawable/rounded_blue_bg"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
|
||||
@@ -107,6 +107,8 @@
|
||||
android:textSize="17sp"
|
||||
android:textStyle="bold"
|
||||
android:background="@drawable/bg_capture_face_button"
|
||||
android:elevation="0dp"
|
||||
android:stateListAnimator="@null"
|
||||
android:textColor="#F2FFFFFF" />
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
@@ -153,6 +153,8 @@
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
android:elevation="0dp"
|
||||
android:stateListAnimator="@null"
|
||||
android:layout_marginStart="12dp" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
@@ -251,6 +253,8 @@
|
||||
android:textSize="16sp"
|
||||
app:cornerRadius="12dp"
|
||||
android:textColor="@color/white"
|
||||
android:elevation="0dp"
|
||||
android:stateListAnimator="@null"
|
||||
android:background="@drawable/rounded_blue_bg"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
|
||||
@@ -168,6 +168,22 @@
|
||||
android:src="@mipmap/default_page" />
|
||||
|
||||
</LinearLayout>
|
||||
<LinearLayout
|
||||
android:id="@+id/layoutNoNetwork"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:gravity="center"
|
||||
android:orientation="vertical"
|
||||
android:paddingHorizontal="32dp"
|
||||
android:background="@color/white"
|
||||
android:visibility="gone">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="244dp"
|
||||
android:layout_height="131dp"
|
||||
android:src="@mipmap/no_network_img_name" />
|
||||
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
||||
<View
|
||||
|
||||
@@ -118,6 +118,7 @@
|
||||
</FrameLayout>
|
||||
<!-- 使用智能文字和图标 -->
|
||||
<LinearLayout
|
||||
android:id="@+id/sys"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
@@ -125,16 +126,16 @@
|
||||
android:gravity="center_vertical">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="20dp"
|
||||
android:layout_height="20dp"
|
||||
android:src="@drawable/syis" />
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"
|
||||
android:src="@mipmap/syis" />
|
||||
|
||||
<TextView
|
||||
android:textColor="@color/green"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="8dp"
|
||||
android:text="@string/use_smart_defense_app"
|
||||
android:textColor="@color/black"
|
||||
android:textSize="14sp" />
|
||||
</LinearLayout>
|
||||
|
||||
@@ -211,6 +212,8 @@
|
||||
android:layout_marginEnd="12dp"
|
||||
android:text="@string/cancel_invite"
|
||||
android:textColor="@color/green"
|
||||
android:elevation="0dp"
|
||||
android:stateListAnimator="@null"
|
||||
android:textSize="16sp"
|
||||
android:background="@drawable/bg_blue_border_round"
|
||||
android:textAllCaps="false" />
|
||||
@@ -223,6 +226,8 @@
|
||||
android:text="@string/regenerate"
|
||||
android:textColor="@color/white"
|
||||
android:textSize="16sp"
|
||||
android:elevation="0dp"
|
||||
android:stateListAnimator="@null"
|
||||
android:background="@drawable/bg_blue_round"
|
||||
android:textAllCaps="false" />
|
||||
</LinearLayout>
|
||||
|
||||
90
app/src/main/res/layout/join_family_invite_activity.xml
Normal file
@@ -0,0 +1,90 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/main"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@color/white"
|
||||
tools:context=".personal.JoinFamilyInviteActivity">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/topBar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="56dp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/ivBack"
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"
|
||||
android:layout_marginStart="16dp"
|
||||
android:contentDescription="@string/back"
|
||||
android:src="@mipmap/back"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/contentLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center_horizontal"
|
||||
android:orientation="vertical"
|
||||
android:paddingHorizontal="32dp"
|
||||
app:layout_constraintBottom_toTopOf="@id/btnJoinNow"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/topBar"
|
||||
app:layout_constraintVertical_bias="0.35">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/ivAvatar"
|
||||
android:layout_width="88dp"
|
||||
android:layout_height="88dp"
|
||||
android:contentDescription="@string/avatar"
|
||||
android:scaleType="centerCrop"
|
||||
android:src="@mipmap/img"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvNickname"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="20dp"
|
||||
android:text="@string/nickname_placeholder"
|
||||
android:textColor="@color/black"
|
||||
android:textSize="18sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvInviteMessage"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:gravity="center"
|
||||
android:text="@string/invite_join_family_message_preview"
|
||||
android:textColor="@color/gray"
|
||||
android:textSize="14sp" />
|
||||
</LinearLayout>
|
||||
|
||||
<android.widget.Button
|
||||
android:id="@+id/btnJoinNow"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="48dp"
|
||||
android:layout_marginHorizontal="16dp"
|
||||
android:layout_marginBottom="40dp"
|
||||
android:background="@drawable/rounded_blue_bg"
|
||||
android:text="@string/join_now"
|
||||
android:textColor="@color/white"
|
||||
android:textSize="16sp"
|
||||
android:textStyle="bold"
|
||||
android:elevation="0dp"
|
||||
android:stateListAnimator="@null"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
@@ -35,6 +35,12 @@
|
||||
android:textStyle="bold" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1"
|
||||
android:orientation="vertical">
|
||||
|
||||
<!-- 搜索区域 -->
|
||||
<LinearLayout
|
||||
android:id="@+id/searchLayout"
|
||||
@@ -72,23 +78,64 @@
|
||||
android:singleLine="true"/>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
<!-- 列表区域 -->
|
||||
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
|
||||
android:id="@+id/swipeRefresh"
|
||||
|
||||
<!-- 内容区域 -->
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1">
|
||||
|
||||
<!-- 列表 -->
|
||||
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
|
||||
android:id="@+id/swipeRefresh"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<com.yanzhenjie.recyclerview.SwipeRecyclerView
|
||||
android:id="@+id/rvLinkedUser"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:paddingHorizontal="16dp"
|
||||
android:paddingTop="8dp"
|
||||
android:paddingBottom="16dp"/>
|
||||
android:layout_height="match_parent"/>
|
||||
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
|
||||
|
||||
<!-- 空页面 -->
|
||||
<LinearLayout
|
||||
android:id="@+id/layoutNoPermission"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:gravity="center"
|
||||
android:orientation="vertical"
|
||||
android:visibility="gone">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="244dp"
|
||||
android:layout_height="131dp"
|
||||
android:src="@mipmap/default_page"/>
|
||||
|
||||
</LinearLayout>
|
||||
<LinearLayout
|
||||
android:id="@+id/layoutNoNetwork"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:gravity="center"
|
||||
android:orientation="vertical"
|
||||
android:paddingHorizontal="32dp"
|
||||
android:background="@color/white"
|
||||
android:visibility="gone">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="244dp"
|
||||
android:layout_height="131dp"
|
||||
android:src="@mipmap/no_network_img_name" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<!-- 底部按钮 -->
|
||||
<LinearLayout
|
||||
android:id="@+id/butting"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
@@ -102,6 +149,8 @@
|
||||
android:text="@string/add_linked_user"
|
||||
android:textColor="@color/white"
|
||||
android:textSize="14dp"
|
||||
android:elevation="0dp"
|
||||
android:stateListAnimator="@null"
|
||||
android:background="@drawable/rounded_blue_bg" />
|
||||
<!-- 悬浮加号按钮 -->
|
||||
<ImageView
|
||||
|
||||
@@ -58,7 +58,22 @@
|
||||
<ImageView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:src="@mipmap/no_message" />
|
||||
android:src="@mipmap/default_page_img_name" />
|
||||
</LinearLayout>
|
||||
<LinearLayout
|
||||
android:id="@+id/layoutNoNetwork"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:gravity="center"
|
||||
android:orientation="vertical"
|
||||
android:paddingHorizontal="32dp"
|
||||
android:visibility="gone">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="244dp"
|
||||
android:layout_height="131dp"
|
||||
android:src="@mipmap/no_network_img_name" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<TextView
|
||||
|
||||
@@ -148,6 +148,8 @@
|
||||
android:background="@drawable/rounded_blue_bg"
|
||||
android:paddingHorizontal="12dp"
|
||||
android:maxWidth="120dp"
|
||||
android:elevation="0dp"
|
||||
android:stateListAnimator="@null"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
@@ -293,6 +295,8 @@
|
||||
android:textSize="16sp"
|
||||
app:cornerRadius="12dp"
|
||||
android:textColor="@color/white"
|
||||
android:elevation="0dp"
|
||||
android:stateListAnimator="@null"
|
||||
android:background="@drawable/rounded_blue_bg"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
|
||||
@@ -35,6 +35,7 @@ tools:context=".login.RegisterSuccessActivity">
|
||||
android:textColor="@color/black"
|
||||
android:textSize="16sp"
|
||||
android:textStyle="bold"
|
||||
|
||||
app:layout_constraintBottom_toBottomOf="@id/backIcon"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
@@ -80,6 +81,8 @@ tools:context=".login.RegisterSuccessActivity">
|
||||
android:textColor="@color/white"
|
||||
android:textSize="14dp"
|
||||
android:textStyle="bold"
|
||||
android:elevation="0dp"
|
||||
android:stateListAnimator="@null"
|
||||
android:background="@drawable/rounded_blue_bg"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
|
||||
@@ -91,6 +91,8 @@
|
||||
android:paddingHorizontal="16dp"
|
||||
android:text="@string/get_verification_code"
|
||||
android:textColor="@color/white"
|
||||
android:elevation="0dp"
|
||||
android:stateListAnimator="@null"
|
||||
android:textSize="14sp" />
|
||||
</RelativeLayout>
|
||||
|
||||
@@ -131,6 +133,8 @@
|
||||
android:background="@drawable/rounded_blue_bg"
|
||||
android:text="@string/confirm_reset_password_btn"
|
||||
android:textColor="@color/white"
|
||||
android:elevation="0dp"
|
||||
android:stateListAnimator="@null"
|
||||
android:textSize="16sp" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
@@ -81,6 +81,8 @@
|
||||
android:text="@string/complete"
|
||||
android:textColor="@color/white"
|
||||
android:textSize="16dp"
|
||||
android:elevation="0dp"
|
||||
android:stateListAnimator="@null"
|
||||
android:textStyle="bold" />
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
@@ -76,6 +76,8 @@
|
||||
android:background="@drawable/rounded_blue_bg"
|
||||
android:text="@string/submit"
|
||||
android:textColor="@color/white"
|
||||
android:elevation="0dp"
|
||||
android:stateListAnimator="@null"
|
||||
android:textSize="16sp" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
@@ -182,6 +182,8 @@
|
||||
android:textSize="16dp"
|
||||
android:background="@drawable/rounded_blue_bg"
|
||||
android:padding="0dp"
|
||||
android:elevation="0dp"
|
||||
android:stateListAnimator="@null"
|
||||
android:layout_margin="0dp"/>
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
@@ -72,7 +72,7 @@
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1"/>
|
||||
|
||||
<Button
|
||||
<android.widget.Button
|
||||
android:id="@+id/btnSave"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
@@ -80,7 +80,9 @@
|
||||
android:layout_marginEnd="20dp"
|
||||
android:layout_marginStart="20dp"
|
||||
android:layout_marginBottom="90dp"
|
||||
android:backgroundTint="@color/green" />
|
||||
android:elevation="0dp"
|
||||
android:stateListAnimator="@null"
|
||||
android:background="@drawable/rounded_blue_bg" />
|
||||
|
||||
|
||||
</LinearLayout>
|
||||
@@ -80,6 +80,8 @@
|
||||
android:background="@drawable/rounded_blue_bg"
|
||||
android:text="@string/select_wifi"
|
||||
android:textColor="@color/white"
|
||||
android:elevation="0dp"
|
||||
android:stateListAnimator="@null"
|
||||
android:textSize="14sp" />
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
BIN
app/src/main/res/mipmap-xhdpi/img1.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
app/src/main/res/mipmap-xhdpi/img2.png
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
app/src/main/res/mipmap-xhdpi/img3.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
app/src/main/res/mipmap-xhdpi/syis.png
Normal file
|
After Width: | Height: | Size: 540 B |
BIN
app/src/main/res/mipmap-xxhdpi/default_page_img_name.png
Normal file
|
After Width: | Height: | Size: 8.0 KiB |
BIN
app/src/main/res/mipmap-xxhdpi/img1.png
Normal file
|
After Width: | Height: | Size: 31 KiB |
BIN
app/src/main/res/mipmap-xxhdpi/img2.png
Normal file
|
After Width: | Height: | Size: 34 KiB |
BIN
app/src/main/res/mipmap-xxhdpi/img3.png
Normal file
|
After Width: | Height: | Size: 30 KiB |
BIN
app/src/main/res/mipmap-xxhdpi/no_network_img_name.png
Normal file
|
After Width: | Height: | Size: 9.5 KiB |
BIN
app/src/main/res/mipmap-xxhdpi/syis.png
Normal file
|
After Width: | Height: | Size: 956 B |
BIN
app/src/main/res/mipmap-xxxhdpi/default_page_img_name.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
app/src/main/res/mipmap-xxxhdpi/img1.png
Normal file
|
After Width: | Height: | Size: 51 KiB |
BIN
app/src/main/res/mipmap-xxxhdpi/img2.png
Normal file
|
After Width: | Height: | Size: 58 KiB |
BIN
app/src/main/res/mipmap-xxxhdpi/img3.png
Normal file
|
After Width: | Height: | Size: 50 KiB |
BIN
app/src/main/res/mipmap-xxxhdpi/no_network_img_name.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
app/src/main/res/mipmap-xxxhdpi/syis.png
Normal file
|
After Width: | Height: | Size: 813 B |
@@ -48,6 +48,7 @@
|
||||
<string name="reset_password">重置密码</string>
|
||||
<string name="new_password">新密码</string>
|
||||
<string name="reset_success">密码重置成功</string>
|
||||
<string name="resetting">重置中...</string>
|
||||
|
||||
<!-- Face Login/Verification -->
|
||||
<string name="face_login">人脸登录</string>
|
||||
@@ -109,6 +110,10 @@
|
||||
<string name="enter_family_name">请输入家庭名称</string>
|
||||
<string name="create_family">创建家庭</string>
|
||||
<string name="join_family">加入家庭</string>
|
||||
<string name="join_now">立即加入</string>
|
||||
<string name="nickname_placeholder">这里是昵称</string>
|
||||
<string name="invite_join_family_message">邀请你加入%s的家庭</string>
|
||||
<string name="invite_join_family_message_preview">邀请你加入这里是昵称的家庭</string>
|
||||
<string name="family_code">家庭码</string>
|
||||
<string name="enter_family_code">请输入家庭码</string>
|
||||
<string name="family_with_normal">的家庭</string>
|
||||
|
||||
@@ -20,5 +20,7 @@
|
||||
<color name="green_light">#E8F7F7</color>
|
||||
<color name="gray_divider">#E5E5E5</color>
|
||||
<color name="orange">#FF9800</color>
|
||||
<color name="gradientLayout1">#EBDCED</color>
|
||||
<color name="gradientLayout2">#CAF4FF</color>
|
||||
|
||||
</resources>
|
||||
|
||||
@@ -44,6 +44,7 @@
|
||||
<string name="reset_password">Reset Password</string>
|
||||
<string name="new_password">New Password</string>
|
||||
<string name="reset_success">Password reset successful</string>
|
||||
<string name="resetting">Resetting...</string>
|
||||
|
||||
<!-- Face Login/Verification -->
|
||||
<string name="face_capture_hint">Please align your face within the frame</string>
|
||||
@@ -104,6 +105,10 @@
|
||||
<string name="enter_family_name">Enter family name</string>
|
||||
<string name="create_family">Create Family</string>
|
||||
<string name="join_family">Join Family</string>
|
||||
<string name="join_now">Join Now</string>
|
||||
<string name="nickname_placeholder">Nickname</string>
|
||||
<string name="invite_join_family_message">Inviting you to join %s\'s family</string>
|
||||
<string name="invite_join_family_message_preview">Inviting you to join Nickname\'s family</string>
|
||||
<string name="family_code">Family Code</string>
|
||||
<string name="enter_family_code">Enter family code</string>
|
||||
|
||||
|
||||
6
app/src/main/res/xml/network_security_config.xml
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<network-security-config>
|
||||
<domain-config cleartextTrafficPermitted="true">
|
||||
<domain includeSubdomains="true">service.reinkun.com</domain>
|
||||
</domain-config>
|
||||
</network-security-config>
|
||||