diff --git a/app/src/main/java/com/example/studentfaceregistry/MainActivity.kt b/app/src/main/java/com/example/studentfaceregistry/MainActivity.kt index 1d5490a..687a3af 100644 --- a/app/src/main/java/com/example/studentfaceregistry/MainActivity.kt +++ b/app/src/main/java/com/example/studentfaceregistry/MainActivity.kt @@ -4,6 +4,7 @@ import android.Manifest import android.content.SharedPreferences import android.content.pm.PackageManager import android.graphics.Bitmap +import android.graphics.Outline import android.graphics.Rect import android.graphics.RectF import android.graphics.Typeface @@ -14,9 +15,11 @@ import android.util.Size import android.util.Log import android.view.Gravity import android.view.View +import android.view.ViewOutlineProvider import android.widget.EditText import android.widget.Button import android.widget.FrameLayout +import android.widget.ImageView import android.widget.LinearLayout import android.widget.TextView import android.widget.Toast @@ -143,27 +146,116 @@ class MainActivity : AppCompatActivity() { cameraExecutor.shutdown() } + private fun dp(value: Int): Int { + return (value * resources.displayMetrics.density).toInt() + } + + private fun primaryButton(text: String, onClick: () -> Unit): Button { + return Button(this).apply { + this.text = text + textSize = 16f + setTextColor(0xFFFFFFFF.toInt()) + typeface = Typeface.DEFAULT_BOLD + isAllCaps = false + setBackgroundResource(R.drawable.bg_button_primary) + minHeight = dp(48) + setPadding(dp(22), 0, dp(22), 0) + setOnClickListener { onClick() } + } + } + + private fun secondaryButton(text: String, onClick: () -> Unit): Button { + return Button(this).apply { + this.text = text + textSize = 16f + setTextColor(0xFF1D4ED8.toInt()) + typeface = Typeface.DEFAULT_BOLD + isAllCaps = false + setBackgroundResource(R.drawable.bg_button_secondary) + minHeight = dp(48) + setPadding(dp(22), 0, dp(22), 0) + setOnClickListener { onClick() } + } + } + + private fun cardButton(iconRes: Int, title: String, subtitle: String, onClick: () -> Unit): View { + return LinearLayout(this).apply { + orientation = LinearLayout.HORIZONTAL + gravity = Gravity.CENTER_VERTICAL + setBackgroundResource(R.drawable.bg_card_click) + isClickable = true + isFocusable = true + elevation = dp(3).toFloat() + setPadding(dp(20), dp(18), dp(20), dp(18)) + setOnClickListener { onClick() } + + addView(FrameLayout(this@MainActivity).apply { + layoutParams = LinearLayout.LayoutParams(dp(52), dp(52)) + setBackgroundResource(R.drawable.bg_button_primary) + addView(ImageView(this@MainActivity).apply { + layoutParams = FrameLayout.LayoutParams(dp(28), dp(28), Gravity.CENTER) + setImageResource(iconRes) + }) + }) + + addView(LinearLayout(this@MainActivity).apply { + orientation = LinearLayout.VERTICAL + layoutParams = LinearLayout.LayoutParams(0, LinearLayout.LayoutParams.WRAP_CONTENT, 1f) + setPadding(dp(16), 0, 0, 0) + + addView(TextView(this@MainActivity).apply { + text = title + textSize = 18f + typeface = Typeface.DEFAULT_BOLD + setTextColor(0xFF0F172A.toInt()) + }) + addView(TextView(this@MainActivity).apply { + text = subtitle + textSize = 13f + setTextColor(0xFF64748B.toInt()) + setPadding(0, dp(4), 0, 0) + }) + }) + + addView(TextView(this@MainActivity).apply { + text = "›" + textSize = 26f + setTextColor(0xFF94A3B8.toInt()) + }) + } + } + private fun createContentView(): View { val root = LinearLayout(this).apply { orientation = LinearLayout.VERTICAL - setBackgroundColor(0xFFF8FAFC.toInt()) + setBackgroundColor(0xFFF1F5F9.toInt()) } val header = LinearLayout(this).apply { orientation = LinearLayout.VERTICAL - setPadding(32, 28, 32, 20) + setBackgroundResource(R.drawable.bg_header) + setPadding(dp(24), dp(58), dp(24), dp(18)) } header.addView(TextView(this).apply { text = "学生人脸识别" - textSize = 24f - setTextColor(0xFF0F172A.toInt()) + textSize = 22f + typeface = Typeface.DEFAULT_BOLD + setTextColor(0xFFFFFFFF.toInt()) }) countText = TextView(this).apply { text = "已入库 0 名学生" - textSize = 15f - setTextColor(0xFF475569.toInt()) + textSize = 13f + setTextColor(0xFFFFFFFF.toInt()) + setBackgroundResource(R.drawable.bg_chip_white) + setPadding(dp(12), dp(6), dp(12), dp(6)) } - header.addView(countText) + header.addView( + countText, + LinearLayout.LayoutParams( + LinearLayout.LayoutParams.WRAP_CONTENT, + LinearLayout.LayoutParams.WRAP_CONTENT + ).apply { topMargin = dp(10) } + ) val content = FrameLayout(this).apply { layoutParams = LinearLayout.LayoutParams( @@ -192,66 +284,83 @@ class MainActivity : AppCompatActivity() { private fun createHomePanel(): View { return LinearLayout(this).apply { orientation = LinearLayout.VERTICAL - gravity = Gravity.CENTER - setPadding(40, 40, 40, 40) + gravity = Gravity.CENTER_HORIZONTAL + setPadding(dp(24), dp(36), dp(24), dp(36)) addView(TextView(this@MainActivity).apply { text = "请选择要进入的功能" - textSize = 26f + textSize = 22f typeface = Typeface.DEFAULT_BOLD setTextColor(0xFF0F172A.toInt()) gravity = Gravity.CENTER }) addView(TextView(this@MainActivity).apply { - text = "识别和注册上传分开运行,减少同时占用相机、模型和本地服务带来的卡顿。" - textSize = 16f - setTextColor(0xFF475569.toInt()) + text = "识别与注册上传分开运行,避免同时占用相机和模型导致卡顿。" + textSize = 14f + setTextColor(0xFF64748B.toInt()) gravity = Gravity.CENTER - setPadding(0, 20, 0, 36) + setPadding(0, dp(10), 0, dp(28)) }) - addView(Button(this@MainActivity).apply { - text = "进入识别" - textSize = 20f - setPadding(36, 24, 36, 24) - setOnClickListener { switchMode(AppMode.RECOGNITION) } - }) + addView( + cardButton( + R.drawable.ic_face_scan, + "进入识别", + "打开摄像头,实时识别学生身份" + ) { switchMode(AppMode.RECOGNITION) }, + LinearLayout.LayoutParams( + LinearLayout.LayoutParams.MATCH_PARENT, + LinearLayout.LayoutParams.WRAP_CONTENT + ).apply { bottomMargin = dp(16) } + ) - addView(Button(this@MainActivity).apply { - text = "进入注册上传" - textSize = 20f - setPadding(36, 24, 36, 24) - setOnClickListener { switchMode(AppMode.UPLOAD) } - }) + addView( + cardButton( + R.drawable.ic_upload, + "进入注册上传", + "上传学生照片或视频,更新人脸库" + ) { switchMode(AppMode.UPLOAD) }, + LinearLayout.LayoutParams( + LinearLayout.LayoutParams.MATCH_PARENT, + LinearLayout.LayoutParams.WRAP_CONTENT + ) + ) } } private fun createRecognitionPanel(): View { return LinearLayout(this).apply { orientation = LinearLayout.VERTICAL - setPadding(24, 16, 24, 24) + setPadding(dp(16), dp(12), dp(16), dp(16)) recognitionStatusText = TextView(this@MainActivity).apply { text = "准备进入识别模式" - textSize = 22f + textSize = 18f typeface = Typeface.DEFAULT_BOLD setTextColor(0xFF0F172A.toInt()) - setPadding(8, 8, 8, 20) + setPadding(dp(8), dp(4), dp(8), dp(12)) } addView(recognitionStatusText) val matcherConfigPanel = LinearLayout(this@MainActivity).apply { orientation = LinearLayout.VERTICAL - setPadding(16, 16, 16, 16) - setBackgroundColor(0xFFF1F5F9.toInt()) + setPadding(dp(16), dp(14), dp(16), dp(14)) + setBackgroundResource(R.drawable.bg_panel_light) } - matcherConfigSummaryText = TextView(this@MainActivity).apply { + matcherConfigPanel.addView(TextView(this@MainActivity).apply { + text = "识别参数" textSize = 14f - setTextColor(0xFF475569.toInt()) + typeface = Typeface.DEFAULT_BOLD + setTextColor(0xFF0F172A.toInt()) + }) + + matcherConfigSummaryText = TextView(this@MainActivity).apply { + textSize = 12f + setTextColor(0xFF64748B.toInt()) text = matcherConfigSummary() - setPadding(0, 0, 0, 12) + setPadding(0, dp(2), 0, dp(10)) } matcherConfigPanel.addView(matcherConfigSummaryText) @@ -262,7 +371,7 @@ class MainActivity : AppCompatActivity() { val euclideanColumn = LinearLayout(this@MainActivity).apply { orientation = LinearLayout.VERTICAL layoutParams = LinearLayout.LayoutParams(0, LinearLayout.LayoutParams.WRAP_CONTENT, 1f) - setPadding(0, 0, 12, 0) + setPadding(0, 0, dp(8), 0) } euclideanColumn.addView(TextView(this@MainActivity).apply { text = "欧氏阈值" @@ -273,15 +382,25 @@ class MainActivity : AppCompatActivity() { setText(formatThreshold(euclideanThreshold)) hint = "0.00" inputType = InputType.TYPE_CLASS_NUMBER or InputType.TYPE_NUMBER_FLAG_DECIMAL + textSize = 15f setTextColor(0xFF0F172A.toInt()) - setBackgroundColor(0xFFFFFFFF.toInt()) - setPadding(20, 18, 20, 18) + setBackgroundResource(R.drawable.bg_input) + setPadding(dp(12), 0, dp(12), 0) + minHeight = dp(44) } - euclideanColumn.addView(euclideanThresholdInput) + euclideanColumn.addView( + euclideanThresholdInput, + LinearLayout.LayoutParams( + LinearLayout.LayoutParams.MATCH_PARENT, + LinearLayout.LayoutParams.WRAP_CONTENT + ).apply { topMargin = dp(6) } + ) + thresholdRow.addView(euclideanColumn) val cosineColumn = LinearLayout(this@MainActivity).apply { orientation = LinearLayout.VERTICAL layoutParams = LinearLayout.LayoutParams(0, LinearLayout.LayoutParams.WRAP_CONTENT, 1f) + setPadding(dp(8), 0, 0, 0) } cosineColumn.addView(TextView(this@MainActivity).apply { text = "余弦阈值" @@ -291,26 +410,37 @@ class MainActivity : AppCompatActivity() { cosineThresholdInput = EditText(this@MainActivity).apply { setText(formatThreshold(cosineThreshold)) hint = "0.00" - inputType = InputType.TYPE_CLASS_NUMBER or InputType.TYPE_NUMBER_FLAG_DECIMAL or InputType.TYPE_NUMBER_FLAG_SIGNED + inputType = InputType.TYPE_CLASS_NUMBER or InputType.TYPE_NUMBER_FLAG_DECIMAL + textSize = 15f setTextColor(0xFF0F172A.toInt()) - setBackgroundColor(0xFFFFFFFF.toInt()) - setPadding(20, 18, 20, 18) + setBackgroundResource(R.drawable.bg_input) + setPadding(dp(12), 0, dp(12), 0) + minHeight = dp(44) } - cosineColumn.addView(cosineThresholdInput) - - thresholdRow.addView(euclideanColumn) + cosineColumn.addView( + cosineThresholdInput, + LinearLayout.LayoutParams( + LinearLayout.LayoutParams.MATCH_PARENT, + LinearLayout.LayoutParams.WRAP_CONTENT + ).apply { topMargin = dp(6) } + ) thresholdRow.addView(cosineColumn) matcherConfigPanel.addView(thresholdRow) - matcherConfigPanel.addView(Button(this@MainActivity).apply { - text = "保存识别参数" - setOnClickListener { saveMatcherConfig() } - }) - matcherConfigPanel.addView(Button(this@MainActivity).apply { - text = "自动校准阈值" - setOnClickListener { applySuggestedThresholds() } - }) + matcherConfigPanel.addView(LinearLayout(this@MainActivity).apply { + orientation = LinearLayout.HORIZONTAL + setPadding(0, dp(12), 0, 0) + addView( + secondaryButton("自动校准阈值") { applySuggestedThresholds() }, + LinearLayout.LayoutParams(0, LinearLayout.LayoutParams.WRAP_CONTENT, 1f) + .apply { rightMargin = dp(8) } + ) + addView( + primaryButton("保存识别参数") { saveMatcherConfig() }, + LinearLayout.LayoutParams(0, LinearLayout.LayoutParams.WRAP_CONTENT, 1f) + ) + }) addView(matcherConfigPanel) val cameraFrame = FrameLayout(this@MainActivity).apply { @@ -319,39 +449,51 @@ class MainActivity : AppCompatActivity() { 0, 1f ) + setBackgroundResource(R.drawable.bg_camera_frame) + setPadding(dp(4), dp(4), dp(4), dp(4)) } - previewView = PreviewView(this@MainActivity).apply { - scaleType = PreviewView.ScaleType.FILL_CENTER - implementationMode = PreviewView.ImplementationMode.COMPATIBLE - } - overlayView = OverlayView(this@MainActivity) - cameraFrame.addView(previewView, FrameLayout.LayoutParams(-1, -1)) - cameraFrame.addView(overlayView, FrameLayout.LayoutParams(-1, -1)) + cameraFrame.addView( + FrameLayout(this@MainActivity).apply { + clipToOutline = true + outlineProvider = object : ViewOutlineProvider() { + override fun getOutline(view: View, outline: Outline) { + outline.setRoundRect(0, 0, view.width, view.height, dp(16).toFloat()) + } + } + + previewView = PreviewView(this@MainActivity).apply { + scaleType = PreviewView.ScaleType.FILL_CENTER + implementationMode = PreviewView.ImplementationMode.COMPATIBLE + } + overlayView = OverlayView(this@MainActivity) + addView(previewView, FrameLayout.LayoutParams(-1, -1)) + addView(overlayView, FrameLayout.LayoutParams(-1, -1)) + }, + FrameLayout.LayoutParams(-1, -1) + ) addView(cameraFrame) addView(LinearLayout(this@MainActivity).apply { gravity = Gravity.CENTER orientation = LinearLayout.HORIZONTAL - setPadding(12, 20, 12, 8) + setPadding(dp(12), dp(16), dp(12), 0) - addView(Button(this@MainActivity).apply { - text = "返回首页" - setOnClickListener { switchMode(AppMode.HOME) } - }) + addView( + secondaryButton("返回首页") { switchMode(AppMode.HOME) }, + LinearLayout.LayoutParams(0, LinearLayout.LayoutParams.WRAP_CONTENT, 1f) + .apply { rightMargin = dp(10) } + ) - pauseRecognitionButton = Button(this@MainActivity).apply { - text = "暂停识别" - setOnClickListener { - recognitionEnabled = !recognitionEnabled - text = if (recognitionEnabled) "暂停识别" else "继续识别" - recognitionStatusText.text = if (recognitionEnabled) "正在识别" else "识别已暂停" - if (!recognitionEnabled) { - overlayView.update(emptyList()) - } - updateAnalyzerState() + pauseRecognitionButton = primaryButton("暂停识别") { + recognitionEnabled = !recognitionEnabled + pauseRecognitionButton.text = if (recognitionEnabled) "暂停识别" else "继续识别" + recognitionStatusText.text = if (recognitionEnabled) "正在识别" else "识别已暂停" + if (!recognitionEnabled) { + overlayView.update(emptyList()) } + updateAnalyzerState() } - addView(pauseRecognitionButton) + addView(pauseRecognitionButton, LinearLayout.LayoutParams(0, LinearLayout.LayoutParams.WRAP_CONTENT, 1f)) }) } } @@ -360,11 +502,11 @@ class MainActivity : AppCompatActivity() { return LinearLayout(this).apply { orientation = LinearLayout.VERTICAL gravity = Gravity.CENTER_HORIZONTAL - setPadding(40, 48, 40, 48) + setPadding(dp(24), dp(32), dp(24), dp(32)) uploadStatusText = TextView(this@MainActivity).apply { text = "准备进入注册上传模式" - textSize = 24f + textSize = 20f typeface = Typeface.DEFAULT_BOLD setTextColor(0xFF0F172A.toInt()) gravity = Gravity.CENTER @@ -373,38 +515,62 @@ class MainActivity : AppCompatActivity() { addView(TextView(this@MainActivity).apply { setText(R.string.upload_instructions) - textSize = 16f - setTextColor(0xFF475569.toInt()) + textSize = 14f + setTextColor(0xFF64748B.toInt()) gravity = Gravity.CENTER - setPadding(0, 16, 0, 20) + setPadding(0, dp(10), 0, dp(24)) }) - uploadUrlText = TextView(this@MainActivity).apply { - text = "-" - textSize = 20f - typeface = Typeface.MONOSPACE - setTextColor(0xFF0F172A.toInt()) - gravity = Gravity.CENTER - setPadding(24, 20, 24, 20) - setTextIsSelectable(true) - setBackgroundColor(0xFFE2E8F0.toInt()) - } - addView(uploadUrlText) + addView( + LinearLayout(this@MainActivity).apply { + orientation = LinearLayout.VERTICAL + setBackgroundResource(R.drawable.bg_card) + elevation = dp(3).toFloat() + setPadding(dp(18), dp(16), dp(18), dp(16)) + + addView(TextView(this@MainActivity).apply { + text = "上传地址" + textSize = 12f + setTextColor(0xFF64748B.toInt()) + }) + uploadUrlText = TextView(this@MainActivity).apply { + text = "-" + textSize = 18f + typeface = Typeface.MONOSPACE + setTextColor(0xFF0F172A.toInt()) + gravity = Gravity.CENTER + setPadding(dp(12), dp(12), dp(12), dp(12)) + setTextIsSelectable(true) + setBackgroundResource(R.drawable.bg_input) + } + addView( + uploadUrlText, + LinearLayout.LayoutParams( + LinearLayout.LayoutParams.MATCH_PARENT, + LinearLayout.LayoutParams.WRAP_CONTENT + ).apply { topMargin = dp(8) } + ) + }, + LinearLayout.LayoutParams( + LinearLayout.LayoutParams.MATCH_PARENT, + LinearLayout.LayoutParams.WRAP_CONTENT + ) + ) addView(LinearLayout(this@MainActivity).apply { gravity = Gravity.CENTER orientation = LinearLayout.HORIZONTAL - setPadding(12, 28, 12, 8) + setPadding(0, dp(24), 0, 0) - addView(Button(this@MainActivity).apply { - text = "刷新地址" - setOnClickListener { startUploadSession() } - }) - - addView(Button(this@MainActivity).apply { - text = "返回首页" - setOnClickListener { switchMode(AppMode.HOME) } - }) + addView( + secondaryButton("刷新地址") { startUploadSession() }, + LinearLayout.LayoutParams(0, LinearLayout.LayoutParams.WRAP_CONTENT, 1f) + .apply { rightMargin = dp(10) } + ) + addView( + primaryButton("返回首页") { switchMode(AppMode.HOME) }, + LinearLayout.LayoutParams(0, LinearLayout.LayoutParams.WRAP_CONTENT, 1f) + ) }) } } diff --git a/app/src/main/java/com/example/studentfaceregistry/ui/OverlayView.kt b/app/src/main/java/com/example/studentfaceregistry/ui/OverlayView.kt index 442663b..cce7dd6 100644 --- a/app/src/main/java/com/example/studentfaceregistry/ui/OverlayView.kt +++ b/app/src/main/java/com/example/studentfaceregistry/ui/OverlayView.kt @@ -20,10 +20,16 @@ class OverlayView @JvmOverloads constructor( attrs: AttributeSet? = null ) : View(context, attrs) { + // 识别框外发光画笔 + private val glowPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply { + style = Paint.Style.STROKE + strokeWidth = 14f + } + // 识别框画笔 private val boxPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply { style = Paint.Style.STROKE - strokeWidth = 6f + strokeWidth = 5f } // 标签背景画笔 @@ -31,24 +37,31 @@ class OverlayView @JvmOverloads constructor( style = Paint.Style.FILL } + // 标签投影画笔 + private val labelShadowPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply { + style = Paint.Style.FILL + color = Color.argb(70, 0, 0, 0) + } + // 标签文字画笔 private val labelPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply { color = Color.WHITE - textSize = 48f - typeface = Typeface.DEFAULT_BOLD + textSize = 40f + typeface = Typeface.create("sans-serif-medium", Typeface.BOLD) } // 置信度文字画笔 private val confidencePaint = Paint(Paint.ANTI_ALIAS_FLAG).apply { color = Color.WHITE - textSize = 32f + textSize = 30f + typeface = Typeface.create("sans-serif-medium", Typeface.NORMAL) } // 颜色定义 private val colorMatch = Color.rgb(34, 197, 94) // 绿色 - 匹配成功 - private val colorUnsure = Color.rgb(234, 179, 8) // 黄色 - 不确定 - private val colorNoMatch = Color.rgb(239, 68, 68) // 红色 - 未匹配 - private val colorUnknown = Color.rgb(59, 130, 246) // 蓝色 - 识别中 + private val colorUnsure = Color.rgb(245, 158, 11) // 橙色 - 不确定 + private val colorNoMatch = Color.rgb(239, 68, 68) // 红色 - 未匹配 + private val colorUnknown = Color.rgb(59, 130, 246) // 蓝色 - 识别中 private var detections: List = emptyList() @@ -72,43 +85,74 @@ class OverlayView @JvmOverloads constructor( val boxColor = getBoxColor(item.result) boxPaint.color = boxColor - // 绘制识别框 - canvas.drawRect(rect.left, rect.top, rect.right, rect.bottom, boxPaint) + // 外发光(半透明描边) + glowPaint.color = boxColor and 0x00FFFFFF or 0x4D000000.toInt() + canvas.drawRoundRect(rect, 14f, 14f, glowPaint) + + // 绘制识别框(圆角) + canvas.drawRoundRect(rect, 14f, 14f, boxPaint) // 绘制标签背景 val label = item.label val labelWidth = labelPaint.measureText(label) - val labelHeight = 60f - val padding = 12f + val labelHeight = 52f + val padding = 14f // 标签在框上方 - val labelLeft = rect.left + padding - val labelTop = (rect.top - labelHeight - padding).coerceAtLeast(padding) + val labelLeft = rect.left + 4f + val labelTop = (rect.top - labelHeight - 10f).coerceAtLeast(padding) val labelRight = labelLeft + labelWidth + padding * 2 val labelBottom = labelTop + labelHeight - // 标签背景颜色与框颜色一致 + // 标签投影 + canvas.drawRoundRect( + labelLeft, + labelTop + 3f, + labelRight, + labelBottom + 3f, + labelHeight / 2f, + labelHeight / 2f, + labelShadowPaint + ) + + // 标签背景颜色与框颜色一致(胶囊形) labelBackgroundPaint.color = boxColor - canvas.drawRoundRect(labelLeft, labelTop, labelRight, labelBottom, 8f, 8f, labelBackgroundPaint) + canvas.drawRoundRect( + labelLeft, + labelTop, + labelRight, + labelBottom, + labelHeight / 2f, + labelHeight / 2f, + labelBackgroundPaint + ) // 绘制标签文字 - canvas.drawText(label, labelLeft + padding, labelTop + 38f, labelPaint) + canvas.drawText(label, labelLeft + padding, labelTop + 36f, labelPaint) // 如果有置信度信息,显示在标签右侧 if (item.confidence != null) { val confidenceText = "${(item.confidence * 100).toInt()}%" val confidenceWidth = confidencePaint.measureText(confidenceText) - val confLeft = labelRight + 8f - val confTop = labelTop + 8f - val confRight = confLeft + confidenceWidth + 16f - val confBottom = confTop + 44f + val chipLeft = labelRight + 8f + val chipTop = labelTop + 6f + val chipRight = chipLeft + confidenceWidth + 22f + val chipBottom = chipTop + 40f - // 置信度背景(半透明黑色) - labelBackgroundPaint.color = Color.argb(180, 0, 0, 0) - canvas.drawRoundRect(confLeft, confTop, confRight, confBottom, 6f, 6f, labelBackgroundPaint) + // 置信度背景(深色半透明胶囊) + labelBackgroundPaint.color = Color.argb(210, 15, 23, 42) + canvas.drawRoundRect( + chipLeft, + chipTop, + chipRight, + chipBottom, + 20f, + 20f, + labelBackgroundPaint + ) // 置信度文字 - canvas.drawText(confidenceText, confLeft + 8f, confTop + 30f, confidencePaint) + canvas.drawText(confidenceText, chipLeft + 11f, chipTop + 27f, confidencePaint) } } diff --git a/app/src/main/res/drawable/bg_button_primary.xml b/app/src/main/res/drawable/bg_button_primary.xml new file mode 100644 index 0000000..02c7ccf --- /dev/null +++ b/app/src/main/res/drawable/bg_button_primary.xml @@ -0,0 +1,13 @@ + + + + + + + + + diff --git a/app/src/main/res/drawable/bg_button_secondary.xml b/app/src/main/res/drawable/bg_button_secondary.xml new file mode 100644 index 0000000..e0704f5 --- /dev/null +++ b/app/src/main/res/drawable/bg_button_secondary.xml @@ -0,0 +1,13 @@ + + + + + + + + + + diff --git a/app/src/main/res/drawable/bg_camera_frame.xml b/app/src/main/res/drawable/bg_camera_frame.xml new file mode 100644 index 0000000..56eefe0 --- /dev/null +++ b/app/src/main/res/drawable/bg_camera_frame.xml @@ -0,0 +1,8 @@ + + + + + + diff --git a/app/src/main/res/drawable/bg_card.xml b/app/src/main/res/drawable/bg_card.xml new file mode 100644 index 0000000..56eefe0 --- /dev/null +++ b/app/src/main/res/drawable/bg_card.xml @@ -0,0 +1,8 @@ + + + + + + diff --git a/app/src/main/res/drawable/bg_card_click.xml b/app/src/main/res/drawable/bg_card_click.xml new file mode 100644 index 0000000..53d748d --- /dev/null +++ b/app/src/main/res/drawable/bg_card_click.xml @@ -0,0 +1,13 @@ + + + + + + + + + + diff --git a/app/src/main/res/drawable/bg_chip_white.xml b/app/src/main/res/drawable/bg_chip_white.xml new file mode 100644 index 0000000..782040d --- /dev/null +++ b/app/src/main/res/drawable/bg_chip_white.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/app/src/main/res/drawable/bg_header.xml b/app/src/main/res/drawable/bg_header.xml new file mode 100644 index 0000000..909a6a2 --- /dev/null +++ b/app/src/main/res/drawable/bg_header.xml @@ -0,0 +1,7 @@ + + + + diff --git a/app/src/main/res/drawable/bg_input.xml b/app/src/main/res/drawable/bg_input.xml new file mode 100644 index 0000000..74d03f1 --- /dev/null +++ b/app/src/main/res/drawable/bg_input.xml @@ -0,0 +1,8 @@ + + + + + + diff --git a/app/src/main/res/drawable/bg_panel_light.xml b/app/src/main/res/drawable/bg_panel_light.xml new file mode 100644 index 0000000..ddb323c --- /dev/null +++ b/app/src/main/res/drawable/bg_panel_light.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/app/src/main/res/drawable/ic_face_scan.xml b/app/src/main/res/drawable/ic_face_scan.xml new file mode 100644 index 0000000..51a8a63 --- /dev/null +++ b/app/src/main/res/drawable/ic_face_scan.xml @@ -0,0 +1,47 @@ + + + + + + + + + diff --git a/app/src/main/res/drawable/ic_launcher_background.xml b/app/src/main/res/drawable/ic_launcher_background.xml index 19daede..3b45352 100644 --- a/app/src/main/res/drawable/ic_launcher_background.xml +++ b/app/src/main/res/drawable/ic_launcher_background.xml @@ -1,4 +1,8 @@ - + diff --git a/app/src/main/res/drawable/ic_launcher_foreground.xml b/app/src/main/res/drawable/ic_launcher_foreground.xml new file mode 100644 index 0000000..ebcebf3 --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_foreground.xml @@ -0,0 +1,47 @@ + + + + + + + + + diff --git a/app/src/main/res/drawable/ic_upload.xml b/app/src/main/res/drawable/ic_upload.xml new file mode 100644 index 0000000..80ea98d --- /dev/null +++ b/app/src/main/res/drawable/ic_upload.xml @@ -0,0 +1,27 @@ + + + + + + diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml index 670bfb3..6b78462 100644 --- a/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml +++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml @@ -1,5 +1,5 @@ - + diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml index 670bfb3..6b78462 100644 --- a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml +++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml @@ -1,5 +1,5 @@ - + diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher.png b/app/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 0000000..63c664d Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher.png differ diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_round.png b/app/src/main/res/mipmap-hdpi/ic_launcher_round.png new file mode 100644 index 0000000..2d4cce8 Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher_round.png differ diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher.png b/app/src/main/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 0000000..f40c94f Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher.png differ diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_round.png b/app/src/main/res/mipmap-mdpi/ic_launcher_round.png new file mode 100644 index 0000000..917a569 Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher_round.png differ diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/app/src/main/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 0000000..ed42e4a Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png new file mode 100644 index 0000000..0575d9d Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png differ diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 0000000..1d7e4a9 Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png new file mode 100644 index 0000000..879ab5f Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png differ diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 0000000..391d5fd Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png new file mode 100644 index 0000000..52251c8 Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png differ diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index f66b27e..d5993f5 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -2,7 +2,11 @@