Sfoglia il codice sorgente

add(auth): add auto auth

zhaoyadi 2 anni fa
parent
commit
1de1c41189
42 ha cambiato i file con 723 aggiunte e 293 eliminazioni
  1. 1 0
      .idea/gradle.xml
  2. 8 0
      app/build.gradle.kts
  3. 5 1
      app/src/main/AndroidManifest.xml
  4. 13 2
      app/src/main/java/com/zaojiao/app/MainActivity.kt
  5. 6 0
      app/src/main/res/values/themes.xml
  6. 21 0
      core/auth/build.gradle.kts
  7. 17 0
      core/auth/src/main/AndroidManifest.xml
  8. 61 0
      core/auth/src/main/kotlin/com/zaojiao/app/core/auth/LoginActivity.kt
  9. 23 0
      core/auth/src/main/kotlin/com/zaojiao/app/core/auth/TokenActivity.kt
  10. 61 0
      core/auth/src/main/kotlin/com/zaojiao/app/core/auth/TokenManager.kt
  11. 9 0
      core/auth/src/main/kotlin/com/zaojiao/app/core/auth/TokenState.kt
  12. 18 0
      core/auth/src/main/kotlin/com/zaojiao/app/core/auth/di/TokenModule.kt
  13. 22 0
      core/auth/src/main/res/layout/layout_login.xml
  14. 0 26
      core/common/src/main/kotlin/com/zaojiao/app/core/common/data/BaseRepository.kt
  15. 40 0
      core/common/src/main/kotlin/com/zaojiao/app/core/common/pref/TokenPreferences.kt
  16. 3 5
      core/common/src/main/kotlin/com/zaojiao/app/core/common/state/UiState.kt
  17. 3 0
      core/http/build.gradle.kts
  18. 14 2
      core/http/src/main/java/com/zaojiao/app/core/http/di/HttpModule.kt
  19. 32 19
      core/http/src/main/java/com/zaojiao/app/core/http/interceptor/ResultInterceptor.kt
  20. 74 3
      core/http/src/main/java/com/zaojiao/app/core/http/interceptor/TokenInterceptor.kt
  21. 20 5
      data/domain/src/main/kotlin/com/zaojiao/app/data/domain/AccountUseCase.kt
  22. 0 22
      data/local/src/main/kotlin/com/zaojiao/app/data/local/di/LocalDataModule.kt
  23. 0 56
      data/local/src/main/kotlin/com/zaojiao/app/data/local/token/LocalTokenData.kt
  24. 0 24
      data/local/src/main/kotlin/com/zaojiao/app/data/local/token/TokenPreferencesSerializer.kt
  25. 0 12
      data/local/src/main/proto/com.zaojiao.app.data.local/token_preferences.proto
  26. 39 0
      data/remote/src/main/kotlin/com/zaojiao/app/data/remote/RemoteLoginData.kt
  27. 9 0
      data/remote/src/main/kotlin/com/zaojiao/app/data/remote/api/BindApi.kt
  28. 26 0
      data/remote/src/main/kotlin/com/zaojiao/app/data/remote/api/LoginApi.kt
  29. 9 0
      data/remote/src/main/kotlin/com/zaojiao/app/data/remote/di/ApiModule.kt
  30. 6 0
      data/repo/src/main/kotlin/com/zaojiao/app/data/repo/BabyRepository.kt
  31. 0 7
      data/repo/src/main/kotlin/com/zaojiao/app/data/repo/TokenRepository.kt
  32. 6 0
      data/repo/src/main/kotlin/com/zaojiao/app/data/repo/UserRepository.kt
  33. 0 9
      data/repo/src/main/kotlin/com/zaojiao/app/data/repo/di/RepoModule.kt
  34. 10 6
      data/repo/src/main/kotlin/com/zaojiao/app/data/repo/impl/BabyRepositoryImpl.kt
  35. 28 7
      data/repo/src/main/kotlin/com/zaojiao/app/data/repo/impl/LoginRepositoryImpl.kt
  36. 0 21
      data/repo/src/main/kotlin/com/zaojiao/app/data/repo/impl/TokenRepositoryImpl.kt
  37. 6 16
      data/repo/src/main/kotlin/com/zaojiao/app/data/repo/impl/UserRepositoryImpl.kt
  38. 71 34
      feat/home/src/main/kotlin/com/zaojiao/app/feat/home/index/HomeIndexTopBar.kt
  39. 38 15
      feat/home/src/main/kotlin/com/zaojiao/app/feat/home/index/HomeIndexViewModel.kt
  40. 15 1
      feat/home/src/main/kotlin/com/zaojiao/app/feat/home/index/state/HomeIndexUserUiState.kt
  41. 8 0
      feat/home/src/main/kotlin/com/zaojiao/app/feat/home/personal/HomePersonalViewModel.kt
  42. 1 0
      settings.gradle.kts

+ 1 - 0
.idea/gradle.xml

@@ -27,6 +27,7 @@
             <option value="$PROJECT_DIR$/built" />
             <option value="$PROJECT_DIR$/built/convention" />
             <option value="$PROJECT_DIR$/core" />
+            <option value="$PROJECT_DIR$/core/auth" />
             <option value="$PROJECT_DIR$/core/common" />
             <option value="$PROJECT_DIR$/core/http" />
             <option value="$PROJECT_DIR$/data" />

+ 8 - 0
app/build.gradle.kts

@@ -26,8 +26,14 @@ android {
 }
 
 dependencies {
+    implementation(project(":core:common"))
+    implementation(project(":core:auth"))
+
     implementation(project(":feat:home"))
 
+    implementation(project(":data:domain"))
+
+    implementation("androidx.core:core-splashscreen:1.0.0")
     implementation("androidx.activity:activity-compose:1.7.2")
 
     implementation("androidx.appcompat:appcompat:1.6.1")
@@ -37,6 +43,8 @@ dependencies {
 
     implementation("com.google.android.material:material:1.9.0")
 
+    api("com.alipay.sdk:alipaysdk-android:+@aar")
+
     implementation(libs.coil.kt)
     implementation(libs.coil.kt.svg)
 

+ 5 - 1
app/src/main/AndroidManifest.xml

@@ -1,6 +1,10 @@
 <?xml version="1.0" encoding="utf-8"?>
 <manifest xmlns:android="http://schemas.android.com/apk/res/android">
 
+    <uses-permission android:name="android.permission.INTERNET"/>
+    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
+    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
+
     <application
         android:name=".LJGApplication"
         android:allowBackup="false"
@@ -12,7 +16,7 @@
         android:theme="@style/Theme.Luojigou">
 
         <activity
-            android:name="com.zaojiao.app.EntryActivity"
+            android:name="com.zaojiao.app.MainActivity"
             android:exported="true"
             android:theme="@style/Theme.Luojigou.LightBar">
             <intent-filter>

+ 13 - 2
app/src/main/java/com/zaojiao/app/EntryActivity.kt → app/src/main/java/com/zaojiao/app/MainActivity.kt

@@ -1,5 +1,6 @@
 package com.zaojiao.app
 
+import android.content.Intent
 import android.graphics.Color
 import android.os.Build
 import android.os.Bundle
@@ -11,15 +12,20 @@ import androidx.core.view.WindowCompat
 import androidx.core.view.WindowInsetsCompat
 import androidx.core.view.WindowInsetsControllerCompat
 import com.google.accompanist.systemuicontroller.rememberSystemUiController
+import com.zaojiao.app.core.auth.TokenManager
 import com.zaojiao.app.ui.App
 import dagger.hilt.android.AndroidEntryPoint
+import javax.inject.Inject
 
 @AndroidEntryPoint
-class EntryActivity : ComponentActivity() {
-    private lateinit var windowInsetsController: WindowInsetsControllerCompat
+class MainActivity : ComponentActivity() {
+    @Inject
+    lateinit var tokenManager: TokenManager
 
+    private lateinit var windowInsetsController: WindowInsetsControllerCompat
     override fun onCreate(savedInstanceState: Bundle?) {
         super.onCreate(savedInstanceState)
+        tokenManager.attach(this)
         configureSystemBar()
         setContent {
             val systemUiController = rememberSystemUiController()
@@ -42,4 +48,9 @@ class EntryActivity : ComponentActivity() {
             show(WindowInsetsCompat.Type.systemBars())
         }
     }
+
+    override fun onDestroy() {
+        super.onDestroy()
+        tokenManager.detach()
+    }
 }

+ 6 - 0
app/src/main/res/values/themes.xml

@@ -18,6 +18,12 @@
         <item name="bottomNavigationStyle">@style/Theme.App.BottomBar</item>
     </style>
 
+    <style name="Theme.App.Starting" parent="Theme.SplashScreen">
+        <item name="windowSplashScreenBackground">@android:color/white</item>
+        <item name="windowSplashScreenAnimatedIcon">@drawable/ic_launcher_foreground</item>
+        <item name="postSplashScreenTheme">@style/Theme.Luojigou.LightBar</item>
+    </style>
+
     <style name="Theme.Luojigou.LightBar">
         <item name="android:windowLightStatusBar">true</item>
         <item name="android:windowLightNavigationBar">true</item>

+ 21 - 0
core/auth/build.gradle.kts

@@ -0,0 +1,21 @@
+plugins {
+    id("d.convention.library")
+    id("d.convention.coroutines")
+    id("d.convention.hilt")
+}
+
+android {
+    namespace = "com.zaojiao.app.core.auth"
+}
+
+dependencies {
+    implementation(project(":core:common"))
+
+    implementation("androidx.appcompat:appcompat:1.6.1")
+    implementation("com.google.android.material:material:1.9.0")
+
+    implementation("com.squareup.okhttp3:okhttp:4.10.0")
+
+    implementation("androidx.datastore:datastore:1.0.0")
+    implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.5.1")
+}

+ 17 - 0
core/auth/src/main/AndroidManifest.xml

@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <application>
+        <activity android:name=".LoginActivity" />
+
+        <activity
+            android:name=".TokenActivity"
+            android:exported="true">
+            <intent-filter>
+                <data
+                    android:host="/com.zaojiao.app"
+                    android:scheme="token" />
+            </intent-filter>
+        </activity>
+    </application>
+</manifest>

+ 61 - 0
core/auth/src/main/kotlin/com/zaojiao/app/core/auth/LoginActivity.kt

@@ -0,0 +1,61 @@
+package com.zaojiao.app.core.auth
+
+import android.content.Intent
+import android.os.Bundle
+import android.util.JsonReader
+import android.widget.Button
+import android.widget.EditText
+import androidx.appcompat.app.AppCompatActivity
+import kotlinx.serialization.json.Json
+import okhttp3.Call
+import okhttp3.Callback
+import okhttp3.OkHttp
+import okhttp3.OkHttpClient
+import okhttp3.Request
+import okhttp3.Response
+import org.json.JSONObject
+import java.io.IOException
+import java.util.concurrent.TimeUnit
+import kotlin.concurrent.thread
+
+class LoginActivity : AppCompatActivity() {
+    private lateinit var editPhone: EditText
+    private lateinit var editSms: EditText
+    private lateinit var actionLogin: Button
+
+    private val okHttpClient = OkHttpClient.Builder()
+        .connectTimeout(30000, TimeUnit.MILLISECONDS)
+        .readTimeout(30000, TimeUnit.MILLISECONDS)
+        .writeTimeout(30000, TimeUnit.MILLISECONDS)
+        .retryOnConnectionFailure(true)
+        .followRedirects(false)
+        .followSslRedirects(false)
+        .build()
+
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+        setContentView(R.layout.layout_login)
+
+        editPhone = findViewById(R.id.edit_phone)
+        editSms = findViewById(R.id.edit_sms)
+        actionLogin = findViewById(R.id.action_login)
+
+        actionLogin.setOnClickListener {
+            val phone = "15141666708"
+            val sms = "5566"
+
+            val request = Request.Builder()
+                .url("https://open.test.luojigou.vip/app/sms/v2/checkCode/app/$phone/$sms")
+                .get()
+                .build()
+            thread {
+                Thread.sleep(3000)
+
+                Intent(this@LoginActivity, TokenActivity::class.java).apply {
+                    startActivity(this)
+                    finish()
+                }
+            }
+        }
+    }
+}

+ 23 - 0
core/auth/src/main/kotlin/com/zaojiao/app/core/auth/TokenActivity.kt

@@ -0,0 +1,23 @@
+package com.zaojiao.app.core.auth
+
+import android.app.Activity
+import android.os.Bundle
+import com.zaojiao.app.core.common.pref.saveAccessToken
+import dagger.hilt.EntryPoint
+import dagger.hilt.android.AndroidEntryPoint
+import javax.inject.Inject
+
+class TokenActivity : Activity() {
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+
+        TokenManager.updateToken(
+            accessToken = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhdWQiOiIxMzY0ODM1MjU0MDY0ODgxNjY1IiwiZXhwIjoxNjg5MzAxNTEzfQ.ddtv_bU3LbyBzvAqrKCeYM0UCUb_37WPL7nfk25wmsE",
+            refreshToken = "",
+        )
+
+        saveAccessToken("eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhdWQiOiIxMzY0ODM1MjU0MDY0ODgxNjY1IiwiZXhwIjoxNjg5MzAxNTEzfQ.ddtv_bU3LbyBzvAqrKCeYM0UCUb_37WPL7nfk25wmsE")
+
+        finish()
+    }
+}

+ 61 - 0
core/auth/src/main/kotlin/com/zaojiao/app/core/auth/TokenManager.kt

@@ -0,0 +1,61 @@
+package com.zaojiao.app.core.auth
+
+import android.app.Activity
+import android.content.Intent
+import java.lang.ref.WeakReference
+import java.util.concurrent.CompletableFuture
+
+object TokenManager {
+    const val ACCESS_TOKEN = "extra_token"
+    const val REFRESH_TOKEN = "extra_token"
+
+    val lock: Any = Any()
+
+    private var activity: WeakReference<Activity?> = WeakReference(null)
+
+    private var tokenFuture: CompletableFuture<String>? = null
+
+    fun attach(activity: Activity) {
+        this.activity = WeakReference(activity)
+    }
+
+    fun detach() {
+        this.activity.clear()
+    }
+
+
+    internal fun putToken(intent: Intent, accessToken: String, refreshToken: String) {
+        intent.putExtra(ACCESS_TOKEN, accessToken)
+        intent.putExtra(REFRESH_TOKEN, refreshToken)
+    }
+
+    @Throws(IllegalAccessException::class)
+    internal fun fromIntent(intent: Intent): TokenState {
+        val accessToken = intent.getStringExtra(ACCESS_TOKEN) ?: throw IllegalAccessException("")
+        val refreshToken = intent.getStringExtra(REFRESH_TOKEN) ?: throw IllegalAccessException("")
+
+        return TokenState(
+            accessToken = accessToken,
+            refreshToken = refreshToken,
+        )
+    }
+
+    fun requestToken(): CompletableFuture<String> {
+        return tokenFuture ?: CompletableFuture<String>().apply {
+            tokenFuture = this
+            activity.get()?.apply {
+                val intent = Intent(this, LoginActivity::class.java)
+                startActivity(intent)
+            }
+            return this
+        }
+    }
+
+    internal fun updateToken(accessToken: String, refreshToken: String) {
+        tokenFuture?.complete(accessToken)
+    }
+
+    fun deleteToken() {
+
+    }
+}

+ 9 - 0
core/auth/src/main/kotlin/com/zaojiao/app/core/auth/TokenState.kt

@@ -0,0 +1,9 @@
+package com.zaojiao.app.core.auth
+
+import kotlinx.serialization.Serializable
+
+@Serializable
+data class TokenState(
+    val accessToken: String,
+    val refreshToken: String,
+)

+ 18 - 0
core/auth/src/main/kotlin/com/zaojiao/app/core/auth/di/TokenModule.kt

@@ -0,0 +1,18 @@
+package com.zaojiao.app.core.auth.di
+
+import com.zaojiao.app.core.auth.TokenManager
+import dagger.Module
+import dagger.Provides
+import dagger.hilt.InstallIn
+import dagger.hilt.components.SingletonComponent
+import javax.inject.Singleton
+
+@Module
+@InstallIn(SingletonComponent::class)
+class TokenModule {
+    @Provides
+    @Singleton
+    fun provideTokenManager(): TokenManager {
+        return TokenManager
+    }
+}

+ 22 - 0
core/auth/src/main/res/layout/layout_login.xml

@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical">
+
+    <EditText
+        android:id="@+id/edit_phone"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content" />
+
+    <EditText
+        android:id="@+id/edit_sms"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content" />
+
+    <Button
+        android:id="@+id/action_login"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:text="登录" />
+</LinearLayout>

+ 0 - 26
core/common/src/main/kotlin/com/zaojiao/app/core/common/data/BaseRepository.kt

@@ -1,26 +0,0 @@
-package com.zaojiao.app.core.common.data
-
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.launch
-
-abstract class BaseRepository(
-    private val coroutineScope: CoroutineScope,
-) {
-    init {
-        coroutineScope.launch {
-            initState()
-        }
-    }
-
-    protected open suspend fun initState() {
-
-    }
-
-    protected open fun onLogout() {
-
-    }
-
-    protected open fun onLogin() {
-
-    }
-}

+ 40 - 0
core/common/src/main/kotlin/com/zaojiao/app/core/common/pref/TokenPreferences.kt

@@ -0,0 +1,40 @@
+package com.zaojiao.app.core.common.pref
+
+import android.content.Context
+import android.content.SharedPreferences
+
+class TokenPreferences {
+}
+
+private const val fileName = "token_prefs"
+
+private const val accessTokenKey = "access_token"
+private const val refreshTokenKey = "refresh_token"
+
+private fun Context.tokenPreferences(): SharedPreferences {
+    return this.getSharedPreferences(fileName, Context.MODE_PRIVATE)
+}
+
+fun Context.getAccessToken(): String? {
+    return tokenPreferences().getString(accessTokenKey, null)
+}
+
+ fun Context.getRefreshToken(): String? {
+    return tokenPreferences().getString(refreshTokenKey, null)
+}
+
+ fun Context.saveAccessToken(accessToken: String) {
+    tokenPreferences().edit().putString(accessTokenKey, accessToken).apply()
+}
+
+ fun Context.saveRefreshToken(refreshToken: String) {
+    tokenPreferences().edit().putString(refreshTokenKey, refreshToken).apply()
+}
+
+ fun Context.clearAccessToken() {
+    tokenPreferences().edit().putString(accessTokenKey, null).apply()
+}
+
+ fun Context.clearRefreshToken() {
+    tokenPreferences().edit().putString(refreshTokenKey, null).apply()
+}

+ 3 - 5
core/common/src/main/kotlin/com/zaojiao/app/core/common/state/UiState.kt

@@ -2,8 +2,6 @@ package com.zaojiao.app.core.common.state
 
 sealed interface UiState {
     object Loading : UiState
-
-    data class Success<T>(val data: T) : UiState
-
-    data class Failure(val throwable: Throwable) : UiState
-}
+    object Success : UiState
+    object Failure : UiState
+}

+ 3 - 0
core/http/build.gradle.kts

@@ -8,6 +8,9 @@ android {
 }
 
 dependencies {
+    implementation(project(":core:common"))
+    implementation(project(":core:auth"))
+
     implementation(libs.coil.kt)
     implementation(libs.coil.kt.svg)
 

+ 14 - 2
core/http/src/main/java/com/zaojiao/app/core/http/di/HttpModule.kt

@@ -3,10 +3,13 @@ package com.zaojiao.app.core.http.di
 import android.content.Context
 import coil.ImageLoader
 import coil.decode.SvgDecoder
+import com.squareup.moshi.JsonAdapter
 import com.squareup.moshi.Moshi
+import com.squareup.moshi.Types
 import com.squareup.moshi.adapters.Rfc3339DateJsonAdapter
 import com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory
 import com.zaojiao.app.core.http.adapter.HexColorAdapter
+import com.zaojiao.app.core.http.common.NetResult
 import com.zaojiao.app.core.http.converter.ResultConverterFactory
 import com.zaojiao.app.core.http.interceptor.ResultInterceptor
 import com.zaojiao.app.core.http.interceptor.TokenInterceptor
@@ -77,10 +80,10 @@ object HttpModule {
             .retryOnConnectionFailure(true)
             .followRedirects(false)
             .followSslRedirects(false)
-            .addInterceptor(resultInterceptor)
             .addInterceptor(loggingInterceptor)
             .addInterceptor(versionInterceptor)
             .addInterceptor(tokenInterceptor)
+            .addInterceptor(resultInterceptor)
             .build()
     }
 
@@ -102,9 +105,18 @@ object HttpModule {
     @Provides
     @Singleton
     fun provideImageLoader(
+        @Named("timeout") timeout: Long,
         @ApplicationContext application: Context,
-        okHttpClient: OkHttpClient,
     ): ImageLoader {
+        val okHttpClient = OkHttpClient.Builder()
+            .connectTimeout(timeout, TimeUnit.MILLISECONDS)
+            .readTimeout(timeout, TimeUnit.MILLISECONDS)
+            .writeTimeout(timeout, TimeUnit.MILLISECONDS)
+            .retryOnConnectionFailure(true)
+            .followRedirects(false)
+            .followSslRedirects(false)
+            .build()
+
         return ImageLoader.Builder(application)
             .callFactory(okHttpClient)
             .components { add(SvgDecoder.Factory()) }

+ 32 - 19
core/http/src/main/java/com/zaojiao/app/core/http/interceptor/ResultInterceptor.kt

@@ -1,6 +1,6 @@
 package com.zaojiao.app.core.http.interceptor
 
-import android.util.Log
+import com.squareup.moshi.Json
 import com.squareup.moshi.JsonAdapter
 import com.squareup.moshi.Moshi
 import com.squareup.moshi.Types
@@ -12,31 +12,44 @@ import okhttp3.Response
 import okhttp3.ResponseBody.Companion.toResponseBody
 import javax.inject.Inject
 
+private data class JsonResult(
+    val status: Int,
+    val msg: String?,
+)
+
 class ResultInterceptor @Inject constructor(
     private val moshi: Moshi,
 ) : Interceptor {
-    private lateinit var resultAdapter: JsonAdapter<NetResult<String>>
-
-    init {
-        try {
-            resultAdapter =
-                moshi.adapter(Types.newParameterizedType(NetResult::class.java, String::class.java))
-        } catch (e: Throwable) {
-            Log.d("ResultInterceptor", e.message ?: "")
-        }
-    }
-
+    private var resultAdapter: JsonAdapter<JsonResult> =
+        moshi.adapter(Types.newParameterizedType(JsonResult::class.java))
 
     override fun intercept(chain: Interceptor.Chain): Response {
         val request = chain.request()
+        val response = chain.proceed(request)
 
         try {
-            return chain.proceed(request)
+            val newResponse = response.newBuilder()
+
+            response.body?.apply {
+                /* 修改响应中的code值 */
+                val body = this.string()
+                val result = resultAdapter.fromJson(body)
+                result?.run {
+                    newResponse.code(status)
+                }
+
+                val newBody = body.toResponseBody(
+                    contentType = this.contentType()
+                )
+                newResponse.body(newBody)
+            }
+
+            return newResponse.build()
         } catch (e: Throwable) {
-            val result = NetResult(
-                status = 5050,
-                data = null,
-                message = e.message,
+            e.printStackTrace()
+            val result = JsonResult(
+                status = 500,
+                msg = e.message,
             )
 
             val body = resultAdapter.toJson(result).toResponseBody(
@@ -46,8 +59,8 @@ class ResultInterceptor @Inject constructor(
             return Response.Builder()
                 .request(request)
                 .protocol(Protocol.HTTP_1_1)
-                .code(200)
-                .message("OK")
+                .code(500)
+                .message("Error")
                 .body(body)
                 .build()
         }

+ 74 - 3
core/http/src/main/java/com/zaojiao/app/core/http/interceptor/TokenInterceptor.kt

@@ -1,15 +1,86 @@
 package com.zaojiao.app.core.http.interceptor
 
+import android.content.Context
+import android.util.Log
+import com.squareup.moshi.JsonAdapter
+import com.squareup.moshi.Moshi
+import com.squareup.moshi.Types
+import com.zaojiao.app.core.auth.TokenManager
+import com.zaojiao.app.core.common.pref.clearAccessToken
+import com.zaojiao.app.core.common.pref.getAccessToken
+import com.zaojiao.app.core.common.pref.getRefreshToken
+import com.zaojiao.app.core.common.pref.saveAccessToken
+import com.zaojiao.app.core.http.common.NetResult
+import com.zaojiao.app.core.http.common.isSuccess
+import dagger.hilt.android.qualifiers.ApplicationContext
 import okhttp3.Interceptor
 import okhttp3.Response
 import javax.inject.Inject
 
-class TokenInterceptor @Inject constructor() : Interceptor {
+class TokenInterceptor @Inject constructor(
+    private val moshi: Moshi,
+    private val tokenManager: TokenManager,
+    @ApplicationContext private val context: Context,
+) : Interceptor {
+    private var jsonAdapter: JsonAdapter<NetResult<String>>
+
+    private var accessToken: String? = context.getAccessToken()
+    private var refreshToken: String? = context.getRefreshToken()
+
+    private var lock: Boolean = false
+
+    init {
+        val types = Types.newParameterizedType(
+            NetResult::class.java,
+            String::class.java,
+        )
+        jsonAdapter = moshi.adapter(types)
+    }
+
     override fun intercept(chain: Interceptor.Chain): Response {
         val newRequest = chain.request().newBuilder()
+        accessToken?.let { newRequest.addHeader("token", it) }
+        val response = chain.proceed(newRequest.build())
+
+        when (response.code) {
+            401 -> {
+                synchronized(tokenManager.lock) {
+                    if (response.request.header("token") == accessToken) {
+                        requestToken()
+                    }
+
+                    accessToken?.let {
+                        val retryRequest = chain.request().newBuilder()
+                        retryRequest.addHeader("token", it)
+                        return chain.proceed(retryRequest.build())
+                    }
+                }
+            }
+
+            403 -> {
+                synchronized(tokenManager.lock) {
+                    if (response.request.header("token") == accessToken) {
+                        //                    refreshToken()
+                        requestToken()
+                    }
+
+                    accessToken?.let {
+                        val retryRequest = chain.request().newBuilder()
+                        retryRequest.addHeader("token", it)
+                        return chain.proceed(retryRequest.build())
+                    }
+                }
+            }
+        }
+
+        return response
+    }
+
+    private fun requestToken() {
+        accessToken = tokenManager.requestToken().get()
+    }
 
-        newRequest.addHeader("token", "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhdWQiOiIxMzY0ODM1MjU0MDY0ODgxNjY1IiwiZXhwIjoxNjg5MzAxNTEzfQ.ddtv_bU3LbyBzvAqrKCeYM0UCUb_37WPL7nfk25wmsE")
+    private fun refreshToken() {
 
-        return chain.proceed(newRequest.build())
     }
 }

+ 20 - 5
data/domain/src/main/kotlin/com/zaojiao/app/data/domain/AccountUseCase.kt

@@ -1,30 +1,45 @@
 package com.zaojiao.app.data.domain
 
 import android.content.Context
+import com.zaojiao.app.core.common.state.UiState
 import com.zaojiao.app.data.repo.BabyRepository
 import com.zaojiao.app.data.repo.LoginRepository
 import com.zaojiao.app.data.repo.LoginState
-import com.zaojiao.app.data.repo.TokenRepository
 import com.zaojiao.app.data.repo.UserRepository
 import dagger.hilt.android.qualifiers.ApplicationContext
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.flow
 import kotlinx.coroutines.flow.onEach
 import javax.inject.Inject
 import javax.inject.Singleton
 
-
 @Singleton
 class AccountUseCase @Inject constructor(
     private val loginRepository: LoginRepository,
     private val userRepository: UserRepository,
     private val babyRepository: BabyRepository,
-    private val tokenRepository: TokenRepository,
     @ApplicationContext private val context: Context,
 ) {
+    val appState: Flow<UiState> = flow {
+        emit(UiState.Loading)
 
-    operator fun invoke() {
         loginRepository.state.onEach {
-            if (it == LoginState.OUT) {
+            try {
+                if (it == LoginState.IN) {
+                    userRepository.getUser()
+                    babyRepository.getBaby()
+                } else {
+                    userRepository.deleteUser()
+                    babyRepository.deleteAllBaby()
+                }
+                emit(UiState.Success)
+            } catch (throwable: Throwable) {
+                emit(UiState.Failure)
             }
         }
     }
+
+    operator fun invoke() {
+
+    }
 }

+ 0 - 22
data/local/src/main/kotlin/com/zaojiao/app/data/local/di/LocalDataModule.kt

@@ -9,11 +9,9 @@ import com.zaojiao.app.core.common.remote.Dispatcher
 import com.zaojiao.app.core.common.remote.di.ApplicationScope
 import com.zaojiao.app.data.local.BabyPreferences
 import com.zaojiao.app.data.local.SettingsPreferences
-import com.zaojiao.app.data.local.TokenPreferences
 import com.zaojiao.app.data.local.UserPreferences
 import com.zaojiao.app.data.local.baby.BabyPreferencesSerializer
 import com.zaojiao.app.data.local.settings.SettingsPreferencesSerializer
-import com.zaojiao.app.data.local.token.TokenPreferencesSerializer
 import com.zaojiao.app.data.local.user.UserPreferencesSerializer
 import dagger.Module
 import dagger.Provides
@@ -27,26 +25,6 @@ import javax.inject.Singleton
 @Module
 @InstallIn(SingletonComponent::class)
 class LocalDataModule {
-
-    /**
-     *  token 的本地存储
-     */
-    @Provides
-    @Singleton
-    fun providerTokenPreferencesDataStore(
-        @ApplicationContext context: Context,
-        @Dispatcher(AppDispatchers.IO) ioDispatcher: CoroutineDispatcher,
-        @ApplicationScope scope: CoroutineScope,
-        tokenPreferencesSerializer: TokenPreferencesSerializer,
-    ): DataStore<TokenPreferences> {
-        return DataStoreFactory.create(
-            serializer = tokenPreferencesSerializer,
-            scope = CoroutineScope(scope.coroutineContext + ioDispatcher),
-        ) {
-            context.dataStoreFile("token_preferences.pb")
-        }
-    }
-
     /**
      *  用户信息 的本地存储
      */

+ 0 - 56
data/local/src/main/kotlin/com/zaojiao/app/data/local/token/LocalTokenData.kt

@@ -1,56 +0,0 @@
-package com.zaojiao.app.data.local.token
-
-import android.util.Log
-import androidx.datastore.core.DataStore
-import com.zaojiao.app.data.local.TokenPreferences
-import com.zaojiao.app.data.local.copy
-import com.zaojiao.app.data.model.TokenModel
-import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.map
-import java.io.IOException
-import javax.inject.Inject
-
-class LocalTokenData @Inject constructor(
-    private val tokenPreferences: DataStore<TokenPreferences>,
-) {
-    val token: Flow<TokenModel?> = tokenPreferences.data.map {
-        if (!it.valid) null else TokenModel(
-            accessToken = it.accessToken,
-            refreshToken = it.refreshToken,
-            expires = it.expires,
-            refreshExpires = it.refreshExpires,
-        )
-    }
-
-    suspend fun updateToken(tokenModel: TokenModel) {
-        try {
-            tokenPreferences.updateData {
-                it.copy {
-                    valid = true
-                    accessToken = tokenModel.accessToken
-                    refreshToken = tokenModel.refreshToken
-                    expires = tokenModel.expires
-                    refreshExpires = tokenModel.refreshExpires
-                }
-            }
-        } catch (exception: IOException) {
-            Log.e("LocalTokenData", "updateToken: Failed....", exception)
-        }
-    }
-
-    suspend fun deleteToken() {
-        try {
-            tokenPreferences.updateData {
-                it.copy {
-                    valid = false
-                    clearAccessToken()
-                    clearRefreshToken()
-                    clearExpires()
-                    clearRefreshExpires()
-                }
-            }
-        } catch (exception: IOException) {
-            Log.e("LocalTokenData", "deleteToken: Failed....", exception)
-        }
-    }
-}

+ 0 - 24
data/local/src/main/kotlin/com/zaojiao/app/data/local/token/TokenPreferencesSerializer.kt

@@ -1,24 +0,0 @@
-package com.zaojiao.app.data.local.token
-
-import androidx.datastore.core.CorruptionException
-import androidx.datastore.core.Serializer
-import com.zaojiao.app.data.local.TokenPreferences
-import java.io.IOException
-import java.io.InputStream
-import java.io.OutputStream
-import javax.inject.Inject
-
-class TokenPreferencesSerializer @Inject constructor() : Serializer<TokenPreferences> {
-    override val defaultValue: TokenPreferences get() = TokenPreferences.getDefaultInstance()
-    override suspend fun readFrom(input: InputStream): TokenPreferences {
-        try {
-            return TokenPreferences.parseFrom(input)
-        } catch (exception: IOException) {
-            throw CorruptionException("OPEN TOKEN PROTO FAILURE", exception)
-        }
-    }
-
-    override suspend fun writeTo(t: TokenPreferences, output: OutputStream) {
-        t.writeTo(output)
-    }
-}

+ 0 - 12
data/local/src/main/proto/com.zaojiao.app.data.local/token_preferences.proto

@@ -1,12 +0,0 @@
-syntax = "proto3";
-
-option java_package = "com.zaojiao.app.data.local";
-option java_multiple_files = true;
-
-message TokenPreferences{
-  bool valid = 1;
-  string access_token = 2;
-  string refresh_token = 3;
-  int32 expires = 4;
-  int32 refresh_expires = 5;
-}

+ 39 - 0
data/remote/src/main/kotlin/com/zaojiao/app/data/remote/RemoteLoginData.kt

@@ -0,0 +1,39 @@
+package com.zaojiao.app.data.remote
+
+import com.zaojiao.app.core.common.state.DataState
+import com.zaojiao.app.data.model.TokenModel
+import com.zaojiao.app.data.remote.api.LoginApi
+import javax.inject.Inject
+import javax.inject.Singleton
+
+@Singleton
+class RemoteLoginData @Inject constructor(
+    private val loginApi: LoginApi,
+) {
+    suspend fun loginBySms(phone: String, code: String): DataState<TokenModel?> {
+        return try {
+            val result = loginApi.loginBySms(phone, code).data
+            DataState.Success(result)
+        } catch (throwable: Throwable) {
+            DataState.Failure(throwable)
+        }
+    }
+
+    suspend fun loginByWechat(code: String): DataState<TokenModel?> {
+        return try {
+            val result = loginApi.loginByWechat(code).data
+            DataState.Success(result)
+        } catch (throwable: Throwable) {
+            DataState.Failure(throwable)
+        }
+    }
+
+    suspend fun loginByOneClick(code: String): DataState<TokenModel?> {
+        return try {
+            val result = loginApi.loginByOneClick(code).data
+            DataState.Success(result)
+        } catch (throwable: Throwable) {
+            DataState.Failure(throwable)
+        }
+    }
+}

+ 9 - 0
data/remote/src/main/kotlin/com/zaojiao/app/data/remote/api/BindApi.kt

@@ -0,0 +1,9 @@
+package com.zaojiao.app.data.remote.api
+
+import com.zaojiao.app.core.http.common.NetResult
+
+interface BindApi {
+    fun bindPhone(): NetResult<Boolean>
+
+    fun bindWechat(): NetResult<Boolean>
+}

+ 26 - 0
data/remote/src/main/kotlin/com/zaojiao/app/data/remote/api/LoginApi.kt

@@ -0,0 +1,26 @@
+package com.zaojiao.app.data.remote.api
+
+import com.zaojiao.app.core.http.common.NetResult
+import com.zaojiao.app.data.model.TokenModel
+import retrofit2.http.Body
+import retrofit2.http.GET
+import retrofit2.http.POST
+import retrofit2.http.Path
+
+interface LoginApi {
+    @POST("/app/sms/v2/checkCode/app/{phone}/{code}")
+    fun loginBySms(
+        @Path(value = "phone") phone: String,
+        @Path(value = "code") code: String,
+    ): NetResult<TokenModel>
+
+    @GET("/app/login/v2/{code}")
+    fun loginByWechat(
+        @Path(value = "code") code: String,
+    ): NetResult<TokenModel>
+
+    @POST("/app/login/oneClickLogin")
+    fun loginByOneClick(
+        @Body token: String,
+    ): NetResult<TokenModel>
+}

+ 9 - 0
data/remote/src/main/kotlin/com/zaojiao/app/data/remote/di/ApiModule.kt

@@ -1,6 +1,7 @@
 package com.zaojiao.app.data.remote.di
 
 import com.zaojiao.app.data.remote.api.BabyApi
+import com.zaojiao.app.data.remote.api.LoginApi
 import com.zaojiao.app.data.remote.api.UserApi
 import dagger.Module
 import dagger.Provides
@@ -28,4 +29,12 @@ class ApiModule {
     ): BabyApi {
         return retrofit.create(BabyApi::class.java)
     }
+
+    @Singleton
+    @Provides
+    fun provideLoginApi(
+        retrofit: Retrofit
+    ): LoginApi {
+        return retrofit.create(LoginApi::class.java)
+    }
 }

+ 6 - 0
data/repo/src/main/kotlin/com/zaojiao/app/data/repo/BabyRepository.kt

@@ -7,4 +7,10 @@ interface BabyRepository {
     val current: Flow<BabyModel?>
 
     val babyList: Flow<List<BabyModel>>
+
+    suspend fun getBaby()
+
+    suspend fun deleteBaby()
+
+    suspend fun deleteAllBaby()
 }

+ 0 - 7
data/repo/src/main/kotlin/com/zaojiao/app/data/repo/TokenRepository.kt

@@ -1,7 +0,0 @@
-package com.zaojiao.app.data.repo
-
-interface TokenRepository {
-    fun saveToken()
-
-    fun deleteToken()
-}

+ 6 - 0
data/repo/src/main/kotlin/com/zaojiao/app/data/repo/UserRepository.kt

@@ -13,4 +13,10 @@ interface UserRepository {
     val phoneNumber: Flow<String?>
 
     val wechatState: Flow<Boolean>
+
+    suspend fun getUser()
+
+    suspend fun updateUser(userModel: UserModel)
+
+    suspend fun deleteUser()
 }

+ 0 - 9
data/repo/src/main/kotlin/com/zaojiao/app/data/repo/di/RepoModule.kt

@@ -2,11 +2,9 @@ package com.zaojiao.app.data.repo.di
 
 import com.zaojiao.app.data.repo.BabyRepository
 import com.zaojiao.app.data.repo.LoginRepository
-import com.zaojiao.app.data.repo.TokenRepository
 import com.zaojiao.app.data.repo.UserRepository
 import com.zaojiao.app.data.repo.impl.BabyRepositoryImpl
 import com.zaojiao.app.data.repo.impl.LoginRepositoryImpl
-import com.zaojiao.app.data.repo.impl.TokenRepositoryImpl
 import com.zaojiao.app.data.repo.impl.UserRepositoryImpl
 import dagger.Binds
 import dagger.Module
@@ -17,13 +15,6 @@ import javax.inject.Singleton
 @Module
 @InstallIn(SingletonComponent::class)
 interface RepoModule {
-
-    @Binds
-    @Singleton
-    fun bindTokenRepository(
-        tokenRepositoryImpl: TokenRepositoryImpl,
-    ): TokenRepository
-
     @Binds
     @Singleton
     fun bindsUserRepository(

+ 10 - 6
data/repo/src/main/kotlin/com/zaojiao/app/data/repo/impl/BabyRepositoryImpl.kt

@@ -1,6 +1,5 @@
 package com.zaojiao.app.data.repo.impl
 
-import com.zaojiao.app.core.common.data.BaseRepository
 import com.zaojiao.app.core.common.remote.di.ApplicationScope
 import com.zaojiao.app.core.common.state.DataState
 import com.zaojiao.app.data.local.baby.LocalBabyData
@@ -9,21 +8,18 @@ import com.zaojiao.app.data.remote.RemoteBabyData
 import com.zaojiao.app.data.repo.BabyRepository
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.MutableStateFlow
-import kotlinx.coroutines.launch
 import javax.inject.Inject
 
 class BabyRepositoryImpl @Inject constructor(
     private val localBabyData: LocalBabyData,
     private val remoteBabyData: RemoteBabyData,
     @ApplicationScope private val coroutineScope: CoroutineScope,
-) : BaseRepository(coroutineScope), BabyRepository {
+) : BabyRepository {
 
     override val current: Flow<BabyModel?> get() = localBabyData.current
 
     override val babyList: Flow<List<BabyModel>> get() = localBabyData.list
-
-    override suspend fun initState() {
+    override suspend fun getBaby() {
         remoteBabyData.getBabyList().apply {
             when (this) {
                 is DataState.Failure -> {
@@ -36,4 +32,12 @@ class BabyRepositoryImpl @Inject constructor(
             }
         }
     }
+
+    override suspend fun deleteBaby() {
+        TODO("Not yet implemented")
+    }
+
+    override suspend fun deleteAllBaby() {
+        TODO("Not yet implemented")
+    }
 }

+ 28 - 7
data/repo/src/main/kotlin/com/zaojiao/app/data/repo/impl/LoginRepositoryImpl.kt

@@ -1,32 +1,53 @@
 package com.zaojiao.app.data.repo.impl
 
-import com.zaojiao.app.core.common.data.BaseRepository
 import com.zaojiao.app.core.common.remote.di.ApplicationScope
+import com.zaojiao.app.core.common.state.DataState
+import com.zaojiao.app.data.model.TokenModel
+import com.zaojiao.app.data.remote.RemoteLoginData
 import com.zaojiao.app.data.repo.LoginRepository
 import com.zaojiao.app.data.repo.LoginState
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.flow
+import kotlinx.coroutines.launch
 import javax.inject.Inject
 import javax.inject.Singleton
 
 @Singleton
 class LoginRepositoryImpl @Inject constructor(
+    private val remoteLoginData: RemoteLoginData,
     @ApplicationScope private val coroutineScope: CoroutineScope,
-    override val state: Flow<LoginState>
-) : BaseRepository(coroutineScope), LoginRepository {
+) : LoginRepository {
+
+    override val state: Flow<LoginState> = flow {
+        emit(LoginState.IN)
+    }
+
     override fun loginBySms(phone: String, code: String) {
-        TODO("Not yet implemented")
+        coroutineScope.launch {
+            processTokenData(remoteLoginData.loginBySms(phone, code))
+        }
     }
 
     override fun loginByWechat(code: String) {
-        TODO("Not yet implemented")
+        coroutineScope.launch {
+            processTokenData(remoteLoginData.loginByWechat(code))
+        }
     }
 
     override fun loginByOneClick(code: String) {
-        TODO("Not yet implemented")
+        coroutineScope.launch {
+            processTokenData(remoteLoginData.loginByOneClick(code))
+        }
+    }
+
+    private suspend fun processTokenData(state: DataState<TokenModel?>) {
+
     }
 
     override fun logout() {
-        TODO("Not yet implemented")
+        coroutineScope.launch {
+
+        }
     }
 }

+ 0 - 21
data/repo/src/main/kotlin/com/zaojiao/app/data/repo/impl/TokenRepositoryImpl.kt

@@ -1,21 +0,0 @@
-package com.zaojiao.app.data.repo.impl
-
-import com.zaojiao.app.core.common.data.BaseRepository
-import com.zaojiao.app.core.common.remote.di.ApplicationScope
-import com.zaojiao.app.data.repo.TokenRepository
-import kotlinx.coroutines.CoroutineScope
-import javax.inject.Inject
-import javax.inject.Singleton
-
-@Singleton
-class TokenRepositoryImpl @Inject constructor(
-    @ApplicationScope private val coroutineScope: CoroutineScope,
-) : BaseRepository(coroutineScope), TokenRepository {
-    override fun saveToken() {
-        TODO("Not yet implemented")
-    }
-
-    override fun deleteToken() {
-        TODO("Not yet implemented")
-    }
-}

+ 6 - 16
data/repo/src/main/kotlin/com/zaojiao/app/data/repo/impl/UserRepositoryImpl.kt

@@ -1,19 +1,13 @@
 package com.zaojiao.app.data.repo.impl
 
-import android.util.Log
-import com.zaojiao.app.core.common.data.BaseRepository
 import com.zaojiao.app.core.common.remote.di.ApplicationScope
 import com.zaojiao.app.data.local.user.LocalUserData
 import com.zaojiao.app.data.model.UserModel
 import com.zaojiao.app.data.remote.RemoteUserData
 import com.zaojiao.app.data.repo.UserRepository
 import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.SupervisorJob
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.MutableStateFlow
-import kotlinx.coroutines.flow.map
-import kotlinx.coroutines.launch
 import javax.inject.Inject
 
 
@@ -21,7 +15,7 @@ class UserRepositoryImpl @Inject constructor(
     private val localUserData: LocalUserData,
     private val remoteUserData: RemoteUserData,
     @ApplicationScope private val coroutineScope: CoroutineScope,
-) : BaseRepository(coroutineScope), UserRepository {
+) : UserRepository {
     override val user: Flow<UserModel?> get() = localUserData.user
 
     private val _fansCount = MutableStateFlow(0)
@@ -36,7 +30,7 @@ class UserRepositoryImpl @Inject constructor(
     private val _wechatState = MutableStateFlow(false)
     override val wechatState: Flow<Boolean> get() = _wechatState
 
-    override suspend fun initState() {
+    override suspend fun getUser() {
         remoteUserData.getUser()?.apply {
             localUserData.updateUser(this.userModel)
 
@@ -45,16 +39,12 @@ class UserRepositoryImpl @Inject constructor(
         }
     }
 
-    suspend fun getUser(){
-        remoteUserData.getUser()?.apply {
-            localUserData.updateUser(this.userModel)
-
-            _fansCount.emit(this.fansCount)
-            _followerCount.emit(this.followCount)
-        }
+    override suspend fun updateUser(userModel: UserModel) {
+        TODO("Not yet implemented")
     }
 
-    suspend fun deleteUser(){
+
+    override suspend fun deleteUser() {
 
     }
 }

+ 71 - 34
feat/home/src/main/kotlin/com/zaojiao/app/feat/home/index/HomeIndexTopBar.kt

@@ -27,6 +27,7 @@ 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.TextAlign
 import androidx.compose.ui.text.style.TextOverflow
 import androidx.compose.ui.unit.dp
 import androidx.compose.ui.unit.sp
@@ -48,7 +49,7 @@ fun HomeIndexTopBar(
             .height(44.dp),
         verticalAlignment = Alignment.CenterVertically,
     ) {
-        HomeIndexTopBarUserInfo(
+        HomeIndexTopBarBabyInfo(
             babyUiState = babyUiState,
         )
         HomeIndexTopBarSearchBar()
@@ -57,7 +58,7 @@ fun HomeIndexTopBar(
 }
 
 @Composable
-fun HomeIndexTopBarUserInfo(
+fun HomeIndexTopBarBabyInfo(
     babyUiState: HomeIndexBabyUiState,
 ) {
     Row(
@@ -71,39 +72,75 @@ fun HomeIndexTopBarUserInfo(
             .wrapContentWidth(),
         verticalAlignment = Alignment.CenterVertically,
     ) {
-        Images.Network(
-            url = babyUiState.avatar,
-            modifier = Modifier
-                .clip(shape = RoundedCornerShape(50))
-                .size(44.dp),
-            contentScale = ContentScale.Crop,
-        )
-        Box(modifier = Modifier.width(4.dp))
-        Column {
-            Text(
-                text = babyUiState.name,
-                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 = babyUiState.age,
-                maxLines = 1,
-                style = TextStyle(
-                    color = Color(0x990B57C7),
-                    fontSize = 11.sp,
-                    lineHeight = 16.sp,
-                    fontWeight = FontWeight.Medium,
-                ),
-            )
+        when (babyUiState) {
+            HomeIndexBabyUiState.None -> {
+                Text(
+                    text = "立即登录",
+                    modifier = Modifier
+                        .width(93.dp)
+                        .fillMaxHeight(),
+                    style = TextStyle(
+                        color = Color(0xFF0B57C7),
+                        fontSize = 13.sp,
+                        lineHeight = 18.sp,
+                        fontWeight = FontWeight.Medium,
+                        textAlign = TextAlign.Center,
+                    ),
+                )
+            }
+
+            HomeIndexBabyUiState.Add -> {
+                Text(
+                    text = "立即登录",
+                    modifier = Modifier
+                        .weight(1f)
+                        .fillMaxHeight(),
+                    style = TextStyle(
+                        color = Color(0xFF0B57C7),
+                        fontSize = 13.sp,
+                        lineHeight = 18.sp,
+                        fontWeight = FontWeight.Medium,
+                        textAlign = TextAlign.Center,
+                    ),
+                )
+            }
+
+            else -> {
+                Images.Network(
+                    url = babyUiState.avatar,
+                    modifier = Modifier
+                        .clip(shape = RoundedCornerShape(50))
+                        .size(44.dp),
+                    contentScale = ContentScale.Crop,
+                )
+                Box(modifier = Modifier.width(4.dp))
+                Column {
+                    Text(
+                        text = babyUiState.name,
+                        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 = babyUiState.age,
+                        maxLines = 1,
+                        style = TextStyle(
+                            color = Color(0x990B57C7),
+                            fontSize = 11.sp,
+                            lineHeight = 16.sp,
+                            fontWeight = FontWeight.Medium,
+                        ),
+                    )
+                }
+                Box(modifier = Modifier.width(12.dp))
+            }
         }
-        Box(modifier = Modifier.width(12.dp))
     }
 }
 

+ 38 - 15
feat/home/src/main/kotlin/com/zaojiao/app/feat/home/index/HomeIndexViewModel.kt

@@ -3,34 +3,57 @@ package com.zaojiao.app.feat.home.index
 import androidx.lifecycle.ViewModel
 import androidx.lifecycle.viewModelScope
 import com.zaojiao.app.data.repo.BabyRepository
-import com.zaojiao.app.data.repo.UserRepository
+import com.zaojiao.app.data.repo.LoginRepository
 import com.zaojiao.app.feat.home.index.state.HomeIndexBabyUiState
 import dagger.hilt.android.lifecycle.HiltViewModel
 import kotlinx.coroutines.flow.SharingStarted
 import kotlinx.coroutines.flow.StateFlow
-import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.combine
 import kotlinx.coroutines.flow.stateIn
 import javax.inject.Inject
 
 @HiltViewModel
 class HomeIndexViewModel @Inject constructor(
-//    private val userRepository: UserRepository,
+    private val loginRepository: LoginRepository,
     private val babyRepository: BabyRepository,
 ) : ViewModel() {
-    val babyUiState: StateFlow<HomeIndexBabyUiState> = babyRepository.current
-        .map {
-            HomeIndexBabyUiState(
-                name = it?.name ?: "逻辑狗",
-                avatar = it?.img,
-                age = it?.age?.substringBefore("-") ?: "",
-            )
+    val babyUiState: StateFlow<HomeIndexBabyUiState> =
+        loginRepository.state.combine(babyRepository.current) { login, baby ->
+//            when (login) {
+//                LoginState.IN -> {
+//                    babyRepository.getBaby()
+//
+//                    if (baby != null) {
+//                        HomeIndexBabyUiState(
+//                            name = baby.name,
+//                            avatar = baby.img,
+//                            age = baby.age.substringBefore("-"),
+//                        )
+//                    } else {
+//                        HomeIndexBabyUiState.Add
+//                    }
+//                }
+//
+//                LoginState.OUT -> {
+//                    HomeIndexBabyUiState.None
+//                }
+//            }
+
+            babyRepository.getBaby()
+
+            if (baby != null) {
+                HomeIndexBabyUiState(
+                    name = baby.name,
+                    avatar = baby.img,
+                    age = baby.age.substringBefore("-"),
+                )
+            } else {
+                HomeIndexBabyUiState.Add
+            }
+
         }.stateIn(
             scope = viewModelScope,
             started = SharingStarted.WhileSubscribed(5_000),
-            initialValue = HomeIndexBabyUiState(
-                name = "逻辑狗",
-                avatar = null,
-                age = "",
-            )
+            initialValue = HomeIndexBabyUiState.None,
         )
 }

+ 15 - 1
feat/home/src/main/kotlin/com/zaojiao/app/feat/home/index/state/HomeIndexUserUiState.kt

@@ -4,4 +4,18 @@ data class HomeIndexBabyUiState(
     val name: String,
     val avatar: String?,
     val age: String,
-)
+) {
+    companion object {
+        val None = HomeIndexBabyUiState(
+            name = "",
+            avatar = null,
+            age = "0",
+        )
+
+        val Add = HomeIndexBabyUiState(
+            name = "",
+            avatar = null,
+            age = "0",
+        )
+    }
+}

+ 8 - 0
feat/home/src/main/kotlin/com/zaojiao/app/feat/home/personal/HomePersonalViewModel.kt

@@ -8,12 +8,20 @@ import kotlinx.coroutines.flow.SharingStarted
 import kotlinx.coroutines.flow.StateFlow
 import kotlinx.coroutines.flow.map
 import kotlinx.coroutines.flow.stateIn
+import kotlinx.coroutines.launch
 import javax.inject.Inject
 
 @HiltViewModel
 class HomePersonalViewModel @Inject constructor(
     private val userRepository: UserRepository
 ) : ViewModel() {
+
+    init {
+        viewModelScope.launch {
+            userRepository.getUser()
+        }
+    }
+
     val userUiState: StateFlow<HomePersonalUserUiState> = userRepository.user
         .map {
             HomePersonalUserUiState(

+ 1 - 0
settings.gradle.kts

@@ -31,3 +31,4 @@ include(":data:repo")
 include(":feat:design")
 include(":feat:home")
 include(":data:domain")
+include(":core:auth")