beautified UI

This commit is contained in:
2026-08-07 22:35:48 +08:00
parent c79c34895c
commit 50b6fac08d
28 changed files with 548 additions and 129 deletions

View File

@@ -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))
}
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)
cameraFrame.addView(previewView, FrameLayout.LayoutParams(-1, -1))
cameraFrame.addView(overlayView, FrameLayout.LayoutParams(-1, -1))
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 {
pauseRecognitionButton = primaryButton("暂停识别") {
recognitionEnabled = !recognitionEnabled
text = if (recognitionEnabled) "暂停识别" else "继续识别"
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))
})
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 = 20f
textSize = 18f
typeface = Typeface.MONOSPACE
setTextColor(0xFF0F172A.toInt())
gravity = Gravity.CENTER
setPadding(24, 20, 24, 20)
setPadding(dp(12), dp(12), dp(12), dp(12))
setTextIsSelectable(true)
setBackgroundColor(0xFFE2E8F0.toInt())
setBackgroundResource(R.drawable.bg_input)
}
addView(uploadUrlText)
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)
)
})
}
}

View File

@@ -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,22 +37,29 @@ 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 colorUnsure = Color.rgb(245, 158, 11) // 色 - 不确定
private val colorNoMatch = Color.rgb(239, 68, 68) // 红色 - 未匹配
private val colorUnknown = Color.rgb(59, 130, 246) // 蓝色 - 识别中
@@ -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)
}
}

View File

@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="#33FFFFFF">
<item>
<shape>
<gradient
android:angle="270"
android:startColor="#2E6BFF"
android:endColor="#1D4ED8" />
<corners android:radius="16dp" />
</shape>
</item>
</ripple>

View File

@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="#1A2563EB">
<item>
<shape>
<solid android:color="#FFFFFF" />
<corners android:radius="16dp" />
<stroke
android:width="1dp"
android:color="#CBD5E1" />
</shape>
</item>
</ripple>

View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#FFFFFF" />
<corners android:radius="20dp" />
<stroke
android:width="1dp"
android:color="#E2E8F0" />
</shape>

View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#FFFFFF" />
<corners android:radius="20dp" />
<stroke
android:width="1dp"
android:color="#E2E8F0" />
</shape>

View File

@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="#1A2563EB">
<item>
<shape>
<solid android:color="#FFFFFF" />
<corners android:radius="20dp" />
<stroke
android:width="1dp"
android:color="#E2E8F0" />
</shape>
</item>
</ripple>

View File

@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#26FFFFFF" />
<corners android:radius="999dp" />
</shape>

View File

@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<gradient
android:angle="270"
android:startColor="#2E6BFF"
android:endColor="#1D4ED8" />
</shape>

View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#FFFFFF" />
<corners android:radius="12dp" />
<stroke
android:width="1dp"
android:color="#CBD5E1" />
</shape>

View File

@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#F1F5F9" />
<corners android:radius="16dp" />
</shape>

View File

@@ -0,0 +1,47 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="32dp"
android:height="32dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:pathData="M12,6.4 A4.2,4.2 0 1 1 12,14.8 A4.2,4.2 0 1 1 12,6.4 Z"
android:strokeColor="#FFFFFF"
android:strokeWidth="1.7"
android:strokeLineCap="round"
android:fillColor="#00000000" />
<path
android:pathData="M6.2,20.2 A5.8,5.8 0 0 1 17.8,20.2"
android:strokeColor="#FFFFFF"
android:strokeWidth="1.7"
android:strokeLineCap="round"
android:fillColor="#00000000" />
<path
android:pathData="M4,8.2 L4,5.2 C4,4.55 4.55,4 5.2,4 L8.2,4"
android:strokeColor="#7DD3FC"
android:strokeWidth="1.8"
android:strokeLineCap="round"
android:strokeLineJoin="round"
android:fillColor="#00000000" />
<path
android:pathData="M15.8,4 L18.8,4 C19.45,4 20,4.55 20,5.2 L20,8.2"
android:strokeColor="#7DD3FC"
android:strokeWidth="1.8"
android:strokeLineCap="round"
android:strokeLineJoin="round"
android:fillColor="#00000000" />
<path
android:pathData="M4,15.8 L4,18.8 C4,19.45 4.55,20 5.2,20 L8.2,20"
android:strokeColor="#7DD3FC"
android:strokeWidth="1.8"
android:strokeLineCap="round"
android:strokeLineJoin="round"
android:fillColor="#00000000" />
<path
android:pathData="M15.8,20 L18.8,20 C19.45,20 20,19.45 20,18.8 L20,15.8"
android:strokeColor="#7DD3FC"
android:strokeWidth="1.8"
android:strokeLineCap="round"
android:strokeLineJoin="round"
android:fillColor="#00000000" />
</vector>

View File

@@ -1,4 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#1D4ED8" />
<gradient
android:angle="315"
android:startColor="#3B82F6"
android:centerColor="#2563EB"
android:endColor="#1E40AF" />
</shape>

View File

@@ -0,0 +1,47 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<path
android:pathData="M54,32 A15,15 0 1 1 54,62 A15,15 0 1 1 54,32 Z"
android:strokeColor="#FFFFFF"
android:strokeWidth="5"
android:strokeLineCap="round"
android:fillColor="#00000000" />
<path
android:pathData="M36,84 A18,18 0 0 1 72,84"
android:strokeColor="#FFFFFF"
android:strokeWidth="5"
android:strokeLineCap="round"
android:fillColor="#00000000" />
<path
android:pathData="M25,40 L25,33 C25,30.6 26.6,29 29,29 L36,29"
android:strokeColor="#7DD3FC"
android:strokeWidth="5"
android:strokeLineCap="round"
android:strokeLineJoin="round"
android:fillColor="#00000000" />
<path
android:pathData="M72,29 L79,29 C81.4,29 83,30.6 83,33 L83,40"
android:strokeColor="#7DD3FC"
android:strokeWidth="5"
android:strokeLineCap="round"
android:strokeLineJoin="round"
android:fillColor="#00000000" />
<path
android:pathData="M25,68 L25,75 C25,77.4 26.6,79 29,79 L36,79"
android:strokeColor="#7DD3FC"
android:strokeWidth="5"
android:strokeLineCap="round"
android:strokeLineJoin="round"
android:fillColor="#00000000" />
<path
android:pathData="M72,79 L79,79 C81.4,79 83,77.4 83,75 L83,68"
android:strokeColor="#7DD3FC"
android:strokeWidth="5"
android:strokeLineCap="round"
android:strokeLineJoin="round"
android:fillColor="#00000000" />
</vector>

View File

@@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="32dp"
android:height="32dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:pathData="M6.2,18.6 L17.8,18.6 A3.2,3.2 0 0 0 17.9,12.3 A4.6,4.6 0 0 0 8.9,10.6 A3.6,3.6 0 0 0 6.2,18.6 Z"
android:strokeColor="#FFFFFF"
android:strokeWidth="1.7"
android:strokeLineCap="round"
android:strokeLineJoin="round"
android:fillColor="#00000000" />
<path
android:pathData="M12,14.6 L12,8.4"
android:strokeColor="#FFFFFF"
android:strokeWidth="1.8"
android:strokeLineCap="round"
android:fillColor="#00000000" />
<path
android:pathData="M9.2,11.2 L12,8.4 L14.8,11.2"
android:strokeColor="#FFFFFF"
android:strokeWidth="1.8"
android:strokeLineCap="round"
android:strokeLineJoin="round"
android:fillColor="#00000000" />
</vector>

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background" />
<foreground android:drawable="@drawable/ic_launcher_background" />
<foreground android:drawable="@drawable/ic_launcher_foreground" />
</adaptive-icon>

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background" />
<foreground android:drawable="@drawable/ic_launcher_background" />
<foreground android:drawable="@drawable/ic_launcher_foreground" />
</adaptive-icon>

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

View File

@@ -2,7 +2,11 @@
<resources>
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
<item name="android:fontFamily">sans</item>
<item name="android:windowLightStatusBar">true</item>
<item name="android:windowLightStatusBar">false</item>
<item name="android:statusBarColor">#1D4ED8</item>
<item name="android:windowBackground">#F1F5F9</item>
<item name="android:colorAccent">#2563EB</item>
<item name="android:windowLightNavigationBar">false</item>
<item name="android:navigationBarColor">#F1F5F9</item>
</style>
</resources>