diff --git a/.idea/misc.xml b/.idea/misc.xml index 74dd639..9cafd9a 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -7,4 +7,11 @@ + + + \ No newline at end of file diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 8bd5963..e77a224 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -1,5 +1,3 @@ -import org.gradle.kotlin.dsl.implementation - plugins { alias(libs.plugins.android.application) alias(libs.plugins.kotlin.android) @@ -41,6 +39,9 @@ android { kotlinOptions { jvmTarget = "11" } + viewBinding { + enable = true + } } dependencies { @@ -53,4 +54,28 @@ dependencies { testImplementation(libs.junit) androidTestImplementation(libs.androidx.junit) androidTestImplementation(libs.androidx.espresso.core) + + // camerax + implementation(libs.androidx.camera.core) + implementation(libs.androidx.camera.camera2) + implementation(libs.androidx.camera.lifecycle) + implementation(libs.androidx.camera.view) + implementation(libs.androidx.camera.extensions) + + // 权限申请 + implementation(libs.accompanist.permissions) + // hilt注入 + implementation(libs.hilt.android) + ksp(libs.hilt.android.compiler) + + // retrofit网络请求 + implementation(libs.retrofit) + implementation(libs.converter.gson) + // okhttp + implementation(libs.okhttp) + implementation(libs.logging.interceptor) + // gson + implementation(libs.gson) + // 日志打印 + implementation(libs.timber) } \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 86bf6e0..6e88fdb 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -2,6 +2,13 @@ + + + + + + android:name=".activity.LoginByPwdActivity" + android:exported="false" + android:launchMode="singleTask" /> + + + + + + + + \ No newline at end of file diff --git a/app/src/main/java/com/sw/platecabinet/MainActivity.kt b/app/src/main/java/com/sw/platecabinet/MainActivity.kt deleted file mode 100644 index 1f03a26..0000000 --- a/app/src/main/java/com/sw/platecabinet/MainActivity.kt +++ /dev/null @@ -1,20 +0,0 @@ -package com.sw.platecabinet - -import android.os.Bundle -import androidx.activity.enableEdgeToEdge -import androidx.appcompat.app.AppCompatActivity -import androidx.core.view.ViewCompat -import androidx.core.view.WindowInsetsCompat - -class MainActivity : AppCompatActivity() { - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - enableEdgeToEdge() - setContentView(R.layout.activity_main) - ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets -> - val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars()) - v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom) - insets - } - } -} \ No newline at end of file diff --git a/app/src/main/java/com/sw/platecabinet/activity/BaseActivity.kt b/app/src/main/java/com/sw/platecabinet/activity/BaseActivity.kt new file mode 100644 index 0000000..6d54a83 --- /dev/null +++ b/app/src/main/java/com/sw/platecabinet/activity/BaseActivity.kt @@ -0,0 +1,40 @@ +package com.sw.platecabinet.activity + +import android.content.Context +import android.os.Bundle +import android.view.WindowManager +import androidx.activity.enableEdgeToEdge +import androidx.appcompat.app.AppCompatActivity +import androidx.viewbinding.ViewBinding + +/** + * activity 基类 + */ +abstract class BaseActivity : AppCompatActivity() { + + protected lateinit var binding: VB + private set + protected lateinit var context: Context + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + enableEdgeToEdge() + window.setFlags( + WindowManager.LayoutParams.FLAG_FULLSCREEN, + WindowManager.LayoutParams.FLAG_FULLSCREEN + ) + context = this + binding = inflateViewBinding() + setContentView(binding.root) + initialize() + } + + protected abstract fun inflateViewBinding(): VB + + protected abstract fun initialize() + + + override fun onDestroy() { + super.onDestroy() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/sw/platecabinet/activity/LoginByFaceActivity.kt b/app/src/main/java/com/sw/platecabinet/activity/LoginByFaceActivity.kt new file mode 100644 index 0000000..1467240 --- /dev/null +++ b/app/src/main/java/com/sw/platecabinet/activity/LoginByFaceActivity.kt @@ -0,0 +1,73 @@ +package com.sw.platecabinet.activity + +import android.content.Intent +import android.graphics.Outline +import android.view.View +import android.view.ViewOutlineProvider +import androidx.camera.core.CameraSelector +import androidx.camera.core.Preview +import androidx.camera.lifecycle.ProcessCameraProvider +import androidx.core.content.ContextCompat +import com.google.common.util.concurrent.ListenableFuture +import com.sw.platecabinet.databinding.ActivityLoginFaceBinding +import timber.log.Timber + +/** + * 人脸识别 + */ +class LoginByFaceActivity : BaseActivity() { + private lateinit var cameraProviderFuture: ListenableFuture + + override fun inflateViewBinding(): ActivityLoginFaceBinding { + return ActivityLoginFaceBinding.inflate(layoutInflater) + } + + override fun initialize() { + initView() + startCamera() + binding.llToPwd.setOnClickListener { + val intent = Intent(this, LoginByPwdActivity::class.java) + startActivity(intent) + } + } + + private fun initView() { + binding.previewView.outlineProvider = object : ViewOutlineProvider() { + override fun getOutline(view: View, outline: Outline) { +// outline.setRoundRect(0, 0, view.width, view.height, 12f.dp) + outline.setOval(0, 0, view.width, view.height) + } + } + binding.previewView.clipToOutline = true + } + + private fun startCamera() { + cameraProviderFuture = ProcessCameraProvider.getInstance(this) + cameraProviderFuture.addListener({ + val cameraProvider = cameraProviderFuture.get() + + // 创建预览用例 + val preview = Preview.Builder() + .build() + .also { + it.setSurfaceProvider(binding.previewView.surfaceProvider) + } + + // 选择后置摄像头 + val cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA + + try { + // 解绑所有用例 + cameraProvider.unbindAll() + + // 绑定到生命周期 + cameraProvider.bindToLifecycle( + this, cameraSelector, preview + ) + } catch (exc: Exception) { + Timber.e(exc, "Use case binding failed") + } + }, ContextCompat.getMainExecutor(this)) + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/sw/platecabinet/activity/LoginByPwdActivity.kt b/app/src/main/java/com/sw/platecabinet/activity/LoginByPwdActivity.kt new file mode 100644 index 0000000..011ef3b --- /dev/null +++ b/app/src/main/java/com/sw/platecabinet/activity/LoginByPwdActivity.kt @@ -0,0 +1,18 @@ +package com.sw.platecabinet.activity + +import android.content.Intent +import com.sw.platecabinet.databinding.ActivityLoginByPwdBinding + +class LoginByPwdActivity : BaseActivity() { + override fun inflateViewBinding(): ActivityLoginByPwdBinding { + return ActivityLoginByPwdBinding.inflate(layoutInflater) + } + + override fun initialize() { + binding.tvFaceRec.setOnClickListener { + val intent = Intent(this, LoginByFaceActivity::class.java) + startActivity(intent) + } + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/sw/platecabinet/activity/MainActivity.kt b/app/src/main/java/com/sw/platecabinet/activity/MainActivity.kt new file mode 100644 index 0000000..794c2eb --- /dev/null +++ b/app/src/main/java/com/sw/platecabinet/activity/MainActivity.kt @@ -0,0 +1,14 @@ +package com.sw.platecabinet.activity + +import com.sw.platecabinet.databinding.ActivityMainBinding + +class MainActivity : BaseActivity() { + + override fun inflateViewBinding(): ActivityMainBinding { + return ActivityMainBinding.inflate(layoutInflater) + } + + override fun initialize() { + + } +} \ No newline at end of file diff --git a/app/src/main/java/com/sw/platecabinet/ext/CommonExt.kt b/app/src/main/java/com/sw/platecabinet/ext/CommonExt.kt new file mode 100644 index 0000000..ef20401 --- /dev/null +++ b/app/src/main/java/com/sw/platecabinet/ext/CommonExt.kt @@ -0,0 +1,49 @@ +package com.sw.platecabinet.ext + +import android.content.res.Resources +import android.util.TypedValue +import androidx.annotation.Dimension + +/** + * 将 Int 值转换为 dp 值 + */ +val Int.dp: Int + @Dimension(unit = Dimension.DP) + get() = TypedValue.applyDimension( + TypedValue.COMPLEX_UNIT_DIP, + this.toFloat(), + Resources.getSystem().displayMetrics + ).toInt() + +/** + * 将 Float 值转换为 dp 值 + */ +val Float.dp: Float + @Dimension(unit = Dimension.DP) + get() = TypedValue.applyDimension( + TypedValue.COMPLEX_UNIT_DIP, + this, + Resources.getSystem().displayMetrics + ) + +/** + * 将 Int 值转换为 sp 值 + */ +val Int.sp: Float + @Dimension(unit = Dimension.SP) + get() = TypedValue.applyDimension( + TypedValue.COMPLEX_UNIT_SP, + this.toFloat(), + Resources.getSystem().displayMetrics + ) + +/** + * 将 Float 值转换为 sp 值 + */ +val Float.sp: Float + @Dimension(unit = Dimension.SP) + get() = TypedValue.applyDimension( + TypedValue.COMPLEX_UNIT_SP, + this, + Resources.getSystem().displayMetrics + ) \ No newline at end of file diff --git a/app/src/main/res/drawable/btn_outline_887872.xml b/app/src/main/res/drawable/btn_outline_887872.xml new file mode 100644 index 0000000..c3590b6 --- /dev/null +++ b/app/src/main/res/drawable/btn_outline_887872.xml @@ -0,0 +1,8 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/circle_dashed_border.xml b/app/src/main/res/drawable/circle_dashed_border.xml new file mode 100644 index 0000000..4136a47 --- /dev/null +++ b/app/src/main/res/drawable/circle_dashed_border.xml @@ -0,0 +1,12 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/rounded_border_transparent.xml b/app/src/main/res/drawable/rounded_border_transparent.xml new file mode 100644 index 0000000..2fb80c3 --- /dev/null +++ b/app/src/main/res/drawable/rounded_border_transparent.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/shape_btn_bg.xml b/app/src/main/res/drawable/shape_btn_bg.xml new file mode 100644 index 0000000..191bd6f --- /dev/null +++ b/app/src/main/res/drawable/shape_btn_bg.xml @@ -0,0 +1,8 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/shape_pwd_bg.xml b/app/src/main/res/drawable/shape_pwd_bg.xml new file mode 100644 index 0000000..c8301e0 --- /dev/null +++ b/app/src/main/res/drawable/shape_pwd_bg.xml @@ -0,0 +1,7 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_login_by_pwd.xml b/app/src/main/res/layout/activity_login_by_pwd.xml new file mode 100644 index 0000000..0b2b90e --- /dev/null +++ b/app/src/main/res/layout/activity_login_by_pwd.xml @@ -0,0 +1,116 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_login_face.xml b/app/src/main/res/layout/activity_login_face.xml new file mode 100644 index 0000000..f4a12dc --- /dev/null +++ b/app/src/main/res/layout/activity_login_face.xml @@ -0,0 +1,71 @@ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 86a5d97..958f021 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -1,19 +1,10 @@ + tools:context=".activity.MainActivity"> - \ No newline at end of file diff --git a/app/src/main/res/layout/item_title_time.xml b/app/src/main/res/layout/item_title_time.xml new file mode 100644 index 0000000..caea9e9 --- /dev/null +++ b/app/src/main/res/layout/item_title_time.xml @@ -0,0 +1,31 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/mipmap-xxhdpi/bg.png b/app/src/main/res/mipmap-xxhdpi/bg.png new file mode 100644 index 0000000..5979fa6 Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/bg.png differ diff --git a/app/src/main/res/mipmap-xxhdpi/bg_face.png b/app/src/main/res/mipmap-xxhdpi/bg_face.png new file mode 100644 index 0000000..64c96b9 Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/bg_face.png differ diff --git a/app/src/main/res/mipmap-xxhdpi/ic_password.png b/app/src/main/res/mipmap-xxhdpi/ic_password.png new file mode 100644 index 0000000..ca70159 Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_password.png differ diff --git a/app/src/main/res/mipmap-xxhdpi/ic_phone.png b/app/src/main/res/mipmap-xxhdpi/ic_phone.png new file mode 100644 index 0000000..9cc79e7 Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_phone.png differ diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml index 2a98c16..d4108e0 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -2,6 +2,5 @@ #FF000000 #FFFFFFFF - - #80000000 + #00000000 \ No newline at end of file diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 86f0dec..1fee65b 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -10,6 +10,14 @@ material = "1.10.0" activity = "1.8.0" constraintlayout = "2.1.4" +accompanistPermissions = "0.37.3" +cameraCore = "1.3.0" +retrofit = "3.0.0" +okhttp = "4.12.0" +timber = "5.0.1" +gson = "2.13.1" +hiltAndroid = "2.56.2" + [libraries] androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" } junit = { group = "junit", name = "junit", version.ref = "junit" } @@ -20,6 +28,23 @@ material = { group = "com.google.android.material", name = "material", version.r androidx-activity = { group = "androidx.activity", name = "activity", version.ref = "activity" } androidx-constraintlayout = { group = "androidx.constraintlayout", name = "constraintlayout", version.ref = "constraintlayout" } +accompanist-permissions = { module = "com.google.accompanist:accompanist-permissions", version.ref = "accompanistPermissions" } +androidx-camera-camera2 = { module = "androidx.camera:camera-camera2", version.ref = "cameraCore" } +androidx-camera-core = { module = "androidx.camera:camera-core", version.ref = "cameraCore" } +androidx-camera-extensions = { module = "androidx.camera:camera-extensions", version.ref = "cameraCore" } +androidx-camera-view = { module = "androidx.camera:camera-view", version.ref = "cameraCore" } +androidx-camera-lifecycle = { module = "androidx.camera:camera-lifecycle", version.ref = "cameraCore" } + +gson = { module = "com.google.code.gson:gson", version.ref = "gson" } +hilt-android-compiler = { module = "com.google.dagger:hilt-android-compiler", version.ref = "hiltAndroid" } +hilt-android = { module = "com.google.dagger:hilt-android", version.ref = "hiltAndroid" } + +logging-interceptor = { module = "com.squareup.okhttp3:logging-interceptor", version.ref = "okhttp" } +okhttp = { module = "com.squareup.okhttp3:okhttp", version.ref = "okhttp" } +retrofit = { module = "com.squareup.retrofit2:retrofit", version.ref = "retrofit" } +converter-gson = { module = "com.squareup.retrofit2:converter-gson", version.ref = "retrofit" } +timber = { module = "com.jakewharton.timber:timber", version.ref = "timber" } + [plugins] android-application = { id = "com.android.application", version.ref = "agp" } kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }