Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ captures
!*.xcworkspace/contents.xcworkspacedata
**/xcshareddata/WorkspaceSettings.xcsettings

# Google Service
composeApp/google-service.json
**/google-service.json
google-service.json
# Google Services
#composeApp/google-services.json
#**/google-services.json
#google-services.json

# Project exclude paths
9 changes: 5 additions & 4 deletions composeApp/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ kotlin {
implementation(compose.components.uiToolingPreview)
implementation(libs.androidx.lifecycle.viewmodelCompose)
implementation(libs.androidx.lifecycle.runtimeCompose)

//adaptive
implementation(libs.adaptive)
implementation(libs.adaptive.layout)
Expand All @@ -90,24 +91,24 @@ kotlin {
implementation(libs.koin.compose.viewmodel.navigation)
api(libs.koin.annotations)

//ktor
implementation(libs.ktor.client.core)
implementation(libs.ktor.serialization.kotlinx.json)
implementation(libs.ktor.client.content.negotiation)
implementation(libs.ktor.client.logging)

implementation(libs.bundles.coil)

implementation(libs.kotlinx.datetime)

implementation(libs.androidx.datastore.preferences)

implementation(libs.calf.file.picker)

//navigation
implementation(libs.navigation.compose)
implementation(libs.kotlinx.serialization.json)

}
commonTest.dependencies {
implementation(libs.kotlin.test)

implementation(libs.kotlinx.coroutines.test)
implementation(libs.ktor.client.mock)
implementation(libs.koin.test)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<string name="error_bottom_sheet_content">الفريق يحاول حلها حاليا, جرب مرة اخرى.</string>
<string name="ok_text">حسناً</string>

<string name="welcome_title">مرحبًا بك في صنعة 👋</string>
<string name="welcome_title">مرحبًا بك في كرافتو 👋</string>
<string name="enter_phone">أدخل رقم هاتفك للمتابعة</string>
<string name="phone_hint">+٢٠ ٠٠٠ - ٠٠٠ - ٠٠٠٠</string>
<string name="terms_and_conditions">الشروط والأحكام</string>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
<string name="ok_text">Ok</string>

<!-- RegisterScreen -->
<string name="welcome_title">Welcome to San3a 👋</string>
<string name="welcome_title">Welcome to Crafto 👋</string>
<string name="enter_phone">Enter your phone number to\n continue</string>
<string name="phone_hint">+20 000 - 000 - 0000</string>
<string name="terms_and_conditions">Terms and Conditions</string>
Expand Down
18 changes: 13 additions & 5 deletions composeApp/src/commonMain/kotlin/org/example/project/App.kt
Original file line number Diff line number Diff line change
@@ -1,17 +1,25 @@
package org.example.project

import androidx.compose.foundation.background
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.navigationBarsPadding
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.navigation.compose.rememberNavController
import org.example.project.presentation.designsystem.textstyle.AppTheme
import org.example.project.presentation.screens.setup.craftsmansetup.CraftsmanSetupScreen
import org.example.project.presentation.screens.splash.SplashScreen
import org.example.project.presentation.navigation.CraftoNavGraph
import org.jetbrains.compose.ui.tooling.preview.Preview

@Composable
@Preview
fun App() {
AppTheme {
//OnboardingScreen()
SplashScreen { }
CraftsmanSetupScreen()
val navController = rememberNavController()
CraftoNavGraph(
navController = navController,
modifier = Modifier
.fillMaxSize()
.background(AppTheme.craftoColors.background.screen)
.navigationBarsPadding())
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,11 @@ import org.example.project.data.remote.network.ApiConstants.Endpoints.ONBOARDING
import org.example.project.data.remote.network.wrapApiCall
import org.example.project.domain.entity.OnboardingItem
import org.example.project.domain.repository.OnboardingRepository
import org.koin.core.annotation.Provided
import org.koin.core.annotation.Single


@Single(binds = [OnboardingRepository::class])

class OnboardingRepositoryImp(
@Provided private val httpClient: HttpClient
private val httpClient: HttpClient
) : OnboardingRepository {

override suspend fun getOnboardingData(): List<OnboardingItem> {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package org.example.project.data.repository

import org.example.project.data.local.datasource.StorageLocalDataSource
import org.example.project.domain.entity.UserType
import org.example.project.domain.repository.UserPreferences

class UserPreferencesImpl(
Expand All @@ -9,6 +10,8 @@ class UserPreferencesImpl(

companion object {
private const val KEY_USER_ID = "user_id"
private const val KEY_USER_TYPE = "user_type"
private const val KEY_IS_FIRST_TIME = "is_first_time"
}

override suspend fun getUserId(): String? {
Expand All @@ -22,4 +25,30 @@ class UserPreferencesImpl(
override suspend fun clearUserId() {
storage.remove(KEY_USER_ID)
}

override suspend fun getUserType(): UserType? {
return storage.getString(KEY_USER_TYPE)?.let {
try {
UserType.valueOf(it)
} catch (e: IllegalArgumentException) {
null
}
}
}

override suspend fun setUserType(userType: UserType) {
storage.saveString(KEY_USER_TYPE, userType.name)
}

override suspend fun clearUserType() {
storage.remove(KEY_USER_TYPE)
}

override suspend fun isFirstTime(): Boolean {
return storage.getBoolean(KEY_IS_FIRST_TIME) ?: true
}

override suspend fun setFirstTime(isFirstTime: Boolean) {
storage.saveBoolean(KEY_IS_FIRST_TIME, isFirstTime)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,12 @@ import org.example.project.data.remote.datasource.CraftsmanRemoteDataSourceImpl
import org.example.project.data.repository.CategoryRepositoryImpl
import org.example.project.data.repository.CraftsmanRepositoryImpl
import org.example.project.data.repository.LocationRepositoryImpl
import org.example.project.data.repository.OnboardingRepositoryImp
import org.example.project.data.service.ValidationServiceImpl
import org.example.project.domain.repository.CategoryRepository
import org.example.project.domain.repository.CraftsmanRepository
import org.example.project.domain.repository.LocationRepository
import org.example.project.domain.repository.OnboardingRepository
import org.example.project.domain.service.ValidationService
import org.koin.dsl.module

Expand All @@ -27,6 +29,9 @@ val dataModule = module {
userPreferences = get()
)
}
single<OnboardingRepository> {
OnboardingRepositoryImp(get())
}
single { categorySeed }
single<CategoryDataSource> { CategoryMemoryDataSource(get()) }
single<CategoryRepository> { CategoryRepositoryImpl(get()) }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ import org.example.project.domain.usecase.craftsman.GetCraftsmanStatusUseCase
import org.example.project.domain.usecase.craftsman.UploadIdCardsUseCase
import org.example.project.domain.usecase.craftsman.UploadProfilePictureUseCase
import org.example.project.domain.usecase.craftsman.UploadWorkPortfolioUseCase
import org.example.project.domain.usecase.session.ClearUserSessionUseCase
import org.example.project.domain.usecase.session.GetUserSessionUseCase
import org.example.project.domain.usecase.session.MarkOnboardingCompleteUseCase
import org.example.project.domain.usecase.session.SaveUserTypeUseCase
import org.koin.dsl.module

val domainModule = module {
Expand All @@ -19,4 +23,9 @@ val domainModule = module {
factory { DeleteCraftsmanAccountUseCase(get()) }
factory { GetCategoriesUseCase(get())}
factory { UploadProfilePictureUseCase(get(),get()) }

factory { GetUserSessionUseCase(get()) }
factory { SaveUserTypeUseCase(get()) }
factory { MarkOnboardingCompleteUseCase(get()) }
factory { ClearUserSessionUseCase(get()) }
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package org.example.project.di

import org.example.project.presentation.screens.auth.UserTypeSelectionViewModel
import org.example.project.presentation.screens.onboarding.OnboardingViewModel
import org.example.project.presentation.screens.setup.craftsmansetup.CraftsmanSetupViewModel
import org.example.project.presentation.screens.setup.location.LocationViewModel
import org.koin.core.module.dsl.viewModel
Expand All @@ -15,5 +17,7 @@ val presentationModule = module {
uploadProfilePictureUseCase = get(),
)
}
viewModel {LocationViewModel(get())}
viewModel { LocationViewModel(get()) }
viewModel { OnboardingViewModel(get(), get()) }
viewModel { UserTypeSelectionViewModel(get()) }
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ fun initKoin(config: KoinAppDeclaration? = null) {
startKoin {
config?.invoke(this)
modules(
//CraftoModule().module,
networkModule,
dataModule,
domainModule,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package org.example.project.domain.entity

data class UserSession(
val userId: String?,
val userType: UserType?,
val isFirstTime: Boolean
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package org.example.project.domain.entity

enum class UserType {
CUSTOMER,
CRAFTSMAN
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,18 @@
package org.example.project.domain.repository

import org.example.project.domain.entity.UserType

interface UserPreferences {
suspend fun getUserId(): String?
suspend fun setUserId(userId: String)
suspend fun clearUserId()

//TODO: Separate UserType to its own Repository
suspend fun getUserType(): UserType?
suspend fun setUserType(userType: UserType)
suspend fun clearUserType()

// Add these
suspend fun isFirstTime(): Boolean
suspend fun setFirstTime(isFirstTime: Boolean)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package org.example.project.domain.usecase.session

import org.example.project.domain.repository.UserPreferences

class ClearUserSessionUseCase(
private val userPreferences: UserPreferences
) {
suspend operator fun invoke() {
userPreferences.clearUserId()
userPreferences.clearUserType()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package org.example.project.domain.usecase.session

import org.example.project.domain.entity.UserSession
import org.example.project.domain.repository.UserPreferences

class GetUserSessionUseCase(
private val userPreferences: UserPreferences
) {
suspend operator fun invoke(): UserSession {
return UserSession(
userId = userPreferences.getUserId(),
userType = userPreferences.getUserType(),
isFirstTime = userPreferences.isFirstTime()
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package org.example.project.domain.usecase.session

import org.example.project.domain.repository.UserPreferences

class MarkOnboardingCompleteUseCase(
private val userPreferences: UserPreferences
) {
suspend operator fun invoke() {
userPreferences.setFirstTime(false)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package org.example.project.domain.usecase.session

import org.example.project.domain.entity.UserType
import org.example.project.domain.repository.UserPreferences

class SaveUserTypeUseCase(
private val userPreferences: UserPreferences
) {
suspend operator fun invoke(userType: UserType) {
userPreferences.setUserType(userType)
}
}
Loading