Kaynağa Gözat

feat: add livescope checker internet connection

Bax 19 saat önce
ebeveyn
işleme
d6c7e0d8e1
15 değiştirilmiş dosya ile 282 ekleme ve 33 silme
  1. 1 0
      mobile_app/Wabi/app/src/main/AndroidManifest.xml
  2. 3 0
      mobile_app/Wabi/app/src/main/java/com/example/wabi/domain/repository/UserShareDate.kt
  3. 6 4
      mobile_app/Wabi/app/src/main/java/com/example/wabi/domain/supabase/SupabaseService.kt
  4. 16 2
      mobile_app/Wabi/app/src/main/java/com/example/wabi/domain/supabase/SupabaseServiceImpl.kt
  5. 7 0
      mobile_app/Wabi/app/src/main/java/com/example/wabi/domain/system/ConnectivityObserver.kt
  6. 66 0
      mobile_app/Wabi/app/src/main/java/com/example/wabi/domain/system/NetworkConnectivityObserver.kt
  7. 12 0
      mobile_app/Wabi/app/src/main/java/com/example/wabi/models/screens/SignUpUser.kt
  8. 41 6
      mobile_app/Wabi/app/src/main/java/com/example/wabi/view/MainActivity.kt
  9. 5 0
      mobile_app/Wabi/app/src/main/java/com/example/wabi/view/MainActivityViewModel.kt
  10. 32 0
      mobile_app/Wabi/app/src/main/java/com/example/wabi/view/components/images/StandartProfileImage.kt
  11. 6 0
      mobile_app/Wabi/app/src/main/java/com/example/wabi/view/screeens/connection/ConncetionDestinations.kt
  12. 24 0
      mobile_app/Wabi/app/src/main/java/com/example/wabi/view/screeens/connection/NoInternet.kt
  13. 42 20
      mobile_app/Wabi/app/src/main/java/com/example/wabi/view/screeens/logIn/LogInViewModel.kt
  14. 20 0
      mobile_app/Wabi/app/src/main/java/com/example/wabi/view/screeens/logIn/items/signUpItems/CreatePofile.kt
  15. 1 1
      mobile_app/Wabi/app/src/main/java/com/example/wabi/view/screeens/logIn/items/signUpItems/EmailAndPassword.kt

+ 1 - 0
mobile_app/Wabi/app/src/main/AndroidManifest.xml

@@ -2,6 +2,7 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:tools="http://schemas.android.com/tools">
 
+    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
     <uses-permission android:name="android.permission.INTERNET" />
 
     <application

+ 3 - 0
mobile_app/Wabi/app/src/main/java/com/example/wabi/domain/repository/UserShareDate.kt

@@ -5,10 +5,13 @@ import android.content.Context
 import androidx.compose.runtime.MutableState
 import androidx.compose.runtime.mutableStateOf
 import com.example.wabi.domain.navigation.Routes
+import com.example.wabi.view.screeens.connection.ConncetionDestinations
 
 @SuppressLint("StaticFieldLeak")
 object UserShareDate {
     var context: Context? = null
     var currentRoute: String = Routes.BASKET
     val userIsLogging: MutableState<Boolean> = mutableStateOf(false)
+    val connectionInternet: MutableState<Boolean> =
+        mutableStateOf(ConncetionDestinations.internetConnection)
 }

+ 6 - 4
mobile_app/Wabi/app/src/main/java/com/example/wabi/domain/supabase/SupabaseService.kt

@@ -1,15 +1,17 @@
 package com.example.wabi.domain.supabase
 
-import com.example.wabi.models.supabase.Basket
-import com.example.wabi.models.supabase.User
 import com.example.wabi.models.responses.Response
+import com.example.wabi.models.screens.SignUpUser
+import com.example.wabi.models.supabase.Basket
 
 interface SupabaseService {
     suspend fun signIn(userEmail: String, userPasword: String): Response
     suspend fun signOut(): Response
     suspend fun signUp(userEmail: String, userPasword: String): Response
-    suspend fun addUser(user: User): Response
+    suspend fun addUser(user: SignUpUser): Response
     suspend fun emailIsExists(userEmail: String): Boolean
-    suspend fun resetPasswordForEmail(userEmail: String):Response
+    suspend fun uploadImageToStorage(where: String, name: String, image: ByteArray): Response
+
+    suspend fun resetPasswordForEmail(userEmail: String): Response
     suspend fun getBasket(): List<Basket>
 }

+ 16 - 2
mobile_app/Wabi/app/src/main/java/com/example/wabi/domain/supabase/SupabaseServiceImpl.kt

@@ -2,14 +2,15 @@ package com.example.wabi.domain.supabase
 
 import android.util.Log
 import com.example.wabi.models.responses.Response
+import com.example.wabi.models.screens.SignUpUser
 import com.example.wabi.models.supabase.Basket
-import com.example.wabi.models.supabase.User
 import io.github.jan.supabase.SupabaseClient
 import io.github.jan.supabase.gotrue.auth
 import io.github.jan.supabase.gotrue.providers.builtin.Email
 import io.github.jan.supabase.postgrest.from
 import io.github.jan.supabase.postgrest.query.Columns
 import io.github.jan.supabase.postgrest.query.Count
+import io.github.jan.supabase.storage.storage
 import javax.inject.Inject
 
 
@@ -54,7 +55,7 @@ class SupabaseServiceImpl @Inject constructor(private val supabase: SupabaseClie
         }
     }
 
-    override suspend fun addUser(user: User): Response {
+    override suspend fun addUser(user: SignUpUser): Response {
         TODO("Not yet implemented")
     }
 
@@ -71,6 +72,19 @@ class SupabaseServiceImpl @Inject constructor(private val supabase: SupabaseClie
         return count == 1.toLong()
     }
 
+    override suspend fun uploadImageToStorage(
+        where: String, name: String, image: ByteArray
+    ): Response {
+        return try {
+            var response = supabase.storage.from(where).upload(name, image, upsert = false)
+            Log.d("storage", "Image $name was uploaded to $where")
+            Response(response.toString())
+        } catch (ex: Exception) {
+            Log.e("storage", ex.message.toString())
+            Response("", ex.message.toString())
+        }
+    }
+
     override suspend fun resetPasswordForEmail(userEmail: String): Response {
         return try {
             val response = supabase.auth.resetPasswordForEmail(email = userEmail)

+ 7 - 0
mobile_app/Wabi/app/src/main/java/com/example/wabi/domain/system/ConnectivityObserver.kt

@@ -0,0 +1,7 @@
+package com.example.wabi.domain.system
+
+import kotlinx.coroutines.flow.Flow
+
+interface ConnectivityObserver {
+    fun observe(): Flow<Boolean>
+}

+ 66 - 0
mobile_app/Wabi/app/src/main/java/com/example/wabi/domain/system/NetworkConnectivityObserver.kt

@@ -0,0 +1,66 @@
+package com.example.wabi.domain.system
+
+import android.content.Context
+import android.net.ConnectivityManager
+import android.net.Network
+import com.example.wabi.view.screeens.connection.ConncetionDestinations
+import kotlinx.coroutines.channels.awaitClose
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.callbackFlow
+import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.launch
+
+class NetworkConnectivityObserver(
+    private val context: Context
+) : ConnectivityObserver {
+
+    private val connectivityManager =
+        context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
+
+    override fun observe(): Flow<Boolean> {
+        return callbackFlow {
+            val callback = object : ConnectivityManager.NetworkCallback() {
+                override fun onAvailable(network: Network) {
+                    super.onAvailable(network)
+                    launch {
+                        send(
+                            ConncetionDestinations.internetConnection
+                        )
+                    }
+                }
+
+                override fun onLosing(network: Network, maxMsToLive: Int) {
+                    super.onLosing(network, maxMsToLive)
+                    launch {
+                        send(
+                            ConncetionDestinations.internetConnection
+                        )
+                    }
+                }
+
+                override fun onLost(network: Network) {
+                    super.onLost(network)
+                    launch {
+                        send(
+                            ConncetionDestinations.noInternetConncetion
+                        )
+                    }
+                }
+
+                override fun onUnavailable() {
+                    super.onUnavailable()
+                    launch {
+                        send(
+                            ConncetionDestinations.noInternetConncetion
+                        )
+                    }
+                }
+            }
+
+            connectivityManager.registerDefaultNetworkCallback(callback)
+            awaitClose {
+                connectivityManager.unregisterNetworkCallback(callback)
+            }
+        }.distinctUntilChanged()
+    }
+}

+ 12 - 0
mobile_app/Wabi/app/src/main/java/com/example/wabi/models/screens/SignUpUser.kt

@@ -0,0 +1,12 @@
+package com.example.wabi.models.screens
+
+import kotlinx.serialization.SerialName
+
+data class SignUpUser(
+    val id: String = "",
+    val nickname: String = "",
+    val image: String? = "",
+    @SerialName("basket_code") val basketCode: String? = "",
+    val theme: Int = 0,
+    val email: String = ""
+)

+ 41 - 6
mobile_app/Wabi/app/src/main/java/com/example/wabi/view/MainActivity.kt

@@ -1,6 +1,7 @@
 package com.example.wabi.view
 
 import android.os.Bundle
+import android.util.Log
 import androidx.activity.ComponentActivity
 import androidx.activity.compose.setContent
 import androidx.activity.enableEdgeToEdge
@@ -10,27 +11,46 @@ import androidx.compose.foundation.layout.padding
 import androidx.compose.material3.Scaffold
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.MutableState
+import androidx.compose.runtime.collectAsState
+import androidx.compose.runtime.getValue
 import androidx.compose.runtime.mutableStateOf
 import androidx.compose.runtime.remember
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.platform.LocalContext
 import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
 import androidx.hilt.navigation.compose.hiltViewModel
+import androidx.lifecycle.lifecycleScope
 import androidx.navigation.NavHostController
 import androidx.navigation.compose.rememberNavController
 import com.example.wabi.domain.navigation.Navigation
 import com.example.wabi.domain.navigation.Routes
 import com.example.wabi.domain.repository.PrefManager
 import com.example.wabi.domain.repository.UserShareDate
+import com.example.wabi.domain.system.ConnectivityObserver
+import com.example.wabi.domain.system.NetworkConnectivityObserver
 import com.example.wabi.ui.theme.WabiTheme
 import com.example.wabi.view.components.bars.bottom.BottomBar
+import com.example.wabi.view.screeens.connection.ConncetionDestinations
+import com.example.wabi.view.screeens.connection.NoInternet
 import dagger.hilt.android.AndroidEntryPoint
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.onEach
 
 @AndroidEntryPoint
 class MainActivity : ComponentActivity() {
+
+    private lateinit var connectivityObserver: ConnectivityObserver
+
     override fun onCreate(savedInstanceState: Bundle?) {
         super.onCreate(savedInstanceState)
+
+        connectivityObserver = NetworkConnectivityObserver(applicationContext)
+        connectivityObserver.observe().onEach {
+            Log.d("connection status", "status is $it")
+        }.launchIn(lifecycleScope)
+
         installSplashScreen()
+
         enableEdgeToEdge()
 
         setContent {
@@ -43,6 +63,10 @@ class MainActivity : ComponentActivity() {
 
             WabiTheme(themeState = PrefManager.userTheme) {
 
+                val connectionStatus by connectivityObserver.observe().collectAsState(
+                    initial = ConncetionDestinations.internetConnection
+                )
+
                 Scaffold(modifier = Modifier.fillMaxSize(),
                     containerColor = WabiTheme.colors.backgroundColor,
                     bottomBar = {
@@ -53,12 +77,23 @@ class MainActivity : ComponentActivity() {
                         }
                     },
                     topBar = {}) { innerPadding ->
-                    Box(
-                        modifier = Modifier
-                            .fillMaxSize()
-                            .padding(innerPadding)
-                    ) {
-                        InitApp(navHostController, isBottomBar)
+
+                    if (connectionStatus) {
+                        Box(
+                            modifier = Modifier
+                                .fillMaxSize()
+                                .padding(innerPadding)
+                        ) {
+                            InitApp(navHostController, isBottomBar)
+                        }
+                    } else {
+                        Box(
+                            modifier = Modifier
+                                .fillMaxSize()
+                                .padding(innerPadding)
+                        ) {
+                            NoInternet()
+                        }
                     }
                 }
             }

+ 5 - 0
mobile_app/Wabi/app/src/main/java/com/example/wabi/view/MainActivityViewModel.kt

@@ -1,5 +1,6 @@
 package com.example.wabi.view
 
+import android.content.Context
 import androidx.lifecycle.ViewModel
 import androidx.lifecycle.viewModelScope
 import com.example.wabi.domain.repository.PrefManager
@@ -9,6 +10,7 @@ import dagger.hilt.android.lifecycle.HiltViewModel
 import kotlinx.coroutines.launch
 import javax.inject.Inject
 
+
 @HiltViewModel
 class MainActivityViewModel @Inject constructor(private val supabase: SupabaseServiceImpl) :
     ViewModel() {
@@ -25,6 +27,9 @@ class MainActivityViewModel @Inject constructor(private val supabase: SupabaseSe
                 }
             }
         }
+    }
+
+    fun checkInternetConection() {
 
     }
 }

+ 32 - 0
mobile_app/Wabi/app/src/main/java/com/example/wabi/view/components/images/StandartProfileImage.kt

@@ -0,0 +1,32 @@
+package com.example.wabi.view.components.images
+
+import androidx.compose.foundation.Image
+import androidx.compose.foundation.background
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.ColorFilter
+import androidx.compose.ui.graphics.vector.ImageVector
+import androidx.compose.ui.res.vectorResource
+import androidx.compose.ui.unit.dp
+import com.example.wabi.R
+import com.example.wabi.ui.theme.WabiTheme
+
+@Composable
+fun StandartProfileImage(modifier: Modifier = Modifier) {
+    Box(
+        modifier = modifier.background(
+            WabiTheme.colors.singleColor, shape = RoundedCornerShape(30.dp)
+        ), contentAlignment = Alignment.Center
+    ) {
+        Image(
+            imageVector = ImageVector.vectorResource(R.drawable.man_vector),
+            contentDescription = "standartProfileImage",
+            colorFilter = ColorFilter.tint(WabiTheme.colors.onBoardLight),
+            modifier = Modifier.padding(20.dp)
+        )
+    }
+}

+ 6 - 0
mobile_app/Wabi/app/src/main/java/com/example/wabi/view/screeens/connection/ConncetionDestinations.kt

@@ -0,0 +1,6 @@
+package com.example.wabi.view.screeens.connection
+
+object ConncetionDestinations {
+    const val internetConnection = true
+    const val noInternetConncetion = false
+}

+ 24 - 0
mobile_app/Wabi/app/src/main/java/com/example/wabi/view/screeens/connection/NoInternet.kt

@@ -0,0 +1,24 @@
+package com.example.wabi.view.screeens.connection
+
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import com.example.wabi.view.components.texts.MainText
+
+@Composable
+fun NoInternet(modifier: Modifier = Modifier) {
+    Column(
+        modifier = Modifier.fillMaxSize(),
+        horizontalAlignment = Alignment.CenterHorizontally,
+        verticalArrangement = Arrangement.Center
+    ) {
+        MainText(
+            text = "Нет доступаn\nк интернету!",
+            maxLines = 2,
+            minLines = 2
+        )
+    }
+}

+ 42 - 20
mobile_app/Wabi/app/src/main/java/com/example/wabi/view/screeens/logIn/LogInViewModel.kt

@@ -1,11 +1,15 @@
 package com.example.wabi.view.screeens.logIn
 
+import android.content.Context
+import android.graphics.Bitmap
+import android.graphics.BitmapFactory
 import android.util.Log
 import androidx.compose.runtime.MutableState
 import androidx.compose.runtime.mutableStateOf
 import androidx.lifecycle.ViewModel
 import androidx.lifecycle.viewModelScope
 import androidx.navigation.NavHostController
+import com.example.wabi.R
 import com.example.wabi.domain.navigation.NavigationProvider
 import com.example.wabi.domain.navigation.Routes
 import com.example.wabi.domain.repository.PrefManager
@@ -13,11 +17,13 @@ import com.example.wabi.domain.repository.UserShareDate
 import com.example.wabi.domain.supabase.SupabaseServiceImpl
 import com.example.wabi.models.screens.SignInState
 import com.example.wabi.models.screens.SignUpState
+import com.example.wabi.models.screens.SignUpUser
 import com.example.wabi.view.screeens.logIn.items.signUpItems.SignUpStateDestination
 import dagger.hilt.android.lifecycle.HiltViewModel
 import kotlinx.coroutines.flow.MutableStateFlow
 import kotlinx.coroutines.flow.asStateFlow
 import kotlinx.coroutines.launch
+import java.io.ByteArrayOutputStream
 import javax.inject.Inject
 
 @HiltViewModel
@@ -31,6 +37,9 @@ class LogInViewModel @Inject constructor(
     private val _signUpData = mutableStateOf(SignUpState())
     val signUpData: SignUpState get() = _signUpData.value
 
+    private val _signUpUser = mutableStateOf(SignUpUser())
+    val signUpUser: SignUpUser get() = _signUpUser.value
+
     private var _emailExists = MutableStateFlow<Boolean>(false)
     val emailExists = _emailExists.asStateFlow()
 
@@ -42,6 +51,10 @@ class LogInViewModel @Inject constructor(
         _signUpData.value = newData
     }
 
+    fun updateUserDataSignUp(newData: SignUpUser) {
+        _signUpUser.value = newData
+    }
+
     fun signIn(navController: NavHostController, printError: MutableState<Boolean>) {
         if (_signInData.value.email != "" && _signInData.value.password != "") {
             viewModelScope.launch {
@@ -79,8 +92,27 @@ class LogInViewModel @Inject constructor(
     }
 
     fun signUp(
-        printError: MutableState<Int>, stationChanger: MutableState<Int>
     ) {
+        viewModelScope.launch {
+            val response = supabase.signUp(
+                userEmail = _signUpData.value.email, userPasword = _signUpData.value.passwordOne
+            )
+
+            if (response.error == "") {
+
+                UserShareDate.userIsLogging.value = true
+                PrefManager.initPrefManager(UserShareDate.context!!)
+                PrefManager.saveDataCurrentUser(
+                    _signInData.value.email, _signInData.value.password
+                )
+
+            } else {
+                Log.d("signUn", "Error registration!")
+            }
+        }
+    }
+
+    fun switchSignUpStation(printError: MutableState<Int>, stationChanger: MutableState<Int>) {
         if (_signUpData.value.email != "" && _signUpData.value.passwordOne != "" && _signUpData.value.passwordTwo != "") {
             if (checkCorrectPassword(_signUpData.value.passwordOne) && checkCorrectPassword(
                     _signUpData.value.passwordTwo
@@ -92,25 +124,9 @@ class LogInViewModel @Inject constructor(
                         if (!checkEmail) {
                             printError.value = 0
 
-                            val response = supabase.signUp(
-                                userEmail = _signUpData.value.email,
-                                userPasword = _signUpData.value.passwordOne
-                            )
-
-                            if (response.error == "") {
-
-                                //UserShareDate.userIsLogging.value = true
-                                PrefManager.initPrefManager(UserShareDate.context!!)
-                                PrefManager.saveDataCurrentUser(
-                                    _signInData.value.email, _signInData.value.password
-                                )
+                            stationChanger.value = SignUpStateDestination.createProfile
 
-                                stationChanger.value = SignUpStateDestination.createProfile
-
-                                Log.d("signUn", "go to created profile")
-                            } else {
-                                Log.d("signUn", "Error registration!")
-                            }
+                            Log.d("signUn", "go to created profile")
                         } else {
                             printError.value = 1
                         }
@@ -126,11 +142,17 @@ class LogInViewModel @Inject constructor(
         }
     }
 
-
     private fun checkCorrectPassword(password: String): Boolean {
         return password.length > 5
     }
 
+    private fun converterBitMapToByteArray(context: Context): ByteArray {
+        val bitmap = BitmapFactory.decodeResource(context.resources, R.drawable.man_vector)
+        val byteArrayInputStream = ByteArrayOutputStream()
+        bitmap.compress(Bitmap.CompressFormat.PNG, 100, byteArrayInputStream)
+        return byteArrayInputStream.toByteArray()
+    }
+
     fun sendEmailForResetPassword(email: String): Boolean {
         var result = false
         viewModelScope.launch {

+ 20 - 0
mobile_app/Wabi/app/src/main/java/com/example/wabi/view/screeens/logIn/items/signUpItems/CreatePofile.kt

@@ -1,7 +1,14 @@
 package com.example.wabi.view.screeens.logIn.items.signUpItems
 
+import androidx.compose.foundation.layout.padding
 import androidx.compose.runtime.Composable
+import androidx.compose.runtime.MutableState
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
 import androidx.compose.ui.Modifier
+import androidx.compose.ui.unit.dp
+import com.example.wabi.view.components.buttons.MainButton
+import com.example.wabi.view.components.images.StandartProfileImage
 import com.example.wabi.view.components.texts.HeaderText
 import com.example.wabi.view.components.texts.MainText
 import com.example.wabi.view.screeens.logIn.LogInViewModel
@@ -12,10 +19,23 @@ fun CreatePofile(
     modifier: Modifier = Modifier,
     vm: LogInViewModel,
 ) {
+    val user = vm.signUpUser
+    val image: MutableState<ByteArray?> = remember { mutableStateOf(byteArrayOf()) }
+
     HeaderText(text = station.header)
 
     MainText(
         text = station.description
     )
 
+    StandartProfileImage()
+
+    MainButton(
+        onClick = {}, textContent = "Cвоё изображение", modifier = Modifier.padding(30.dp)
+    )
+
+    MainButton(
+        onClick = {}, textContent = station.buttonName, modifier = Modifier.padding(30.dp)
+    )
+
 }

+ 1 - 1
mobile_app/Wabi/app/src/main/java/com/example/wabi/view/screeens/logIn/items/signUpItems/EmailAndPassword.kt

@@ -74,7 +74,7 @@ fun EmailAndPassword(
 
     MainButton(
         onClick = {
-            vm.signUp(printError = errorState, stationChanger = stationChanger)
+            vm.switchSignUpStation(printError = errorState, stationChanger = stationChanger)
         }, enabled = data.passwordOne != "" && data.passwordTwo != "" && vm.validateEmail(
             data.email
         ), textContent = station.buttonName, modifier = Modifier.padding(30.dp, 0.dp)