ソースを参照

add(main): home main page

zhaoyadi 2 年 前
コミット
d68c90064f
29 ファイル変更464 行追加66 行削除
  1. 1 0
      .idea/gradle.xml
  2. 32 0
      .idea/inspectionProfiles/Project_Default.xml
  3. 21 0
      app/build.gradle.kts
  4. 20 0
      app/src/main/java/com/zaojiao/app/ui/demo/ComposePerform.kt
  5. 19 8
      app/src/main/java/com/zaojiao/app/ui/home/HomeActivity.kt
  6. 29 0
      app/src/main/java/com/zaojiao/app/ui/home/HomeMainFragment.kt
  7. 12 0
      app/src/main/java/com/zaojiao/app/ui/home/HomePersonFragment.kt
  8. 23 0
      app/src/main/java/com/zaojiao/app/ui/home/HomePlanFragment.kt
  9. 117 0
      app/src/main/java/com/zaojiao/app/ui/home/main/MainComponents.kt
  10. 1 1
      app/src/main/res/layout/activity_home.xml
  11. 6 0
      app/src/main/res/layout/fragment_home_main.xml
  12. 1 37
      app/src/main/res/layout/fragment_person.xml
  13. 46 0
      app/src/main/res/layout/fragment_person_info.xml
  14. 5 0
      app/src/main/res/layout/fragment_plan.xml
  15. 8 4
      app/src/main/res/menu/nav_home_menu.xml
  16. BIN
      app/src/main/res/mipmap-xhdpi/ic_default_avatar.png
  17. BIN
      app/src/main/res/mipmap-xhdpi/ic_home_signup.png
  18. BIN
      app/src/main/res/mipmap-xxhdpi/ic_default_avatar.png
  19. BIN
      app/src/main/res/mipmap-xxhdpi/ic_home_signup.png
  20. BIN
      app/src/main/res/mipmap-xxxhdpi/ic_default_avatar.png
  21. BIN
      app/src/main/res/mipmap-xxxhdpi/ic_home_signup.png
  22. 13 9
      app/src/main/res/navigation/nav_home_graph.xml
  23. 1 0
      app/src/main/res/values/strings.xml
  24. 2 7
      settings.gradle.kts
  25. 23 0
      ui/build.gradle.kts
  26. 21 0
      ui/proguard-rules.pro
  27. 3 0
      ui/src/main/AndroidManifest.xml
  28. 54 0
      ui/src/main/java/com/zaojiao/ui/ClipRRectView.kt
  29. 6 0
      ui/src/main/res/values/styles.xml

+ 1 - 0
.idea/gradle.xml

@@ -13,6 +13,7 @@
             <option value="$PROJECT_DIR$" />
             <option value="$PROJECT_DIR$/app" />
             <option value="$PROJECT_DIR$/http" />
+            <option value="$PROJECT_DIR$/ui" />
           </set>
         </option>
       </GradleProjectSettings>

+ 32 - 0
.idea/inspectionProfiles/Project_Default.xml

@@ -0,0 +1,32 @@
+<component name="InspectionProjectProfileManager">
+  <profile version="1.0">
+    <option name="myName" value="Project Default" />
+    <inspection_tool class="PreviewAnnotationInFunctionWithParameters" enabled="true" level="ERROR" enabled_by_default="true">
+      <option name="composableFile" value="true" />
+    </inspection_tool>
+    <inspection_tool class="PreviewApiLevelMustBeValid" enabled="true" level="ERROR" enabled_by_default="true">
+      <option name="composableFile" value="true" />
+    </inspection_tool>
+    <inspection_tool class="PreviewDimensionRespectsLimit" enabled="true" level="WARNING" enabled_by_default="true">
+      <option name="composableFile" value="true" />
+    </inspection_tool>
+    <inspection_tool class="PreviewFontScaleMustBeGreaterThanZero" enabled="true" level="ERROR" enabled_by_default="true">
+      <option name="composableFile" value="true" />
+    </inspection_tool>
+    <inspection_tool class="PreviewMultipleParameterProviders" enabled="true" level="ERROR" enabled_by_default="true">
+      <option name="composableFile" value="true" />
+    </inspection_tool>
+    <inspection_tool class="PreviewMustBeTopLevelFunction" enabled="true" level="ERROR" enabled_by_default="true">
+      <option name="composableFile" value="true" />
+    </inspection_tool>
+    <inspection_tool class="PreviewNeedsComposableAnnotation" enabled="true" level="ERROR" enabled_by_default="true">
+      <option name="composableFile" value="true" />
+    </inspection_tool>
+    <inspection_tool class="PreviewNotSupportedInUnitTestFiles" enabled="true" level="ERROR" enabled_by_default="true">
+      <option name="composableFile" value="true" />
+    </inspection_tool>
+    <inspection_tool class="PreviewPickerAnnotation" enabled="true" level="ERROR" enabled_by_default="true">
+      <option name="composableFile" value="true" />
+    </inspection_tool>
+  </profile>
+</component>

+ 21 - 0
app/build.gradle.kts

@@ -33,12 +33,25 @@ android {
         targetCompatibility = JavaVersion.VERSION_11
     }
 
+    composeOptions {
+        kotlinCompilerExtensionVersion = "1.4.7"
+    }
+
+    buildFeatures {
+        aidl = true
+        compose = true
+        viewBinding = true
+    }
+
     kotlinOptions {
         jvmTarget = "11"
     }
 }
 
 dependencies {
+    implementation(project(":http"))
+    implementation(project(":ui"))
+
     implementation("androidx.core:core-ktx:1.10.1")
     implementation("androidx.appcompat:appcompat:1.6.1")
     implementation("androidx.navigation:navigation-fragment-ktx:2.5.3")
@@ -49,6 +62,14 @@ dependencies {
 
     implementation("com.google.android.material:material:1.9.0")
 
+    implementation(platform("androidx.compose:compose-bom:2023.05.01"))
+    implementation("androidx.compose.ui:ui")
+    implementation("androidx.compose.foundation:foundation")
+    implementation("androidx.compose.material3:material3")
+    implementation("androidx.compose.ui:ui-tooling-preview")
+
+    implementation("com.google.accompanist:accompanist-systemuicontroller:0.30.1")
+
     testImplementation("junit:junit:4.13.2")
     androidTestImplementation("androidx.test.ext:junit:1.1.5")
     androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1")

+ 20 - 0
app/src/main/java/com/zaojiao/app/ui/demo/ComposePerform.kt

@@ -0,0 +1,20 @@
+package com.zaojiao.app.ui.demo
+
+import androidx.compose.foundation.layout.Column
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.remember
+
+@Composable
+fun BalanceColumn() {
+    val transactions = listOf(1, 2, 3, 4, 5)
+    val balances = remember(transactions) {
+        transactions.runningReduce { a, b -> a + b }
+    }
+
+    Column() {
+        for ((transaction, balance) in transactions.zip(balances)) {
+            Text("Transaction: $transaction Balance: $balance")
+        }
+    }
+}

+ 19 - 8
app/src/main/java/com/zaojiao/app/ui/home/HomeActivity.kt

@@ -1,18 +1,29 @@
 package com.zaojiao.app.ui.home
 
-import androidx.appcompat.app.AppCompatActivity
 import android.os.Bundle
-import android.view.WindowManager
-import androidx.core.view.ViewCompat
-import androidx.core.view.WindowCompat
-import androidx.core.view.WindowInsetsAnimationCompat
-import androidx.core.view.WindowInsetsCompat
-import androidx.core.view.WindowInsetsControllerCompat
+import androidx.navigation.findNavController
+import androidx.navigation.fragment.NavHostFragment
+import androidx.navigation.ui.setupWithNavController
 import com.zaojiao.app.R
 import com.zaojiao.app.base.BaseActivity
+import com.zaojiao.app.databinding.ActivityHomeBinding
 
-class HomeActivity : BaseActivity(R.layout.activity_home) {
+class HomeActivity : BaseActivity() {
+    private var _binding: ActivityHomeBinding? = null
+    private val binding get() = _binding!!
     override fun onCreate(savedInstanceState: Bundle?) {
         super.onCreate(savedInstanceState)
+
+        _binding = ActivityHomeBinding.inflate(layoutInflater)
+        setContentView(binding.root)
+
+        val navHostFragment =
+            supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment
+        val navController = navHostFragment.navController
+        binding.homeNav.setupWithNavController(navController)
+    }
+
+    override fun onSupportNavigateUp(): Boolean {
+        return findNavController(R.id.nav_host_fragment).navigateUp()
     }
 }

+ 29 - 0
app/src/main/java/com/zaojiao/app/ui/home/HomeMainFragment.kt

@@ -0,0 +1,29 @@
+package com.zaojiao.app.ui.home
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.compose.ui.platform.ComposeView
+import androidx.fragment.app.Fragment
+import com.zaojiao.app.R
+import com.zaojiao.app.ui.home.main.HomeMainTopBar
+
+class HomeMainFragment : Fragment() {
+    override fun onCreateView(
+        inflater: LayoutInflater,
+        container: ViewGroup?,
+        savedInstanceState: Bundle?
+    ): View? {
+        return inflater.inflate(R.layout.fragment_home_main, container, false)
+    }
+
+    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+        super.onViewCreated(view, savedInstanceState)
+        if(view is ComposeView){
+            view.setContent {
+                HomeMainTopBar()
+            }
+        }
+    }
+}

+ 12 - 0
app/src/main/java/com/zaojiao/app/ui/home/HomePersonFragment.kt

@@ -1,6 +1,18 @@
 package com.zaojiao.app.ui.home
 
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
 import androidx.fragment.app.Fragment
+import com.zaojiao.app.R
 
 class HomePersonFragment : Fragment() {
+    override fun onCreateView(
+        inflater: LayoutInflater,
+        container: ViewGroup?,
+        savedInstanceState: Bundle?
+    ): View? {
+        return inflater.inflate(R.layout.fragment_person, container, false)
+    }
 }

+ 23 - 0
app/src/main/java/com/zaojiao/app/ui/home/HomePlanFragment.kt

@@ -1,6 +1,29 @@
 package com.zaojiao.app.ui.home
 
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.compose.ui.platform.ComposeView
 import androidx.fragment.app.Fragment
+import com.zaojiao.app.R
+import com.zaojiao.app.ui.demo.BalanceColumn
 
 class HomePlanFragment : Fragment() {
+    override fun onCreateView(
+        inflater: LayoutInflater,
+        container: ViewGroup?,
+        savedInstanceState: Bundle?
+    ): View? {
+        return inflater.inflate(R.layout.fragment_plan, container, false)
+    }
+
+    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+        super.onViewCreated(view, savedInstanceState)
+
+        val composeStage = view.findViewById<ComposeView>(R.id.compose_stage)
+        composeStage.setContent {
+            BalanceColumn()
+        }
+    }
 }

+ 117 - 0
app/src/main/java/com/zaojiao/app/ui/home/main/MainComponents.kt

@@ -0,0 +1,117 @@
+package com.zaojiao.app.ui.home.main
+
+import androidx.compose.foundation.Image
+import androidx.compose.foundation.background
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.requiredWidth
+import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.layout.statusBarsPadding
+import androidx.compose.foundation.layout.width
+import androidx.compose.foundation.layout.wrapContentWidth
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.clip
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.layout.ContentScale
+import androidx.compose.ui.res.painterResource
+import androidx.compose.ui.text.TextStyle
+import androidx.compose.ui.text.font.FontWeight
+import androidx.compose.ui.text.style.TextOverflow
+import androidx.compose.ui.unit.dp
+import androidx.compose.ui.unit.sp
+import com.zaojiao.app.R
+
+@Composable
+fun HomeMainTopBar() {
+    Row(
+        modifier = Modifier
+            .fillMaxWidth()
+            .statusBarsPadding()
+            .padding(top = 25.dp, bottom = 22.dp)
+    ) {
+        HomeMainTopBarUserInfo()
+        HomeMainTopBarSearchBar()
+        HomeMainTopMainSignupButton()
+    }
+}
+
+@Composable
+fun HomeMainTopBarUserInfo() {
+    Row(
+        modifier = Modifier
+            .padding(start = 16.dp, end = 16.dp)
+            .background(
+                color = Color(0x260B57C7),
+                shape = RoundedCornerShape(100.dp)
+            )
+            .height(44.dp)
+            .wrapContentWidth(),
+        verticalAlignment = Alignment.CenterVertically,
+    ) {
+        Image(
+            painter = painterResource(id = R.mipmap.ic_message),
+            contentDescription = "这是用户的头像",
+            modifier = Modifier
+                .clip(
+                    shape = RoundedCornerShape(50),
+                )
+                .size(44.dp),
+            contentScale = ContentScale.Crop,
+        )
+        Box(modifier = Modifier.width(4.dp))
+        Column {
+            Text(
+                text = "逻辑狗",
+                modifier = Modifier.requiredWidth(45.dp),
+                maxLines = 1,
+                overflow = TextOverflow.Ellipsis,
+                style = TextStyle(
+                    color = Color(0xFF0B57C7),
+                    fontSize = 13.sp,
+                    lineHeight = 18.sp,
+                    fontWeight = FontWeight.Medium,
+                ),
+            )
+            Text(
+                text = "3岁8个月",
+                maxLines = 1,
+                style = TextStyle(
+                    color = Color(0x990B57C7),
+                    fontSize = 11.sp,
+                    lineHeight = 16.sp,
+                    fontWeight = FontWeight.Medium,
+                ),
+            )
+        }
+        Box(modifier = Modifier.width(12.dp))
+    }
+}
+
+@Composable
+fun HomeMainTopBarSearchBar() {
+    Box(
+    ) {
+    }
+}
+
+@Composable
+fun HomeMainTopMainSignupButton() {
+    Image(
+        painter = painterResource(id = R.mipmap.ic_message),
+        contentDescription = "这是用户的头像",
+        modifier = Modifier
+            .clip(
+                shape = RoundedCornerShape(50),
+            )
+            .size(44.dp),
+        contentScale = ContentScale.Crop,
+    )
+}

+ 1 - 1
app/src/main/res/layout/activity_home.xml

@@ -17,7 +17,7 @@
         app:layout_constraintLeft_toLeftOf="parent"
         app:layout_constraintRight_toRightOf="parent"
         app:layout_constraintTop_toTopOf="parent"
-        app:navGraph="@navigation/nav_graph" />
+        app:navGraph="@navigation/nav_home_graph" />
 
     <com.google.android.material.bottomnavigation.BottomNavigationView
         android:id="@+id/home_nav"

+ 6 - 0
app/src/main/res/layout/fragment_home_main.xml

@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<androidx.compose.ui.platform.ComposeView xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+</androidx.compose.ui.platform.ComposeView>

+ 1 - 37
app/src/main/res/layout/fragment_person.xml

@@ -6,7 +6,6 @@
     <androidx.appcompat.widget.LinearLayoutCompat
         android:layout_width="match_parent"
         android:layout_height="41dp"
-        android:background=""
         android:fitsSystemWindows="true"
         android:gravity="center_vertical"
         android:orientation="vertical">
@@ -49,42 +48,7 @@
             android:layout_width="0dp"
             android:layout_height="23dp" />
 
-        <androidx.appcompat.widget.LinearLayoutCompat
-            android:layout_width="match_parent"
-            android:layout_height="70dp">
-
-            <androidx.appcompat.widget.AppCompatImageView
-                android:id="@+id/person_avatar"
-                android:layout_width="70dp"
-                android:layout_height="70dp" />
-
-            <View
-                android:layout_width="12dp"
-                android:layout_height="match_parent" />
-
-            <TextView
-                android:id="@+id/person_name"
-                android:layout_width="0dp"
-                android:layout_height="match_parent"
-                android:layout_weight="1"
-                android:gravity="center_vertical"
-                android:text="逻辑狗" />
-
-            <androidx.appcompat.widget.LinearLayoutCompat
-                android:id="@+id/person_homepage"
-                android:layout_width="wrap_content"
-                android:layout_height="match_parent">
+        <include layout="@layout/fragment_person_info" />
 
-                <TextView
-                    android:layout_width="wrap_content"
-                    android:layout_height="match_parent"
-                    android:gravity="center_vertical"
-                    android:text="个人主页" />
-
-                <View
-                    android:layout_width="7dp"
-                    android:layout_height="match_parent" />
-            </androidx.appcompat.widget.LinearLayoutCompat>
-        </androidx.appcompat.widget.LinearLayoutCompat>
     </androidx.appcompat.widget.LinearLayoutCompat>
 </ScrollView>

+ 46 - 0
app/src/main/res/layout/fragment_person_info.xml

@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="utf-8"?>
+<androidx.appcompat.widget.LinearLayoutCompat xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:layout_width="match_parent"
+    android:layout_height="70dp">
+
+    <com.zaojiao.ui.ClipRRectView
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        app:radius="35dp">
+
+        <androidx.appcompat.widget.AppCompatImageView
+            android:id="@+id/person_avatar"
+            android:layout_width="70dp"
+            android:layout_height="70dp"
+            android:src="@mipmap/ic_qrcode" />
+    </com.zaojiao.ui.ClipRRectView>
+
+    <View
+        android:layout_width="12dp"
+        android:layout_height="match_parent" />
+
+    <TextView
+        android:id="@+id/person_name"
+        android:layout_width="0dp"
+        android:layout_height="match_parent"
+        android:layout_weight="1"
+        android:gravity="center_vertical"
+        android:text="逻辑狗" />
+
+    <androidx.appcompat.widget.LinearLayoutCompat
+        android:id="@+id/person_homepage"
+        android:layout_width="wrap_content"
+        android:layout_height="match_parent">
+
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="match_parent"
+            android:gravity="center_vertical"
+            android:text="个人主页" />
+
+        <View
+            android:layout_width="7dp"
+            android:layout_height="match_parent" />
+    </androidx.appcompat.widget.LinearLayoutCompat>
+</androidx.appcompat.widget.LinearLayoutCompat>

+ 5 - 0
app/src/main/res/layout/fragment_plan.xml

@@ -3,4 +3,9 @@
     android:layout_width="match_parent"
     android:layout_height="match_parent">
 
+    <androidx.compose.ui.platform.ComposeView
+        android:id="@+id/compose_stage"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent" />
+
 </androidx.constraintlayout.widget.ConstraintLayout>

+ 8 - 4
app/src/main/res/menu/nav_home_menu.xml

@@ -1,18 +1,22 @@
 <?xml version="1.0" encoding="utf-8"?>
 <menu xmlns:android="http://schemas.android.com/apk/res/android">
     <item
-        android:id="@id/nav_item_course"
+        android:id="@id/nav_home_main"
+        android:title="@string/home_item_main" />
+
+    <item
+        android:id="@id/nav_home_course"
         android:title="@string/home_item_course" />
 
     <item
-        android:id="@id/nav_item_plan"
+        android:id="@id/nav_home_plan"
         android:title="@string/home_item_plan" />
 
     <item
-        android:id="@id/nav_item_bbs"
+        android:id="@id/nav_home_bbs"
         android:title="@string/home_item_bbs" />
 
     <item
-        android:id="@+id/nav_item_person"
+        android:id="@+id/nav_home_person"
         android:title="@string/home_item_person" />
 </menu>

BIN
app/src/main/res/mipmap-xhdpi/ic_default_avatar.png


BIN
app/src/main/res/mipmap-xhdpi/ic_home_signup.png


BIN
app/src/main/res/mipmap-xxhdpi/ic_default_avatar.png


BIN
app/src/main/res/mipmap-xxhdpi/ic_home_signup.png


BIN
app/src/main/res/mipmap-xxxhdpi/ic_default_avatar.png


BIN
app/src/main/res/mipmap-xxxhdpi/ic_home_signup.png


+ 13 - 9
app/src/main/res/navigation/nav_graph.xml → app/src/main/res/navigation/nav_home_graph.xml

@@ -1,23 +1,27 @@
 <?xml version="1.0" encoding="utf-8"?>
 <navigation xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:app="http://schemas.android.com/apk/res-auto"
-    android:id="@+id/nav_graph.xml"
-    app:startDestination="@id/homeCourseFragment">
+    android:id="@+id/nav_home_graph"
+    app:startDestination="@id/nav_home_main">
 
     <fragment
-        android:id="@+id/homeCourseFragment"
+        android:id="@+id/nav_home_main"
+        android:name="com.zaojiao.app.ui.home.HomeMainFragment"
+        android:label="HomeMainFragment" />
+    <fragment
+        android:id="@+id/nav_home_course"
         android:name="com.zaojiao.app.ui.home.HomeCourseFragment"
         android:label="HomeCourseFragment" />
     <fragment
-        android:id="@+id/homeBBSFragment"
-        android:name="com.zaojiao.app.ui.home.HomeBBSFragment"
-        android:label="HomeBBSFragment" />
-    <fragment
-        android:id="@+id/homePlanFragment"
+        android:id="@+id/nav_home_plan"
         android:name="com.zaojiao.app.ui.home.HomePlanFragment"
         android:label="HomePlanFragment" />
     <fragment
-        android:id="@+id/homePersonFragment"
+        android:id="@+id/nav_home_bbs"
+        android:name="com.zaojiao.app.ui.home.HomeBBSFragment"
+        android:label="HomeBBSFragment" />
+    <fragment
+        android:id="@+id/nav_home_person"
         android:name="com.zaojiao.app.ui.home.HomePersonFragment"
         android:label="HomePersonFragment" />
 </navigation>

+ 1 - 0
app/src/main/res/values/strings.xml

@@ -1,5 +1,6 @@
 <resources>
     <string name="app_name">逻辑狗一起成长</string>
+    <string name="home_item_main">首页</string>
     <string name="home_item_course">探索空间</string>
     <string name="home_item_plan">学习计划</string>
     <string name="home_item_bbs">妈咪社团</string>

+ 2 - 7
settings.gradle.kts

@@ -9,18 +9,13 @@ pluginManagement {
 }
 dependencyResolutionManagement {
     repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
+
     repositories {
         google()
         mavenCentral()
     }
-    versionCatalogs {
-        create("libs") {
-            version("minSdkVersion", "24")
-            version("maxSdkVersion", "33")
-            library("androidx-appcompat", "androidx.appcompat:appcompat:1.6.1")
-        }
-    }
 }
 
 include(":app")
 include(":http")
+include(":ui")

+ 23 - 0
ui/build.gradle.kts

@@ -0,0 +1,23 @@
+plugins {
+    id("com.android.library")
+    id("org.jetbrains.kotlin.android")
+}
+
+android {
+    namespace = "com.zaojiao.ui"
+    compileSdk = 33
+    defaultConfig.minSdk = 24
+    kotlinOptions.jvmTarget = "17"
+    compileOptions.sourceCompatibility = JavaVersion.VERSION_17
+    compileOptions.targetCompatibility = JavaVersion.VERSION_17
+
+    buildTypes {
+        release {
+            isMinifyEnabled = false
+        }
+    }
+}
+
+dependencies {
+    implementation("androidx.core:core-ktx:1.10.1")
+}

+ 21 - 0
ui/proguard-rules.pro

@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+#   http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+#   public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile

+ 3 - 0
ui/src/main/AndroidManifest.xml

@@ -0,0 +1,3 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android">
+</manifest>

+ 54 - 0
ui/src/main/java/com/zaojiao/ui/ClipRRectView.kt

@@ -0,0 +1,54 @@
+package com.zaojiao.ui
+
+import android.content.Context
+import android.graphics.Canvas
+import android.graphics.Path
+import android.graphics.RectF
+import android.util.AttributeSet
+import android.view.ViewGroup
+
+class ClipRRectView @JvmOverloads constructor(
+    context: Context,
+    attrs: AttributeSet? = null,
+    defStyle: Int = 0,
+) : ViewGroup(context, attrs, defStyle) {
+    private val path = Path()
+    private var radius = 0f
+
+    init {
+        val ta = context.obtainStyledAttributes(attrs, R.styleable.ClipRRectView)
+        radius = ta.getDimension(R.styleable.ClipRRectView_radius, 0f)
+        ta.recycle()
+    }
+
+    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
+        super.onMeasure(widthMeasureSpec, heightMeasureSpec)
+        assert(childCount <= 1)
+
+        val child = getChildAt(0)
+        measureChild(child, widthMeasureSpec, heightMeasureSpec)
+        setMeasuredDimension(child.measuredWidth, child.measuredHeight)
+    }
+
+    override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) {
+        val child = getChildAt(0)
+        child.layout(l, t, r, b)
+    }
+
+    override fun dispatchDraw(canvas: Canvas?) {
+        path.reset()
+        path.addRoundRect(
+            RectF(left.toFloat(), top.toFloat(), right.toFloat(), bottom.toFloat()),
+            radius,
+            radius,
+            Path.Direction.CW
+        )
+
+        canvas?.apply {
+//            save()
+            clipPath(path)
+            super.dispatchDraw(canvas)
+//            restore()
+        }
+    }
+}

+ 6 - 0
ui/src/main/res/values/styles.xml

@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+    <declare-styleable name="ClipRRectView">
+        <attr name="radius" format="dimension" />
+    </declare-styleable>
+</resources>