├── sc
├── frame2.png
├── frame3.png
└── frame4.png
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── iosApp
├── Podfile
├── iosApp
│ ├── Assets.xcassets
│ │ ├── Contents.json
│ │ ├── AppIcon.appiconset
│ │ │ ├── AppIcon~ios-marketing.png
│ │ │ └── Contents.json
│ │ └── AccentColor.colorset
│ │ │ └── Contents.json
│ ├── Preview Content
│ │ └── Preview Assets.xcassets
│ │ │ └── Contents.json
│ ├── iOSApp.swift
│ ├── ContentView.swift
│ ├── Info.plist
│ ├── poem
│ │ └── presentation
│ │ │ ├── components
│ │ │ └── ProgressButton.swift
│ │ │ ├── IOSPoemViewModel.swift
│ │ │ └── PoemScreen.swift
│ ├── like
│ │ └── presentation
│ │ │ ├── IOSLikeViewModel.swift
│ │ │ └── LikeScreen.swift
│ └── core
│ │ └── presentation
│ │ └── Colors.swift
├── Pods
│ ├── Target Support Files
│ │ ├── Pods-iosApp
│ │ │ ├── Pods-iosApp-frameworks-Debug-output-files.xcfilelist
│ │ │ ├── Pods-iosApp-frameworks-Release-output-files.xcfilelist
│ │ │ ├── Pods-iosApp.modulemap
│ │ │ ├── Pods-iosApp-dummy.m
│ │ │ ├── Pods-iosApp-acknowledgements.markdown
│ │ │ ├── Pods-iosApp-frameworks-Debug-input-files.xcfilelist
│ │ │ ├── Pods-iosApp-frameworks-Release-input-files.xcfilelist
│ │ │ ├── Pods-iosApp-umbrella.h
│ │ │ ├── Pods-iosApp.debug.xcconfig
│ │ │ ├── Pods-iosApp.release.xcconfig
│ │ │ ├── Pods-iosApp-acknowledgements.plist
│ │ │ ├── Pods-iosApp-Info.plist
│ │ │ └── Pods-iosApp-frameworks.sh
│ │ └── shared
│ │ │ ├── shared.debug.xcconfig
│ │ │ └── shared.release.xcconfig
│ ├── Manifest.lock
│ ├── Pods.xcodeproj
│ │ ├── xcuserdata
│ │ │ └── hamidrezasahraei.xcuserdatad
│ │ │ │ └── xcschemes
│ │ │ │ ├── xcschememanagement.plist
│ │ │ │ ├── shared.xcscheme
│ │ │ │ └── Pods-iosApp.xcscheme
│ │ └── project.pbxproj
│ └── Local Podspecs
│ │ └── shared.podspec.json
├── Podfile.lock
├── iosApp.xcworkspace
│ └── contents.xcworkspacedata
└── KorsiSher.xcodeproj
│ ├── xcuserdata
│ └── hamidrezasahraei.xcuserdatad
│ │ └── xcschemes
│ │ └── xcschememanagement.plist
│ └── project.pbxproj
├── androidApp
├── src
│ └── main
│ │ ├── res
│ │ ├── values
│ │ │ └── styles.xml
│ │ ├── mipmap-hdpi
│ │ │ ├── ic_launcher.png
│ │ │ ├── ic_launcher_background.png
│ │ │ ├── ic_launcher_foreground.png
│ │ │ └── ic_launcher_monochrome.png
│ │ ├── mipmap-mdpi
│ │ │ ├── ic_launcher.png
│ │ │ ├── ic_launcher_background.png
│ │ │ ├── ic_launcher_foreground.png
│ │ │ └── ic_launcher_monochrome.png
│ │ ├── mipmap-xhdpi
│ │ │ ├── ic_launcher.png
│ │ │ ├── ic_launcher_background.png
│ │ │ ├── ic_launcher_foreground.png
│ │ │ └── ic_launcher_monochrome.png
│ │ ├── mipmap-xxhdpi
│ │ │ ├── ic_launcher.png
│ │ │ ├── ic_launcher_background.png
│ │ │ ├── ic_launcher_foreground.png
│ │ │ └── ic_launcher_monochrome.png
│ │ ├── mipmap-xxxhdpi
│ │ │ ├── ic_launcher.png
│ │ │ ├── ic_launcher_background.png
│ │ │ ├── ic_launcher_foreground.png
│ │ │ └── ic_launcher_monochrome.png
│ │ └── mipmap-anydpi-v26
│ │ │ └── ic_launcher.xml
│ │ ├── java
│ │ └── korsi
│ │ │ └── sher
│ │ │ └── android
│ │ │ ├── core
│ │ │ └── presentation
│ │ │ │ ├── Routes.kt
│ │ │ │ └── components
│ │ │ │ ├── ProgressButton.kt
│ │ │ │ └── PoemComponent.kt
│ │ │ ├── KorsiSherApp.kt
│ │ │ ├── like
│ │ │ └── presentation
│ │ │ │ ├── AndroidLikeViewModel.kt
│ │ │ │ └── LikeScreen.kt
│ │ │ ├── poem
│ │ │ └── presentation
│ │ │ │ ├── AndroidPoemViewModel.kt
│ │ │ │ └── PoemScreen.kt
│ │ │ ├── MyApplicationTheme.kt
│ │ │ ├── di
│ │ │ └── AppModule.kt
│ │ │ └── MainActivity.kt
│ │ └── AndroidManifest.xml
└── build.gradle.kts
├── shared
├── src
│ ├── commonMain
│ │ ├── kotlin
│ │ │ └── korsi
│ │ │ │ └── sher
│ │ │ │ ├── Platform.kt
│ │ │ │ ├── poem
│ │ │ │ ├── data
│ │ │ │ │ ├── remote
│ │ │ │ │ │ └── HttpClientFactory.kt
│ │ │ │ │ ├── local
│ │ │ │ │ │ └── DatabaseDriverFactory.kt
│ │ │ │ │ ├── poem
│ │ │ │ │ │ ├── PoemDto.kt
│ │ │ │ │ │ └── KtorPoemClient.kt
│ │ │ │ │ ├── mapper
│ │ │ │ │ │ └── PoemItemMapper.kt
│ │ │ │ │ └── history
│ │ │ │ │ │ └── SqlDelightHistoryDataSource.kt
│ │ │ │ ├── domain
│ │ │ │ │ ├── poem
│ │ │ │ │ │ ├── PoemClient.kt
│ │ │ │ │ │ ├── PoemError.kt
│ │ │ │ │ │ └── PoemUseCase.kt
│ │ │ │ │ └── history
│ │ │ │ │ │ ├── PoemHistoryDataSource.kt
│ │ │ │ │ │ ├── PoemItem.kt
│ │ │ │ │ │ └── LikeUseCase.kt
│ │ │ │ └── presentation
│ │ │ │ │ ├── like
│ │ │ │ │ ├── LikeEvent.kt
│ │ │ │ │ ├── LikeState.kt
│ │ │ │ │ └── LikeViewModel.kt
│ │ │ │ │ ├── poem
│ │ │ │ │ ├── PoemEvent.kt
│ │ │ │ │ ├── PoemState.kt
│ │ │ │ │ └── PoemViewModel.kt
│ │ │ │ │ └── util
│ │ │ │ │ └── ColorUtil.kt
│ │ │ │ ├── Greeting.kt
│ │ │ │ └── core
│ │ │ │ ├── domain
│ │ │ │ └── util
│ │ │ │ │ ├── CommonFlow.kt
│ │ │ │ │ ├── CommonStateFlow.kt
│ │ │ │ │ ├── Resource.kt
│ │ │ │ │ └── CommonMutableStateFlow.kt
│ │ │ │ └── presentation
│ │ │ │ └── Colors.kt
│ │ └── sqldelight
│ │ │ └── database
│ │ │ └── poem.sq
│ ├── iosMain
│ │ └── kotlin
│ │ │ └── korsi
│ │ │ └── sher
│ │ │ ├── core.domain.util
│ │ │ ├── DisposableHandle.kt
│ │ │ ├── IOSMutableStateFlow.kt
│ │ │ ├── CommonStateFlow.kt
│ │ │ ├── CommonFlow.kt
│ │ │ └── CommonMutableStateFlow.kt
│ │ │ ├── Platform.kt
│ │ │ ├── poem.data
│ │ │ └── local
│ │ │ │ └── DatabaseDriverFactory.kt
│ │ │ ├── poem.data.remote
│ │ │ └── HttpClientFactory.kt
│ │ │ └── di
│ │ │ └── AppModule.kt
│ └── androidMain
│ │ └── kotlin
│ │ └── korsi
│ │ └── sher
│ │ ├── Platform.kt
│ │ ├── core
│ │ └── domain
│ │ │ └── util
│ │ │ ├── CommonFlow.kt
│ │ │ ├── CommonStateFlow.kt
│ │ │ └── CommonMutableStateFlow.kt
│ │ └── poem
│ │ └── data
│ │ ├── remote
│ │ └── HttpClientFactory.kt
│ │ └── local
│ │ └── DatabaseDriverFactory.kt
├── shared.podspec
└── build.gradle.kts
├── gradle.properties
├── settings.gradle.kts
├── .gitignore
├── gradlew.bat
├── Readme.md
└── gradlew
/sc/frame2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hamidrezasahraei/KorsiSher/HEAD/sc/frame2.png
--------------------------------------------------------------------------------
/sc/frame3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hamidrezasahraei/KorsiSher/HEAD/sc/frame3.png
--------------------------------------------------------------------------------
/sc/frame4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hamidrezasahraei/KorsiSher/HEAD/sc/frame4.png
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hamidrezasahraei/KorsiSher/HEAD/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/iosApp/Podfile:
--------------------------------------------------------------------------------
1 | target 'iosApp' do
2 | use_frameworks!
3 | platform :ios, '14.1'
4 | pod 'shared', :path => '../shared'
5 | end
--------------------------------------------------------------------------------
/iosApp/iosApp/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/androidApp/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/iosApp/iosApp/Preview Content/Preview Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
--------------------------------------------------------------------------------
/iosApp/Pods/Target Support Files/Pods-iosApp/Pods-iosApp-frameworks-Debug-output-files.xcfilelist:
--------------------------------------------------------------------------------
1 | ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/shared.framework
--------------------------------------------------------------------------------
/iosApp/Pods/Target Support Files/Pods-iosApp/Pods-iosApp-frameworks-Release-output-files.xcfilelist:
--------------------------------------------------------------------------------
1 | ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/shared.framework
--------------------------------------------------------------------------------
/androidApp/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hamidrezasahraei/KorsiSher/HEAD/androidApp/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/androidApp/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hamidrezasahraei/KorsiSher/HEAD/androidApp/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/androidApp/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hamidrezasahraei/KorsiSher/HEAD/androidApp/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/androidApp/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hamidrezasahraei/KorsiSher/HEAD/androidApp/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/androidApp/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hamidrezasahraei/KorsiSher/HEAD/androidApp/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/shared/src/commonMain/kotlin/korsi/sher/Platform.kt:
--------------------------------------------------------------------------------
1 | package korsi.sher
2 |
3 | interface Platform {
4 | val name: String
5 | }
6 |
7 | expect fun getPlatform(): Platform
--------------------------------------------------------------------------------
/androidApp/src/main/res/mipmap-hdpi/ic_launcher_background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hamidrezasahraei/KorsiSher/HEAD/androidApp/src/main/res/mipmap-hdpi/ic_launcher_background.png
--------------------------------------------------------------------------------
/androidApp/src/main/res/mipmap-hdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hamidrezasahraei/KorsiSher/HEAD/androidApp/src/main/res/mipmap-hdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/androidApp/src/main/res/mipmap-hdpi/ic_launcher_monochrome.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hamidrezasahraei/KorsiSher/HEAD/androidApp/src/main/res/mipmap-hdpi/ic_launcher_monochrome.png
--------------------------------------------------------------------------------
/androidApp/src/main/res/mipmap-mdpi/ic_launcher_background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hamidrezasahraei/KorsiSher/HEAD/androidApp/src/main/res/mipmap-mdpi/ic_launcher_background.png
--------------------------------------------------------------------------------
/androidApp/src/main/res/mipmap-mdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hamidrezasahraei/KorsiSher/HEAD/androidApp/src/main/res/mipmap-mdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/androidApp/src/main/res/mipmap-mdpi/ic_launcher_monochrome.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hamidrezasahraei/KorsiSher/HEAD/androidApp/src/main/res/mipmap-mdpi/ic_launcher_monochrome.png
--------------------------------------------------------------------------------
/androidApp/src/main/res/mipmap-xhdpi/ic_launcher_background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hamidrezasahraei/KorsiSher/HEAD/androidApp/src/main/res/mipmap-xhdpi/ic_launcher_background.png
--------------------------------------------------------------------------------
/androidApp/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hamidrezasahraei/KorsiSher/HEAD/androidApp/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/androidApp/src/main/res/mipmap-xhdpi/ic_launcher_monochrome.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hamidrezasahraei/KorsiSher/HEAD/androidApp/src/main/res/mipmap-xhdpi/ic_launcher_monochrome.png
--------------------------------------------------------------------------------
/shared/src/iosMain/kotlin/korsi/sher/core.domain.util/DisposableHandle.kt:
--------------------------------------------------------------------------------
1 | package korsi.sher.core.domain.util
2 |
3 | fun interface DisposableHandle: kotlinx.coroutines.DisposableHandle
--------------------------------------------------------------------------------
/androidApp/src/main/res/mipmap-xxhdpi/ic_launcher_background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hamidrezasahraei/KorsiSher/HEAD/androidApp/src/main/res/mipmap-xxhdpi/ic_launcher_background.png
--------------------------------------------------------------------------------
/androidApp/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hamidrezasahraei/KorsiSher/HEAD/androidApp/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/androidApp/src/main/res/mipmap-xxhdpi/ic_launcher_monochrome.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hamidrezasahraei/KorsiSher/HEAD/androidApp/src/main/res/mipmap-xxhdpi/ic_launcher_monochrome.png
--------------------------------------------------------------------------------
/androidApp/src/main/res/mipmap-xxxhdpi/ic_launcher_background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hamidrezasahraei/KorsiSher/HEAD/androidApp/src/main/res/mipmap-xxxhdpi/ic_launcher_background.png
--------------------------------------------------------------------------------
/androidApp/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hamidrezasahraei/KorsiSher/HEAD/androidApp/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/androidApp/src/main/res/mipmap-xxxhdpi/ic_launcher_monochrome.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hamidrezasahraei/KorsiSher/HEAD/androidApp/src/main/res/mipmap-xxxhdpi/ic_launcher_monochrome.png
--------------------------------------------------------------------------------
/iosApp/Pods/Target Support Files/Pods-iosApp/Pods-iosApp.modulemap:
--------------------------------------------------------------------------------
1 | framework module Pods_iosApp {
2 | umbrella header "Pods-iosApp-umbrella.h"
3 |
4 | export *
5 | module * { export * }
6 | }
7 |
--------------------------------------------------------------------------------
/androidApp/src/main/java/korsi/sher/android/core/presentation/Routes.kt:
--------------------------------------------------------------------------------
1 | package korsi.sher.android.core.presentation
2 |
3 | object Routes {
4 | const val POEM = "poem"
5 | const val LIKE = "liked"
6 | }
--------------------------------------------------------------------------------
/iosApp/Pods/Target Support Files/Pods-iosApp/Pods-iosApp-dummy.m:
--------------------------------------------------------------------------------
1 | #import
2 | @interface PodsDummy_Pods_iosApp : NSObject
3 | @end
4 | @implementation PodsDummy_Pods_iosApp
5 | @end
6 |
--------------------------------------------------------------------------------
/iosApp/iosApp/Assets.xcassets/AppIcon.appiconset/AppIcon~ios-marketing.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hamidrezasahraei/KorsiSher/HEAD/iosApp/iosApp/Assets.xcassets/AppIcon.appiconset/AppIcon~ios-marketing.png
--------------------------------------------------------------------------------
/iosApp/Pods/Target Support Files/Pods-iosApp/Pods-iosApp-acknowledgements.markdown:
--------------------------------------------------------------------------------
1 | # Acknowledgements
2 | This application makes use of the following third party libraries:
3 | Generated by CocoaPods - https://cocoapods.org
4 |
--------------------------------------------------------------------------------
/shared/src/commonMain/kotlin/korsi/sher/poem/data/remote/HttpClientFactory.kt:
--------------------------------------------------------------------------------
1 | package korsi.sher.poem.data.remote
2 |
3 | import io.ktor.client.*
4 |
5 | expect class HttpClientFactory {
6 | fun create(): HttpClient
7 | }
--------------------------------------------------------------------------------
/androidApp/src/main/java/korsi/sher/android/KorsiSherApp.kt:
--------------------------------------------------------------------------------
1 | package korsi.sher.android
2 |
3 | import android.app.Application
4 | import dagger.hilt.android.HiltAndroidApp
5 |
6 | @HiltAndroidApp
7 | class KorsiSherApp: Application()
--------------------------------------------------------------------------------
/iosApp/iosApp/Assets.xcassets/AccentColor.colorset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "colors" : [
3 | {
4 | "idiom" : "universal"
5 | }
6 | ],
7 | "info" : {
8 | "author" : "xcode",
9 | "version" : 1
10 | }
11 | }
--------------------------------------------------------------------------------
/iosApp/Pods/Target Support Files/Pods-iosApp/Pods-iosApp-frameworks-Debug-input-files.xcfilelist:
--------------------------------------------------------------------------------
1 | ${PODS_ROOT}/Target Support Files/Pods-iosApp/Pods-iosApp-frameworks.sh
2 | ${PODS_ROOT}/../../shared/build/cocoapods/framework/shared.framework
--------------------------------------------------------------------------------
/iosApp/Pods/Target Support Files/Pods-iosApp/Pods-iosApp-frameworks-Release-input-files.xcfilelist:
--------------------------------------------------------------------------------
1 | ${PODS_ROOT}/Target Support Files/Pods-iosApp/Pods-iosApp-frameworks.sh
2 | ${PODS_ROOT}/../../shared/build/cocoapods/framework/shared.framework
--------------------------------------------------------------------------------
/shared/src/commonMain/kotlin/korsi/sher/poem/domain/poem/PoemClient.kt:
--------------------------------------------------------------------------------
1 | package korsi.sher.poem.domain.poem
2 |
3 | import korsi.sher.poem.domain.history.PoemItem
4 |
5 | interface PoemClient {
6 | suspend fun randomPoem(): PoemItem
7 | }
--------------------------------------------------------------------------------
/shared/src/commonMain/kotlin/korsi/sher/Greeting.kt:
--------------------------------------------------------------------------------
1 | package korsi.sher
2 |
3 | class Greeting {
4 | private val platform: Platform = getPlatform()
5 |
6 | fun greet(): String {
7 | return "Hello, ${platform.name}!"
8 | }
9 | }
--------------------------------------------------------------------------------
/iosApp/iosApp/iOSApp.swift:
--------------------------------------------------------------------------------
1 | import SwiftUI
2 |
3 | @main
4 | struct iOSApp: App {
5 | var body: some Scene {
6 | WindowGroup {
7 | NavigationView {
8 | ContentView()
9 | }
10 | }
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/shared/src/commonMain/kotlin/korsi/sher/poem/data/local/DatabaseDriverFactory.kt:
--------------------------------------------------------------------------------
1 | package korsi.sher.poem.data.local
2 |
3 | import com.squareup.sqldelight.db.SqlDriver
4 |
5 | expect class DatabaseDriverFactory {
6 | fun create(): SqlDriver
7 | }
--------------------------------------------------------------------------------
/shared/src/androidMain/kotlin/korsi/sher/Platform.kt:
--------------------------------------------------------------------------------
1 | package korsi.sher
2 |
3 | class AndroidPlatform : Platform {
4 | override val name: String = "Android ${android.os.Build.VERSION.SDK_INT}"
5 | }
6 |
7 | actual fun getPlatform(): Platform = AndroidPlatform()
--------------------------------------------------------------------------------
/shared/src/androidMain/kotlin/korsi/sher/core/domain/util/CommonFlow.kt:
--------------------------------------------------------------------------------
1 | package korsi.sher.core.domain.util
2 |
3 | import kotlinx.coroutines.flow.Flow
4 |
5 | actual class CommonFlow actual constructor(
6 | private val flow: Flow
7 | ): Flow by flow
--------------------------------------------------------------------------------
/shared/src/commonMain/kotlin/korsi/sher/core/domain/util/CommonFlow.kt:
--------------------------------------------------------------------------------
1 | package korsi.sher.core.domain.util
2 |
3 | import kotlinx.coroutines.flow.Flow
4 |
5 | expect class CommonFlow(flow: Flow): Flow
6 |
7 | fun Flow.toCommonFlow() = CommonFlow(this)
--------------------------------------------------------------------------------
/shared/src/androidMain/kotlin/korsi/sher/core/domain/util/CommonStateFlow.kt:
--------------------------------------------------------------------------------
1 | package korsi.sher.core.domain.util
2 |
3 | import kotlinx.coroutines.flow.StateFlow
4 |
5 | actual class CommonStateFlow actual constructor(
6 | private val flow: StateFlow
7 | ): StateFlow by flow
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Wed Jun 21 11:31:30 CEST 2023
2 | distributionBase=GRADLE_USER_HOME
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-bin.zip
4 | distributionPath=wrapper/dists
5 | zipStorePath=wrapper/dists
6 | zipStoreBase=GRADLE_USER_HOME
7 |
--------------------------------------------------------------------------------
/shared/src/iosMain/kotlin/korsi/sher/core.domain.util/IOSMutableStateFlow.kt:
--------------------------------------------------------------------------------
1 | package korsi.sher.core.domain.util
2 |
3 | import kotlinx.coroutines.flow.MutableStateFlow
4 |
5 | class IOSMutableStateFlow(
6 | initialValue: T
7 | ): CommonMutableStateFlow(MutableStateFlow(initialValue))
--------------------------------------------------------------------------------
/shared/src/commonMain/kotlin/korsi/sher/core/domain/util/CommonStateFlow.kt:
--------------------------------------------------------------------------------
1 | package korsi.sher.core.domain.util
2 |
3 | import kotlinx.coroutines.flow.StateFlow
4 |
5 | expect class CommonStateFlow(flow: StateFlow): StateFlow
6 |
7 | fun StateFlow.toCommonStateFlow() = CommonStateFlow(this)
--------------------------------------------------------------------------------
/shared/src/commonMain/kotlin/korsi/sher/core/presentation/Colors.kt:
--------------------------------------------------------------------------------
1 | package korsi.sher.core.presentation
2 |
3 | object Colors {
4 | const val LightBackground = 0xFFA8A5BB
5 | const val DarkBackground = 0xFFF6F4F4
6 | const val WhiteText = 0xFF5643C9
7 | const val BlackText = 0xFF111111
8 | }
--------------------------------------------------------------------------------
/shared/src/commonMain/kotlin/korsi/sher/poem/presentation/like/LikeEvent.kt:
--------------------------------------------------------------------------------
1 | package korsi.sher.poem.presentation.like
2 |
3 | import korsi.sher.poem.domain.history.PoemItem
4 |
5 | sealed class LikeEvent {
6 | data class SharePoem(val poem: PoemItem): LikeEvent()
7 | object OnErrorSeen: LikeEvent()
8 | }
9 |
--------------------------------------------------------------------------------
/shared/src/androidMain/kotlin/korsi/sher/core/domain/util/CommonMutableStateFlow.kt:
--------------------------------------------------------------------------------
1 | package korsi.sher.core.domain.util
2 |
3 | import kotlinx.coroutines.flow.MutableStateFlow
4 |
5 | actual class CommonMutableStateFlow actual constructor(
6 | private val flow: MutableStateFlow
7 | ): MutableStateFlow by flow
--------------------------------------------------------------------------------
/shared/src/iosMain/kotlin/korsi/sher/Platform.kt:
--------------------------------------------------------------------------------
1 | package korsi.sher
2 |
3 | import platform.UIKit.UIDevice
4 |
5 | class IOSPlatform: Platform {
6 | override val name: String = UIDevice.currentDevice.systemName() + " " + UIDevice.currentDevice.systemVersion
7 | }
8 |
9 | actual fun getPlatform(): Platform = IOSPlatform()
--------------------------------------------------------------------------------
/shared/src/commonMain/kotlin/korsi/sher/poem/domain/history/PoemHistoryDataSource.kt:
--------------------------------------------------------------------------------
1 | package korsi.sher.poem.domain.history
2 |
3 | import korsi.sher.core.domain.util.CommonFlow
4 |
5 | interface PoemHistoryDataSource {
6 | fun getHistory(): CommonFlow>
7 | suspend fun insertHistoryItem(item: PoemItem)
8 | }
--------------------------------------------------------------------------------
/shared/src/commonMain/kotlin/korsi/sher/core/domain/util/Resource.kt:
--------------------------------------------------------------------------------
1 | package korsi.sher.core.domain.util
2 |
3 | sealed class Resource(val data: T?, val throwable: Throwable? = null) {
4 | class Success(data: T): Resource(data)
5 | class Error(throwable: Throwable): Resource(data = null, throwable = throwable)
6 | }
--------------------------------------------------------------------------------
/iosApp/iosApp/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "AppIcon~ios-marketing.png",
5 | "idiom" : "universal",
6 | "platform" : "ios",
7 | "size" : "1024x1024"
8 | }
9 | ],
10 | "info" : {
11 | "author" : "xcode",
12 | "version" : 1
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/iosApp/Podfile.lock:
--------------------------------------------------------------------------------
1 | PODS:
2 | - shared (1.1)
3 |
4 | DEPENDENCIES:
5 | - shared (from `../shared`)
6 |
7 | EXTERNAL SOURCES:
8 | shared:
9 | :path: "../shared"
10 |
11 | SPEC CHECKSUMS:
12 | shared: 039a628f2f63c363c8fa7b2288a6ce21417b1543
13 |
14 | PODFILE CHECKSUM: f282da88f39e69507b0a255187c8a6b644477756
15 |
16 | COCOAPODS: 1.12.1
17 |
--------------------------------------------------------------------------------
/iosApp/iosApp/ContentView.swift:
--------------------------------------------------------------------------------
1 | import SwiftUI
2 | import shared
3 |
4 | struct ContentView: View {
5 |
6 | private let appModule = AppModule()
7 |
8 | var body: some View {
9 | PoemScreen(poemHistoryDataSource: appModule.poemHistoryDataSource, poemUseCase: appModule.poemUseCase, likeUseCase: appModule.likeUseCase)
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/shared/src/commonMain/kotlin/korsi/sher/core/domain/util/CommonMutableStateFlow.kt:
--------------------------------------------------------------------------------
1 | package korsi.sher.core.domain.util
2 |
3 | import kotlinx.coroutines.flow.MutableStateFlow
4 |
5 | expect class CommonMutableStateFlow(flow: MutableStateFlow): MutableStateFlow
6 |
7 | fun MutableStateFlow.toCommonMutableStateFlow() = CommonMutableStateFlow(this)
--------------------------------------------------------------------------------
/iosApp/Pods/Manifest.lock:
--------------------------------------------------------------------------------
1 | PODS:
2 | - shared (1.1)
3 |
4 | DEPENDENCIES:
5 | - shared (from `../shared`)
6 |
7 | EXTERNAL SOURCES:
8 | shared:
9 | :path: "../shared"
10 |
11 | SPEC CHECKSUMS:
12 | shared: 039a628f2f63c363c8fa7b2288a6ce21417b1543
13 |
14 | PODFILE CHECKSUM: f282da88f39e69507b0a255187c8a6b644477756
15 |
16 | COCOAPODS: 1.12.1
17 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | #Gradle
2 | org.gradle.jvmargs=-Xmx2048M -Dfile.encoding=UTF-8 -Dkotlin.daemon.jvm.options\="-Xmx2048M"
3 |
4 | #Kotlin
5 | kotlin.code.style=official
6 |
7 | #Android
8 | android.useAndroidX=true
9 | android.nonTransitiveRClass=true
10 |
11 | #MPP
12 | kotlin.mpp.enableCInteropCommonization=true
13 | kotlin.mpp.androidSourceSetLayoutVersion=2
--------------------------------------------------------------------------------
/shared/src/commonMain/kotlin/korsi/sher/poem/domain/poem/PoemError.kt:
--------------------------------------------------------------------------------
1 | package korsi.sher.poem.domain.poem
2 |
3 | enum class PoemError {
4 | SERVICE_UNAVAILABLE,
5 | CLIENT_ERROR,
6 | SERVER_ERROR,
7 | UNKNOWN_ERROR
8 | }
9 |
10 | class PoemException(val error: PoemError): Exception(
11 | "An error occurred when getting a poem: $error"
12 | )
--------------------------------------------------------------------------------
/shared/src/commonMain/kotlin/korsi/sher/poem/data/poem/PoemDto.kt:
--------------------------------------------------------------------------------
1 | package korsi.sher.poem.data.poem
2 |
3 | import kotlinx.serialization.SerialName
4 |
5 | @kotlinx.serialization.Serializable
6 | data class PoemDto(
7 | @SerialName("m1") val verse1: String,
8 | @SerialName("m2") val verse2: String,
9 | val poet: String,
10 | val url: String
11 | )
12 |
--------------------------------------------------------------------------------
/iosApp/iosApp.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/settings.gradle.kts:
--------------------------------------------------------------------------------
1 | pluginManagement {
2 | repositories {
3 | google()
4 | gradlePluginPortal()
5 | mavenCentral()
6 | }
7 | }
8 |
9 | dependencyResolutionManagement {
10 | repositories {
11 | google()
12 | mavenCentral()
13 | }
14 | }
15 |
16 | rootProject.name = "KorsiSher"
17 | include(":androidApp")
18 | include(":shared")
--------------------------------------------------------------------------------
/androidApp/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/shared/src/commonMain/kotlin/korsi/sher/poem/domain/history/PoemItem.kt:
--------------------------------------------------------------------------------
1 | package korsi.sher.poem.domain.history
2 |
3 | data class PoemItem(
4 | val id: Long,
5 | val verse1: String,
6 | val verse2: String,
7 | val poet: String,
8 | var isLiked: Boolean = false
9 | ) {
10 | fun getTextForShare(): String {
11 | return "$verse1\n$verse2\n« $poet »"
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/shared/src/commonMain/kotlin/korsi/sher/poem/presentation/poem/PoemEvent.kt:
--------------------------------------------------------------------------------
1 | package korsi.sher.poem.presentation.poem
2 |
3 | import korsi.sher.poem.domain.history.PoemItem
4 |
5 | sealed class PoemEvent {
6 | object RandomPoem: PoemEvent()
7 | data class SharePoem(val poem: PoemItem): PoemEvent()
8 | data class LikePoem(val poem: PoemItem): PoemEvent()
9 | object OnErrorSeen: PoemEvent()
10 | }
11 |
--------------------------------------------------------------------------------
/iosApp/Pods/Target Support Files/Pods-iosApp/Pods-iosApp-umbrella.h:
--------------------------------------------------------------------------------
1 | #ifdef __OBJC__
2 | #import
3 | #else
4 | #ifndef FOUNDATION_EXPORT
5 | #if defined(__cplusplus)
6 | #define FOUNDATION_EXPORT extern "C"
7 | #else
8 | #define FOUNDATION_EXPORT extern
9 | #endif
10 | #endif
11 | #endif
12 |
13 |
14 | FOUNDATION_EXPORT double Pods_iosAppVersionNumber;
15 | FOUNDATION_EXPORT const unsigned char Pods_iosAppVersionString[];
16 |
17 |
--------------------------------------------------------------------------------
/iosApp/KorsiSher.xcodeproj/xcuserdata/hamidrezasahraei.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | iosApp.xcscheme_^#shared#^_
8 |
9 | orderHint
10 | 2
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/shared/src/iosMain/kotlin/korsi/sher/poem.data/local/DatabaseDriverFactory.kt:
--------------------------------------------------------------------------------
1 | package korsi.sher.poem.data.local
2 |
3 | import com.squareup.sqldelight.db.SqlDriver
4 | import com.squareup.sqldelight.drivers.native.NativeSqliteDriver
5 | import korsi.sher.database.PoemDatabase
6 |
7 | actual class DatabaseDriverFactory {
8 | actual fun create(): SqlDriver {
9 | return NativeSqliteDriver(
10 | schema = PoemDatabase.Schema,
11 | name = "poem.db"
12 | )
13 | }
14 | }
--------------------------------------------------------------------------------
/shared/src/commonMain/kotlin/korsi/sher/poem/presentation/like/LikeState.kt:
--------------------------------------------------------------------------------
1 | package korsi.sher.poem.presentation.like
2 |
3 | import korsi.sher.poem.domain.history.PoemItem
4 | import korsi.sher.poem.domain.poem.PoemError
5 | import korsi.sher.poem.presentation.util.generateRandomColors
6 |
7 | data class LikeState(
8 | val isLoading: Boolean = false,
9 | val likedPoems: List = emptyList(),
10 | val error: PoemError? = null,
11 | val colors: Triple = generateRandomColors()
12 | )
--------------------------------------------------------------------------------
/shared/src/commonMain/sqldelight/database/poem.sq:
--------------------------------------------------------------------------------
1 | CREATE TABLE poemEntity(
2 | id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
3 | verse1 TEXT NOT NULL,
4 | verse2 TEXT NOT NULL,
5 | poet TEXT NOT NULL,
6 | timestamp INTEGER NOT NULL
7 | );
8 |
9 | getHistory:
10 | SELECT *
11 | FROM poemEntity
12 | ORDER BY timestamp DESC;
13 |
14 | insertHistoryEntity:
15 | INSERT OR REPLACE
16 | INTO poemEntity(
17 | id,
18 | verse1,
19 | verse2,
20 | poet,
21 | timestamp
22 | )
23 | VALUES (?,?,?,?,?);
--------------------------------------------------------------------------------
/shared/src/iosMain/kotlin/korsi/sher/poem.data.remote/HttpClientFactory.kt:
--------------------------------------------------------------------------------
1 | package korsi.sher.poem.data.remote
2 |
3 | import io.ktor.client.*
4 | import io.ktor.client.engine.darwin.*
5 | import io.ktor.client.plugins.contentnegotiation.*
6 | import io.ktor.serialization.kotlinx.json.*
7 |
8 | actual class HttpClientFactory {
9 | actual fun create(): HttpClient {
10 | return HttpClient(Darwin) {
11 | install(ContentNegotiation) {
12 | json()
13 | }
14 | }
15 | }
16 | }
--------------------------------------------------------------------------------
/shared/src/androidMain/kotlin/korsi/sher/poem/data/remote/HttpClientFactory.kt:
--------------------------------------------------------------------------------
1 | package korsi.sher.poem.data.remote
2 |
3 | import io.ktor.client.*
4 | import io.ktor.client.engine.android.*
5 | import io.ktor.client.plugins.contentnegotiation.*
6 | import io.ktor.serialization.kotlinx.json.*
7 |
8 | actual class HttpClientFactory {
9 | actual fun create(): HttpClient {
10 | return HttpClient(Android) {
11 | install(ContentNegotiation) {
12 | json()
13 | }
14 | }
15 | }
16 | }
--------------------------------------------------------------------------------
/shared/src/commonMain/kotlin/korsi/sher/poem/presentation/poem/PoemState.kt:
--------------------------------------------------------------------------------
1 | package korsi.sher.poem.presentation.poem
2 |
3 | import korsi.sher.poem.domain.history.PoemItem
4 | import korsi.sher.poem.domain.poem.PoemError
5 | import korsi.sher.poem.presentation.util.generateRandomColors
6 |
7 | data class PoemState(
8 | val poemItem: PoemItem? = null,
9 | val isLoading: Boolean = false,
10 | val history: List = emptyList(),
11 | val error: PoemError? = null,
12 | val colors: Triple = generateRandomColors()
13 | )
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Gradle files
2 | .gradle/
3 | build/
4 |
5 | # Local configuration file (sdk path, etc)
6 | local.properties
7 |
8 | # Log/OS Files
9 | *.log
10 |
11 | # Android Studio generated files and folders
12 | captures/
13 | .externalNativeBuild/
14 | .cxx/
15 | *.apk
16 | output.json
17 |
18 | # IntelliJ
19 | *.iml
20 | .idea/
21 | misc.xml
22 | deploymentTargetDropDown.xml
23 | render.experimental.xml
24 |
25 | # Keystore files
26 | *.jks
27 | *.keystore
28 |
29 | # Google Services (e.g. APIs or Firebase)
30 | google-services.json
31 |
32 | # Android Profiling
33 | *.hprof
--------------------------------------------------------------------------------
/shared/src/androidMain/kotlin/korsi/sher/poem/data/local/DatabaseDriverFactory.kt:
--------------------------------------------------------------------------------
1 | package korsi.sher.poem.data.local
2 |
3 | import android.content.Context
4 | import com.squareup.sqldelight.android.AndroidSqliteDriver
5 | import com.squareup.sqldelight.db.SqlDriver
6 | import korsi.sher.database.PoemDatabase
7 |
8 | actual class DatabaseDriverFactory (
9 | private val context: Context
10 | ){
11 | actual fun create(): SqlDriver {
12 | return AndroidSqliteDriver(
13 | schema = PoemDatabase.Schema,
14 | context = context,
15 | name = "poem.db"
16 | )
17 | }
18 | }
--------------------------------------------------------------------------------
/shared/src/iosMain/kotlin/korsi/sher/core.domain.util/CommonStateFlow.kt:
--------------------------------------------------------------------------------
1 | package korsi.sher.core.domain.util
2 |
3 | import kotlinx.coroutines.flow.FlowCollector
4 | import kotlinx.coroutines.flow.StateFlow
5 |
6 | actual open class CommonStateFlow actual constructor(
7 | private val flow: StateFlow
8 | ) : CommonFlow(flow), StateFlow {
9 | override val replayCache: List
10 | get() = flow.replayCache
11 |
12 | override suspend fun collect(collector: FlowCollector): Nothing {
13 | flow.collect(collector)
14 | }
15 |
16 | override val value: T
17 | get() = flow.value
18 | }
--------------------------------------------------------------------------------
/shared/src/commonMain/kotlin/korsi/sher/poem/data/mapper/PoemItemMapper.kt:
--------------------------------------------------------------------------------
1 | package korsi.sher.poem.data.mapper
2 |
3 | import database.PoemEntity
4 | import korsi.sher.poem.data.poem.PoemDto
5 | import korsi.sher.poem.domain.history.PoemItem
6 |
7 | fun PoemEntity.toPoemItem(): PoemItem {
8 | return PoemItem(
9 | id = id,
10 | verse1 = verse1,
11 | verse2 = verse2,
12 | poet = poet
13 | )
14 | }
15 |
16 | fun PoemDto.toPoemItem(): PoemItem {
17 | return PoemItem(
18 | id = "$verse1+$verse2".hashCode().toLong(),
19 | verse1 = verse1,
20 | verse2 = verse2,
21 | poet = poet
22 | )
23 | }
24 |
25 |
--------------------------------------------------------------------------------
/iosApp/Pods/Pods.xcodeproj/xcuserdata/hamidrezasahraei.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | Pods-iosApp.xcscheme
8 |
9 | isShown
10 |
11 | orderHint
12 | 0
13 |
14 | shared.xcscheme
15 |
16 | isShown
17 |
18 | orderHint
19 | 1
20 |
21 |
22 | SuppressBuildableAutocreation
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/shared/src/commonMain/kotlin/korsi/sher/poem/domain/history/LikeUseCase.kt:
--------------------------------------------------------------------------------
1 | package korsi.sher.poem.domain.history
2 |
3 | import korsi.sher.core.domain.util.Resource
4 | import korsi.sher.poem.domain.history.PoemHistoryDataSource
5 | import korsi.sher.poem.domain.history.PoemItem
6 | import korsi.sher.poem.domain.poem.PoemException
7 |
8 | class LikeUseCase(
9 | private val poemHistoryDataSource: PoemHistoryDataSource
10 | ) {
11 |
12 | suspend fun execute(poemItem: PoemItem): Resource {
13 | return try {
14 | poemHistoryDataSource.insertHistoryItem(poemItem)
15 | Resource.Success(Unit)
16 | } catch (e: PoemException) {
17 | e.printStackTrace()
18 | Resource.Error(e)
19 | }
20 | }
21 | }
--------------------------------------------------------------------------------
/iosApp/Pods/Target Support Files/Pods-iosApp/Pods-iosApp.debug.xcconfig:
--------------------------------------------------------------------------------
1 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO
2 | FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/../../shared/build/cocoapods/framework"
3 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
4 | LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks'
5 | OTHER_LDFLAGS = $(inherited) -l"c++" -framework "shared"
6 | PODS_BUILD_DIR = ${BUILD_DIR}
7 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
8 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/.
9 | PODS_ROOT = ${SRCROOT}/Pods
10 | PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates
11 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES
12 |
--------------------------------------------------------------------------------
/iosApp/Pods/Target Support Files/Pods-iosApp/Pods-iosApp.release.xcconfig:
--------------------------------------------------------------------------------
1 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO
2 | FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/../../shared/build/cocoapods/framework"
3 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
4 | LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks'
5 | OTHER_LDFLAGS = $(inherited) -l"c++" -framework "shared"
6 | PODS_BUILD_DIR = ${BUILD_DIR}
7 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
8 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/.
9 | PODS_ROOT = ${SRCROOT}/Pods
10 | PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates
11 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES
12 |
--------------------------------------------------------------------------------
/androidApp/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
12 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/iosApp/Pods/Target Support Files/shared/shared.debug.xcconfig:
--------------------------------------------------------------------------------
1 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO
2 | CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/shared
3 | FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/../../shared/build/cocoapods/framework"
4 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
5 | KOTLIN_PROJECT_PATH = :shared
6 | OTHER_LDFLAGS = $(inherited) -l"c++"
7 | PODS_BUILD_DIR = ${BUILD_DIR}
8 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
9 | PODS_DEVELOPMENT_LANGUAGE = ${DEVELOPMENT_LANGUAGE}
10 | PODS_ROOT = ${SRCROOT}
11 | PODS_TARGET_SRCROOT = ${PODS_ROOT}/../../shared
12 | PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates
13 | PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier}
14 | PRODUCT_MODULE_NAME = shared
15 | SKIP_INSTALL = YES
16 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES
17 |
--------------------------------------------------------------------------------
/iosApp/Pods/Target Support Files/shared/shared.release.xcconfig:
--------------------------------------------------------------------------------
1 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO
2 | CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/shared
3 | FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/../../shared/build/cocoapods/framework"
4 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
5 | KOTLIN_PROJECT_PATH = :shared
6 | OTHER_LDFLAGS = $(inherited) -l"c++"
7 | PODS_BUILD_DIR = ${BUILD_DIR}
8 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
9 | PODS_DEVELOPMENT_LANGUAGE = ${DEVELOPMENT_LANGUAGE}
10 | PODS_ROOT = ${SRCROOT}
11 | PODS_TARGET_SRCROOT = ${PODS_ROOT}/../../shared
12 | PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates
13 | PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier}
14 | PRODUCT_MODULE_NAME = shared
15 | SKIP_INSTALL = YES
16 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES
17 |
--------------------------------------------------------------------------------
/shared/src/commonMain/kotlin/korsi/sher/poem/domain/poem/PoemUseCase.kt:
--------------------------------------------------------------------------------
1 | package korsi.sher.poem.domain.poem
2 |
3 | import korsi.sher.core.domain.util.Resource
4 | import korsi.sher.poem.domain.history.PoemHistoryDataSource
5 | import korsi.sher.poem.domain.history.PoemItem
6 | import kotlinx.coroutines.flow.collect
7 | import kotlinx.coroutines.flow.first
8 |
9 | class PoemUseCase(
10 | private val poemClient: PoemClient,
11 | private val poemHistoryDataSource: PoemHistoryDataSource
12 | ) {
13 |
14 | suspend fun execute(): Resource {
15 | return try {
16 | val poemItem = poemClient.randomPoem()
17 | val likeList = poemHistoryDataSource.getHistory().first()
18 | poemItem.isLiked = likeList.any { it.id == poemItem.id }
19 | Resource.Success(poemItem)
20 | } catch (e: PoemException) {
21 | e.printStackTrace()
22 | Resource.Error(e)
23 | }
24 | }
25 | }
--------------------------------------------------------------------------------
/iosApp/Pods/Target Support Files/Pods-iosApp/Pods-iosApp-acknowledgements.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | PreferenceSpecifiers
6 |
7 |
8 | FooterText
9 | This application makes use of the following third party libraries:
10 | Title
11 | Acknowledgements
12 | Type
13 | PSGroupSpecifier
14 |
15 |
16 | FooterText
17 | Generated by CocoaPods - https://cocoapods.org
18 | Title
19 |
20 | Type
21 | PSGroupSpecifier
22 |
23 |
24 | StringsTable
25 | Acknowledgements
26 | Title
27 | Acknowledgements
28 |
29 |
30 |
--------------------------------------------------------------------------------
/iosApp/Pods/Target Support Files/Pods-iosApp/Pods-iosApp-Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | ${PODS_DEVELOPMENT_LANGUAGE}
7 | CFBundleExecutable
8 | ${EXECUTABLE_NAME}
9 | CFBundleIdentifier
10 | ${PRODUCT_BUNDLE_IDENTIFIER}
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | ${PRODUCT_NAME}
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 1.0.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | ${CURRENT_PROJECT_VERSION}
23 | NSPrincipalClass
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/shared/src/commonMain/kotlin/korsi/sher/poem/presentation/util/ColorUtil.kt:
--------------------------------------------------------------------------------
1 | package korsi.sher.poem.presentation.util
2 |
3 | import kotlin.random.Random
4 |
5 | fun generateRandomColors(): Triple {
6 | val backgroundColor = generateRandomColor()
7 | val textColor = getReadableTextColor(backgroundColor)
8 | return Triple(backgroundColor, textColor, textColor)
9 | }
10 |
11 | private fun generateRandomColor(): Int {
12 | val alpha = 255
13 | val red = Random.nextInt(128)
14 | val green = Random.nextInt(128)
15 | val blue = Random.nextInt(128)
16 | return (alpha shl 24) or (red shl 16) or (green shl 8) or blue
17 | }
18 |
19 | private fun getReadableTextColor(backgroundColor: Int): Int {
20 | val red = (backgroundColor shr 16) and 0xFF
21 | val green = (backgroundColor shr 8) and 0xFF
22 | val blue = backgroundColor and 0xFF
23 |
24 | val darkness = 1 - (0.299 * red + 0.587 * green + 0.114 * blue) / 255
25 | return if (darkness < 0.5) 0xFF000000.toInt() else 0xFFFFFFFF.toInt()
26 | }
--------------------------------------------------------------------------------
/shared/src/iosMain/kotlin/korsi/sher/core.domain.util/CommonFlow.kt:
--------------------------------------------------------------------------------
1 | package korsi.sher.core.domain.util
2 |
3 | import kotlinx.coroutines.CoroutineDispatcher
4 | import kotlinx.coroutines.CoroutineScope
5 | import kotlinx.coroutines.Dispatchers
6 | import kotlinx.coroutines.GlobalScope
7 | import kotlinx.coroutines.flow.Flow
8 | import kotlinx.coroutines.launch
9 |
10 | actual open class CommonFlow actual constructor(
11 | private val flow: Flow
12 | ) : Flow by flow {
13 |
14 | fun subscribe(
15 | coroutineScope: CoroutineScope,
16 | dispatcher: CoroutineDispatcher,
17 | onCollect: (T) -> Unit
18 | ): DisposableHandle {
19 | val job = coroutineScope.launch(dispatcher) {
20 | flow.collect(onCollect)
21 | }
22 | return DisposableHandle { job.cancel() }
23 | }
24 |
25 | fun subscribe(
26 | onCollect: (T) -> Unit
27 | ): DisposableHandle {
28 | return subscribe(
29 | coroutineScope = GlobalScope,
30 | dispatcher = Dispatchers.Main,
31 | onCollect = onCollect
32 | )
33 | }
34 | }
--------------------------------------------------------------------------------
/androidApp/src/main/java/korsi/sher/android/like/presentation/AndroidLikeViewModel.kt:
--------------------------------------------------------------------------------
1 | package korsi.sher.android.like.presentation
2 |
3 | import androidx.lifecycle.ViewModel
4 | import androidx.lifecycle.viewModelScope
5 | import dagger.hilt.android.lifecycle.HiltViewModel
6 | import korsi.sher.poem.domain.history.LikeUseCase
7 | import korsi.sher.poem.domain.history.PoemHistoryDataSource
8 | import korsi.sher.poem.presentation.like.LikeEvent
9 | import korsi.sher.poem.presentation.like.LikeViewModel
10 | import javax.inject.Inject
11 |
12 | @HiltViewModel
13 | class AndroidLikeViewModel @Inject constructor(
14 | private val likeUseCase: LikeUseCase,
15 | private val poemHistoryDataSource: PoemHistoryDataSource
16 | ) : ViewModel() {
17 |
18 | private val viewModel by lazy {
19 | LikeViewModel(
20 | likeUseCase = likeUseCase,
21 | poemHistoryDataSource = poemHistoryDataSource,
22 | coroutineScope = viewModelScope
23 | )
24 | }
25 |
26 | val state = viewModel.state
27 |
28 | fun onEvent(event: LikeEvent) {
29 | viewModel.onEvent(event)
30 | }
31 | }
--------------------------------------------------------------------------------
/shared/src/iosMain/kotlin/korsi/sher/core.domain.util/CommonMutableStateFlow.kt:
--------------------------------------------------------------------------------
1 | package korsi.sher.core.domain.util
2 |
3 | import kotlinx.coroutines.ExperimentalCoroutinesApi
4 | import kotlinx.coroutines.flow.MutableStateFlow
5 | import kotlinx.coroutines.flow.StateFlow
6 |
7 | actual open class CommonMutableStateFlow actual constructor(
8 | private val flow: MutableStateFlow
9 | ) : CommonStateFlow(flow), MutableStateFlow {
10 |
11 | override var value: T
12 | get() = super.value
13 | set(value) {
14 | flow.value = value
15 | }
16 |
17 | override val subscriptionCount: StateFlow
18 | get() = flow.subscriptionCount
19 |
20 | override suspend fun emit(value: T) {
21 | flow.emit(value)
22 | }
23 |
24 | @ExperimentalCoroutinesApi
25 | override fun resetReplayCache() {
26 | flow.resetReplayCache()
27 | }
28 |
29 | override fun tryEmit(value: T): Boolean {
30 | return flow.tryEmit(value)
31 | }
32 |
33 | override fun compareAndSet(expect: T, update: T): Boolean {
34 | return flow.compareAndSet(expect, update)
35 | }
36 | }
--------------------------------------------------------------------------------
/shared/src/iosMain/kotlin/korsi/sher/di/AppModule.kt:
--------------------------------------------------------------------------------
1 | package korsi.sher.di
2 |
3 | import korsi.sher.database.PoemDatabase
4 | import korsi.sher.poem.data.history.SqlDelightHistoryDataSource
5 | import korsi.sher.poem.data.local.DatabaseDriverFactory
6 | import korsi.sher.poem.data.poem.KtorPoemClient
7 | import korsi.sher.poem.data.remote.HttpClientFactory
8 | import korsi.sher.poem.domain.history.LikeUseCase
9 | import korsi.sher.poem.domain.history.PoemHistoryDataSource
10 | import korsi.sher.poem.domain.poem.PoemClient
11 | import korsi.sher.poem.domain.poem.PoemUseCase
12 |
13 | class AppModule {
14 |
15 | val poemHistoryDataSource: PoemHistoryDataSource by lazy {
16 | SqlDelightHistoryDataSource(
17 | PoemDatabase(
18 | DatabaseDriverFactory().create()
19 | )
20 | )
21 | }
22 |
23 | private val poemClient: PoemClient by lazy {
24 | KtorPoemClient(
25 | HttpClientFactory().create()
26 | )
27 | }
28 |
29 | val poemUseCase: PoemUseCase by lazy {
30 | PoemUseCase(poemClient, poemHistoryDataSource)
31 | }
32 |
33 | val likeUseCase: LikeUseCase by lazy {
34 | LikeUseCase(poemHistoryDataSource)
35 | }
36 | }
--------------------------------------------------------------------------------
/androidApp/src/main/java/korsi/sher/android/poem/presentation/AndroidPoemViewModel.kt:
--------------------------------------------------------------------------------
1 | package korsi.sher.android.poem.presentation
2 |
3 | import androidx.lifecycle.ViewModel
4 | import androidx.lifecycle.viewModelScope
5 | import dagger.hilt.android.lifecycle.HiltViewModel
6 | import korsi.sher.poem.domain.history.LikeUseCase
7 | import korsi.sher.poem.domain.history.PoemHistoryDataSource
8 | import korsi.sher.poem.domain.poem.PoemUseCase
9 | import korsi.sher.poem.presentation.poem.PoemEvent
10 | import korsi.sher.poem.presentation.poem.PoemViewModel
11 | import javax.inject.Inject
12 |
13 | @HiltViewModel
14 | class AndroidPoemViewModel @Inject constructor(
15 | private val poemUseCase: PoemUseCase,
16 | private val likeUseCase: LikeUseCase,
17 | private val poemHistoryDataSource: PoemHistoryDataSource
18 | ) : ViewModel() {
19 |
20 | private val viewModel by lazy {
21 | PoemViewModel(
22 | poemUseCase = poemUseCase,
23 | likeUseCase = likeUseCase,
24 | poemHistoryDataSource = poemHistoryDataSource,
25 | coroutineScope = viewModelScope
26 | )
27 | }
28 |
29 | val state = viewModel.state
30 |
31 | fun onEvent(event: PoemEvent) {
32 | viewModel.onEvent(event)
33 | }
34 | }
--------------------------------------------------------------------------------
/iosApp/iosApp/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE)
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 | LSRequiresIPhoneOS
22 |
23 | UIApplicationSceneManifest
24 |
25 | UIApplicationSupportsMultipleScenes
26 |
27 |
28 | UILaunchScreen
29 |
30 | UIRequiredDeviceCapabilities
31 |
32 | armv7
33 |
34 | UISupportedInterfaceOrientations
35 |
36 | UIInterfaceOrientationPortrait
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/iosApp/Pods/Local Podspecs/shared.podspec.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "shared",
3 | "version": "1.1",
4 | "homepage": "Link to the Shared Module homepage",
5 | "source": {
6 | "http": ""
7 | },
8 | "authors": "",
9 | "license": "",
10 | "summary": "Some description for the Shared Module",
11 | "vendored_frameworks": "build/cocoapods/framework/shared.framework",
12 | "libraries": "c++",
13 | "platforms": {
14 | "ios": "14.1"
15 | },
16 | "pod_target_xcconfig": {
17 | "KOTLIN_PROJECT_PATH": ":shared",
18 | "PRODUCT_MODULE_NAME": "shared"
19 | },
20 | "script_phases": [
21 | {
22 | "name": "Build shared",
23 | "execution_position": "before_compile",
24 | "shell_path": "/bin/sh",
25 | "script": " if [ \"YES\" = \"$OVERRIDE_KOTLIN_BUILD_IDE_SUPPORTED\" ]; then\n echo \"Skipping Gradle build task invocation due to OVERRIDE_KOTLIN_BUILD_IDE_SUPPORTED environment variable set to \"YES\"\"\n exit 0\n fi\n set -ev\n REPO_ROOT=\"$PODS_TARGET_SRCROOT\"\n \"$REPO_ROOT/../gradlew\" -p \"$REPO_ROOT\" $KOTLIN_PROJECT_PATH:syncFramework -Pkotlin.native.cocoapods.platform=$PLATFORM_NAME -Pkotlin.native.cocoapods.archs=\"$ARCHS\" -Pkotlin.native.cocoapods.configuration=\"$CONFIGURATION\"\n"
26 | }
27 | ]
28 | }
29 |
--------------------------------------------------------------------------------
/shared/src/commonMain/kotlin/korsi/sher/poem/data/history/SqlDelightHistoryDataSource.kt:
--------------------------------------------------------------------------------
1 | package korsi.sher.poem.data.history
2 |
3 | import com.squareup.sqldelight.runtime.coroutines.asFlow
4 | import com.squareup.sqldelight.runtime.coroutines.mapToList
5 | import korsi.sher.core.domain.util.CommonFlow
6 | import korsi.sher.core.domain.util.toCommonFlow
7 | import korsi.sher.database.PoemDatabase
8 | import korsi.sher.poem.data.mapper.toPoemItem
9 | import korsi.sher.poem.domain.history.PoemHistoryDataSource
10 | import korsi.sher.poem.domain.history.PoemItem
11 | import kotlinx.coroutines.flow.map
12 | import kotlinx.datetime.Clock
13 |
14 | class SqlDelightHistoryDataSource(
15 | db: PoemDatabase
16 | ) : PoemHistoryDataSource {
17 |
18 | private val queries = db.poemQueries
19 |
20 | override fun getHistory(): CommonFlow> {
21 | return queries
22 | .getHistory()
23 | .asFlow()
24 | .mapToList()
25 | .map { poemEntity ->
26 | poemEntity.map { it.toPoemItem() }
27 | }
28 | .toCommonFlow()
29 | }
30 |
31 | override suspend fun insertHistoryItem(item: PoemItem) {
32 | queries.insertHistoryEntity(
33 | id = item.id,
34 | verse1 = item.verse1,
35 | verse2 = item.verse2,
36 | poet = item.poet,
37 | timestamp = Clock.System.now().toEpochMilliseconds()
38 | )
39 | }
40 | }
--------------------------------------------------------------------------------
/iosApp/iosApp/poem/presentation/components/ProgressButton.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ProgressButton.swift
3 | // iosApp
4 | //
5 | // Created by Hamidreza Sahraei on 7/2/23.
6 | // Copyright © 2023 orgName. All rights reserved.
7 | //
8 |
9 | import SwiftUI
10 | import shared
11 |
12 | struct ProgressButton: View {
13 | var text: String
14 | var isLoading: Bool
15 | var onClick: () -> Void
16 | var body: some View {
17 | Button(
18 | action: {
19 | if !isLoading {
20 | onClick()
21 | }
22 | }
23 | ) {
24 | if isLoading {
25 | ProgressView()
26 | .animation(.easeInOut, value: isLoading)
27 | .padding(5)
28 | .background(.black)
29 | .cornerRadius(100)
30 | .progressViewStyle(CircularProgressViewStyle(tint: .white))
31 | } else {
32 | Text(text)
33 | .animation(.easeInOut, value: isLoading)
34 | .padding(.horizontal)
35 | .padding(.vertical, 5)
36 | .background(.black)
37 | .foregroundColor(.white)
38 | .cornerRadius(100)
39 |
40 | }
41 |
42 | }
43 | }
44 | }
45 |
46 | struct ProgressButton_Previews: PreviewProvider {
47 | static var previews: some View {
48 | ProgressButton(
49 | text: "Sher",
50 | isLoading: false,
51 | onClick: {}
52 | )
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/shared/src/commonMain/kotlin/korsi/sher/poem/data/poem/KtorPoemClient.kt:
--------------------------------------------------------------------------------
1 | package korsi.sher.poem.data.poem
2 |
3 | import io.ktor.client.*
4 | import io.ktor.client.call.*
5 | import io.ktor.client.request.*
6 | import io.ktor.http.*
7 | import io.ktor.utils.io.errors.*
8 | import korsi.sher.poem.data.mapper.toPoemItem
9 | import korsi.sher.poem.data.poem.NetworkConstants.RANDOM_POEM_URL
10 | import korsi.sher.poem.domain.history.PoemItem
11 | import korsi.sher.poem.domain.poem.PoemClient
12 | import korsi.sher.poem.domain.poem.PoemError
13 | import korsi.sher.poem.domain.poem.PoemException
14 |
15 | class KtorPoemClient(
16 | private val httpClient: HttpClient //Will differ on Android and IOS but the logic is the same
17 | ): PoemClient {
18 | override suspend fun randomPoem(): PoemItem {
19 | val result = try {
20 | httpClient.get {
21 | url(RANDOM_POEM_URL)
22 | contentType(ContentType.Application.Json)
23 | }
24 | } catch (ioException: IOException) {
25 | throw PoemException(PoemError.SERVICE_UNAVAILABLE)
26 | }
27 |
28 | when(result.status.value) {
29 | in 200..299 -> Unit
30 | 500 -> throw PoemException(PoemError.SERVER_ERROR)
31 | in 400..499 -> throw PoemException(PoemError.CLIENT_ERROR)
32 | else -> throw PoemException(PoemError.UNKNOWN_ERROR)
33 | }
34 |
35 | return try {
36 | result.body().toPoemItem()
37 | } catch (e: Exception) {
38 | throw PoemException(PoemError.SERVER_ERROR)
39 | }
40 | }
41 | }
42 |
43 | object NetworkConstants {
44 | const val RANDOM_POEM_URL = "https://c.ganjoor.net/beyt-json.php"
45 | }
--------------------------------------------------------------------------------
/iosApp/iosApp/like/presentation/IOSLikeViewModel.swift:
--------------------------------------------------------------------------------
1 | //
2 | // IOSLikeViewModel.swift
3 | // iosApp
4 | //
5 | // Created by Hamidreza Sahraei on 7/2/23.
6 | // Copyright © 2023 orgName. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import shared
11 |
12 | extension LikeScreen {
13 | @MainActor class IOSLikeViewModel: ObservableObject {
14 | private var historyDataSource: PoemHistoryDataSource
15 | private var likeUseCase: LikeUseCase
16 |
17 | private let viewModel: LikeViewModel
18 |
19 | @Published var state: LikeState = LikeState(
20 | isLoading: false,
21 | likedPoems: [],
22 | error: nil,
23 | colors: ColorUtilKt.generateRandomColors()
24 | )
25 |
26 | private var handle: DisposableHandle?
27 |
28 | init(historyDataSource: PoemHistoryDataSource, likeUseCase: LikeUseCase) {
29 | self.historyDataSource = historyDataSource
30 | self.likeUseCase = likeUseCase
31 | self.viewModel = LikeViewModel(
32 | likeUseCase: likeUseCase,
33 | poemHistoryDataSource: historyDataSource,
34 | coroutineScope: nil
35 | )
36 | }
37 |
38 | func onEvent(event: LikeEvent) {
39 | viewModel.onEvent(event: event)
40 | }
41 |
42 | func startObserving() {
43 | handle = viewModel.state.subscribe(onCollect: { state in
44 | if let state = state {
45 | self.state = state
46 | }
47 | })
48 | }
49 |
50 | func dispose() {
51 | handle?.dispose()
52 | }
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/shared/shared.podspec:
--------------------------------------------------------------------------------
1 | Pod::Spec.new do |spec|
2 | spec.name = 'shared'
3 | spec.version = '1.1'
4 | spec.homepage = 'Link to the Shared Module homepage'
5 | spec.source = { :http=> ''}
6 | spec.authors = ''
7 | spec.license = ''
8 | spec.summary = 'Some description for the Shared Module'
9 | spec.vendored_frameworks = 'build/cocoapods/framework/shared.framework'
10 | spec.libraries = 'c++'
11 | spec.ios.deployment_target = '14.1'
12 |
13 |
14 | spec.pod_target_xcconfig = {
15 | 'KOTLIN_PROJECT_PATH' => ':shared',
16 | 'PRODUCT_MODULE_NAME' => 'shared',
17 | }
18 |
19 | spec.script_phases = [
20 | {
21 | :name => 'Build shared',
22 | :execution_position => :before_compile,
23 | :shell_path => '/bin/sh',
24 | :script => <<-SCRIPT
25 | if [ "YES" = "$OVERRIDE_KOTLIN_BUILD_IDE_SUPPORTED" ]; then
26 | echo "Skipping Gradle build task invocation due to OVERRIDE_KOTLIN_BUILD_IDE_SUPPORTED environment variable set to \"YES\""
27 | exit 0
28 | fi
29 | set -ev
30 | REPO_ROOT="$PODS_TARGET_SRCROOT"
31 | "$REPO_ROOT/../gradlew" -p "$REPO_ROOT" $KOTLIN_PROJECT_PATH:syncFramework \
32 | -Pkotlin.native.cocoapods.platform=$PLATFORM_NAME \
33 | -Pkotlin.native.cocoapods.archs="$ARCHS" \
34 | -Pkotlin.native.cocoapods.configuration="$CONFIGURATION"
35 | SCRIPT
36 | }
37 | ]
38 |
39 | end
--------------------------------------------------------------------------------
/iosApp/iosApp/core/presentation/Colors.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Colors.swift
3 | // iosApp
4 | //
5 | // Created by Hamidreza Sahraei on 7/1/23.
6 | // Copyright © 2023 orgName. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import SwiftUI
11 | import shared
12 |
13 | extension Color {
14 | init(hex: Int64, alpha: Double = 1) {
15 | self.init(
16 | .sRGB,
17 | red: Double((hex >> 16) & 0xff) / 255,
18 | green: Double((hex >> 08) & 0xff) / 255,
19 | blue: Double((hex >> 00) & 0xff) / 255,
20 | opacity: alpha
21 | )
22 | }
23 |
24 | private static let colors = Colors()
25 | static let lightBackground = Color(hex: colors.LightBackground)
26 | static let darkBackground = Color(hex: colors.DarkBackground)
27 | static let whiteText = Color(hex: colors.WhiteText)
28 | static let BlackText = Color(hex: colors.BlackText)
29 |
30 | static let background = Color(light: .lightBackground, dark: .darkBackground)
31 | static let onPrimary = Color(light: .whiteText, dark: .whiteText)
32 | static let onBackground = Color(light: .whiteText, dark: .whiteText)
33 |
34 | }
35 |
36 |
37 | private extension Color {
38 | init(light: Self, dark: Self) {
39 | self.init(uiColor: UIColor(light: UIColor(light), dark: UIColor(dark)))
40 | }
41 | }
42 |
43 | private extension UIColor {
44 | convenience init(light: UIColor, dark: UIColor) {
45 | self.init { traits in
46 | switch traits.userInterfaceStyle {
47 | case .light, .unspecified:
48 | return light
49 | case .dark:
50 | return dark
51 | @unknown default:
52 | return light
53 | }
54 | }
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/androidApp/src/main/java/korsi/sher/android/MyApplicationTheme.kt:
--------------------------------------------------------------------------------
1 | package korsi.sher.android
2 |
3 | import androidx.compose.foundation.isSystemInDarkTheme
4 | import androidx.compose.foundation.shape.RoundedCornerShape
5 | import androidx.compose.material.MaterialTheme
6 | import androidx.compose.material.Shapes
7 | import androidx.compose.material.Typography
8 | import androidx.compose.material.darkColors
9 | import androidx.compose.material.lightColors
10 | import androidx.compose.runtime.Composable
11 | import androidx.compose.ui.graphics.Color
12 | import androidx.compose.ui.text.TextStyle
13 | import androidx.compose.ui.text.font.FontFamily
14 | import androidx.compose.ui.text.font.FontWeight
15 | import androidx.compose.ui.unit.dp
16 | import androidx.compose.ui.unit.sp
17 |
18 | @Composable
19 | fun MyApplicationTheme(
20 | darkTheme: Boolean = isSystemInDarkTheme(),
21 | content: @Composable () -> Unit
22 | ) {
23 | val colors = if (darkTheme) {
24 | darkColors(
25 | primary = Color(0xFFBB86FC),
26 | primaryVariant = Color(0xFF3700B3),
27 | secondary = Color(0xFF03DAC5)
28 | )
29 | } else {
30 | lightColors(
31 | primary = Color(0xFF6200EE),
32 | primaryVariant = Color(0xFF3700B3),
33 | secondary = Color(0xFF03DAC5)
34 | )
35 | }
36 | val typography = Typography(
37 | body1 = TextStyle(
38 | fontFamily = FontFamily.Default,
39 | fontWeight = FontWeight.Normal,
40 | fontSize = 16.sp
41 | )
42 | )
43 | val shapes = Shapes(
44 | small = RoundedCornerShape(4.dp),
45 | medium = RoundedCornerShape(4.dp),
46 | large = RoundedCornerShape(0.dp)
47 | )
48 |
49 | MaterialTheme(
50 | colors = colors,
51 | typography = typography,
52 | shapes = shapes,
53 | content = content
54 | )
55 | }
56 |
--------------------------------------------------------------------------------
/iosApp/iosApp/poem/presentation/IOSPoemViewModel.swift:
--------------------------------------------------------------------------------
1 | //
2 | // IOSPoemViewModel.swift
3 | // iosApp
4 | //
5 | // Created by Hamidreza Sahraei on 7/2/23.
6 | // Copyright © 2023 orgName. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import shared
11 |
12 | extension PoemScreen {
13 | @MainActor class IOSPoemViewModel: ObservableObject {
14 | private var historyDataSource: PoemHistoryDataSource
15 | private var poemUseCase: PoemUseCase
16 | private var likeUseCase: LikeUseCase
17 |
18 | private let viewModel: PoemViewModel
19 |
20 | @Published var state: PoemState = PoemState(
21 | poemItem: nil,
22 | isLoading: false,
23 | history: [],
24 | error: nil,
25 | colors: ColorUtilKt.generateRandomColors()
26 | )
27 |
28 | private var handle: DisposableHandle?
29 |
30 | init(historyDataSource: PoemHistoryDataSource, poemUseCase: PoemUseCase, likeUseCase: LikeUseCase) {
31 | self.historyDataSource = historyDataSource
32 | self.poemUseCase = poemUseCase
33 | self.likeUseCase = likeUseCase
34 | self.viewModel = PoemViewModel(
35 | poemUseCase: poemUseCase,
36 | likeUseCase: likeUseCase,
37 | poemHistoryDataSource: historyDataSource,
38 | coroutineScope: nil
39 | )
40 | }
41 |
42 | func onEvent(event: PoemEvent) {
43 | viewModel.onEvent(event: event)
44 | }
45 |
46 | func startObserving() {
47 | handle = viewModel.state.subscribe(onCollect: { state in
48 | if let state = state {
49 | self.state = state
50 | }
51 | })
52 | }
53 | func dispose() {
54 | handle?.dispose()
55 | }
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/androidApp/src/main/java/korsi/sher/android/core/presentation/components/ProgressButton.kt:
--------------------------------------------------------------------------------
1 | package korsi.sher.android.poem.presentation.components
2 |
3 | import androidx.compose.animation.AnimatedContent
4 | import androidx.compose.animation.ExperimentalAnimationApi
5 | import androidx.compose.foundation.BorderStroke
6 | import androidx.compose.foundation.background
7 | import androidx.compose.foundation.layout.size
8 | import androidx.compose.foundation.shape.RoundedCornerShape
9 | import androidx.compose.material.Button
10 | import androidx.compose.material.ButtonDefaults
11 | import androidx.compose.material.CircularProgressIndicator
12 | import androidx.compose.material.Text
13 | import androidx.compose.material.TextButton
14 | import androidx.compose.runtime.Composable
15 | import androidx.compose.ui.Modifier
16 | import androidx.compose.ui.graphics.Color
17 | import androidx.compose.ui.text.TextStyle
18 | import androidx.compose.ui.unit.dp
19 | import androidx.compose.ui.unit.sp
20 |
21 | @OptIn(ExperimentalAnimationApi::class)
22 | @Composable
23 | fun ProgressButton(
24 | text: String,
25 | isLoading: Boolean,
26 | onClick: () -> Unit,
27 | modifier: Modifier = Modifier
28 | ) {
29 | Button(
30 | onClick = onClick,
31 | shape = RoundedCornerShape(50),
32 | colors = ButtonDefaults.outlinedButtonColors(backgroundColor = Color.Black,contentColor = Color.White),
33 | modifier = modifier
34 | ){
35 | AnimatedContent(targetState = isLoading) { isLoading ->
36 | if(isLoading) {
37 | CircularProgressIndicator(
38 | modifier = Modifier.size(24.dp),
39 | color = Color.White,
40 | strokeWidth = 2.dp
41 | )
42 | } else {
43 | Text(
44 | text = text,
45 | style = TextStyle(
46 | color = Color.White,
47 | fontSize = 16.sp
48 | )
49 | )
50 | }
51 | }
52 | }
53 | }
--------------------------------------------------------------------------------
/androidApp/build.gradle.kts:
--------------------------------------------------------------------------------
1 | plugins {
2 | id("com.android.application")
3 | kotlin("android")
4 | id("kotlin-kapt")
5 | id("dagger.hilt.android.plugin")
6 | kotlin("plugin.serialization") version Deps.kotlinVersion
7 | }
8 |
9 | android {
10 | namespace = "korsi.sher.android"
11 | compileSdk = 33
12 | defaultConfig {
13 | applicationId = "korsi.sher.android"
14 | minSdk = 24
15 | targetSdk = 33
16 | versionCode = 2
17 | versionName = "1.1"
18 | }
19 | buildFeatures {
20 | compose = true
21 | }
22 | composeOptions {
23 | kotlinCompilerExtensionVersion = Deps.composeVersion
24 | }
25 | packagingOptions {
26 | resources {
27 | excludes += "/META-INF/{AL2.0,LGPL2.1}"
28 | }
29 | }
30 | buildTypes {
31 | getByName("release") {
32 | isMinifyEnabled = false
33 | }
34 | }
35 | compileOptions {
36 | sourceCompatibility = JavaVersion.VERSION_1_8
37 | targetCompatibility = JavaVersion.VERSION_1_8
38 | }
39 | kotlinOptions {
40 | jvmTarget = "1.8"
41 | }
42 | }
43 |
44 | dependencies {
45 | implementation(project(":shared"))
46 | implementation(Deps.composeUi)
47 | implementation(Deps.composeUiTooling)
48 | implementation(Deps.composeUiToolingPreview)
49 | implementation(Deps.composeFoundation)
50 | implementation(Deps.composeMaterial)
51 | implementation(Deps.activityCompose)
52 | implementation(Deps.composeIconsExtended)
53 | implementation(Deps.composeNavigation)
54 | implementation(Deps.coilCompose)
55 |
56 | implementation(Deps.hiltAndroid)
57 | kapt(Deps.hiltAndroidCompiler)
58 | kapt(Deps.hiltCompiler)
59 | implementation(Deps.hiltNavigationCompose)
60 |
61 | implementation(Deps.ktorAndroid)
62 |
63 | androidTestImplementation(Deps.testRunner)
64 | androidTestImplementation(Deps.jUnit)
65 | androidTestImplementation(Deps.composeTesting)
66 | debugImplementation(Deps.composeTestManifest)
67 |
68 | kaptAndroidTest(Deps.hiltAndroidCompiler)
69 | androidTestImplementation(Deps.hiltTesting)
70 | }
--------------------------------------------------------------------------------
/androidApp/src/main/java/korsi/sher/android/di/AppModule.kt:
--------------------------------------------------------------------------------
1 | package korsi.sher.android.di
2 |
3 | import android.app.Application
4 | import com.squareup.sqldelight.db.SqlDriver
5 | import dagger.Module
6 | import dagger.Provides
7 | import dagger.hilt.InstallIn
8 | import dagger.hilt.components.SingletonComponent
9 | import io.ktor.client.*
10 | import korsi.sher.database.PoemDatabase
11 | import korsi.sher.poem.data.history.SqlDelightHistoryDataSource
12 | import korsi.sher.poem.data.local.DatabaseDriverFactory
13 | import korsi.sher.poem.data.poem.KtorPoemClient
14 | import korsi.sher.poem.data.remote.HttpClientFactory
15 | import korsi.sher.poem.domain.history.LikeUseCase
16 | import korsi.sher.poem.domain.history.PoemHistoryDataSource
17 | import korsi.sher.poem.domain.poem.PoemClient
18 | import korsi.sher.poem.domain.poem.PoemUseCase
19 | import javax.inject.Singleton
20 |
21 | @Module
22 | @InstallIn(SingletonComponent::class)
23 | class AppModule {
24 |
25 | @Provides
26 | @Singleton
27 | fun provideHttpClient(): HttpClient {
28 | return HttpClientFactory().create()
29 | }
30 |
31 | @Provides
32 | @Singleton
33 | fun providePoemClient(httpClient: HttpClient): PoemClient {
34 | return KtorPoemClient(httpClient)
35 | }
36 |
37 | @Provides
38 | @Singleton
39 | fun provideDatabaseDriver(app: Application): SqlDriver {
40 | return DatabaseDriverFactory(app).create()
41 | }
42 |
43 | @Provides
44 | @Singleton
45 | fun provideHistoryDataSource(sqlDriver: SqlDriver): PoemHistoryDataSource {
46 | return SqlDelightHistoryDataSource(PoemDatabase(sqlDriver))
47 | }
48 |
49 | @Provides
50 | @Singleton
51 | fun providePoemUseCase(
52 | poemClient: PoemClient,
53 | poemHistoryDataSource: PoemHistoryDataSource
54 | ): PoemUseCase {
55 | return PoemUseCase(
56 | poemClient = poemClient,
57 | poemHistoryDataSource = poemHistoryDataSource
58 | )
59 | }
60 |
61 | @Provides
62 | @Singleton
63 | fun provideLikeUseCase(
64 | poemHistoryDataSource: PoemHistoryDataSource
65 | ): LikeUseCase {
66 | return LikeUseCase(
67 | poemHistoryDataSource = poemHistoryDataSource
68 | )
69 | }
70 | }
--------------------------------------------------------------------------------
/iosApp/Pods/Pods.xcodeproj/xcuserdata/hamidrezasahraei.xcuserdatad/xcschemes/shared.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
43 |
44 |
50 |
51 |
53 |
54 |
57 |
58 |
59 |
--------------------------------------------------------------------------------
/iosApp/Pods/Pods.xcodeproj/xcuserdata/hamidrezasahraei.xcuserdatad/xcschemes/Pods-iosApp.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
43 |
44 |
50 |
51 |
53 |
54 |
57 |
58 |
59 |
--------------------------------------------------------------------------------
/iosApp/iosApp/like/presentation/LikeScreen.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LikeScreen.swift
3 | // iosApp
4 | //
5 | // Created by Hamidreza Sahraei on 7/2/23.
6 | // Copyright © 2023 orgName. All rights reserved.
7 | //
8 |
9 | import SwiftUI
10 | import shared
11 |
12 | struct LikeScreen: View {
13 |
14 | private var poemHistoryDataSource: PoemHistoryDataSource
15 | private var likeUseCase: LikeUseCase
16 |
17 | @ObservedObject var viewModel: IOSLikeViewModel
18 |
19 | init(poemHistoryDataSource: PoemHistoryDataSource, likeUseCase: LikeUseCase) {
20 | self.poemHistoryDataSource = poemHistoryDataSource
21 | self.likeUseCase = likeUseCase
22 | self.viewModel = IOSLikeViewModel(historyDataSource: poemHistoryDataSource, likeUseCase: likeUseCase)
23 | }
24 |
25 |
26 | var body: some View {
27 | let backgroundColor = Color(hex: viewModel.state.colors.first as! Int64)
28 | let textColor = Color(hex: viewModel.state.colors.second as! Int64)
29 |
30 | List {
31 | ForEach(viewModel.state.likedPoems, id: \.self) { poemItem in
32 | VStack(spacing: 16) {
33 | Text(poemItem.verse1)
34 | .font(.system(size: 20))
35 |
36 | Text(poemItem.verse2)
37 | .font(.system(size: 20))
38 |
39 | Text("« \(poemItem.poet) »")
40 | .font(.system(size: 16))
41 | }
42 | .padding() // Optional: To give some space between cell content and borders
43 | .background(backgroundColor)
44 | .listRowBackground(backgroundColor)
45 | .foregroundColor(textColor)
46 | .cornerRadius(20)
47 | .overlay(
48 | RoundedRectangle(cornerRadius: 20)
49 | .stroke(.white, lineWidth: 1)
50 | )
51 | .frame(maxWidth: .infinity)
52 | }
53 | }
54 | .listStyle(PlainListStyle()) // This removes default list styling
55 | .edgesIgnoringSafeArea(.horizontal) // This extends the content to the screen edges
56 | .onAppear {
57 | viewModel.startObserving()
58 | }
59 | .onDisappear {
60 | viewModel.dispose()
61 | }
62 | }
63 |
64 | }
65 |
--------------------------------------------------------------------------------
/androidApp/src/main/java/korsi/sher/android/like/presentation/LikeScreen.kt:
--------------------------------------------------------------------------------
1 | package korsi.sher.android.like.presentation
2 |
3 | import androidx.compose.foundation.background
4 | import androidx.compose.foundation.layout.Arrangement
5 | import androidx.compose.foundation.layout.fillMaxSize
6 | import androidx.compose.foundation.layout.padding
7 | import androidx.compose.foundation.lazy.LazyColumn
8 | import androidx.compose.material.Text
9 | import androidx.compose.runtime.Composable
10 | import androidx.compose.ui.Alignment
11 | import androidx.compose.ui.Modifier
12 | import androidx.compose.ui.graphics.Color
13 | import androidx.compose.ui.text.style.TextAlign
14 | import androidx.compose.ui.unit.dp
15 | import androidx.compose.ui.unit.sp
16 | import korsi.sher.android.core.presentation.components.PoemComponent
17 | import korsi.sher.poem.presentation.like.LikeEvent
18 | import korsi.sher.poem.presentation.like.LikeState
19 |
20 | @Composable
21 | fun LikeScreen(
22 | state: LikeState,
23 | onEvent: (LikeEvent) -> Unit
24 | ) {
25 | LazyColumn(
26 | verticalArrangement = Arrangement.spacedBy(8.dp),
27 | horizontalAlignment = Alignment.CenterHorizontally,
28 | modifier = Modifier
29 | .background(Color(state.colors.first))
30 | .padding(16.dp)
31 | .fillMaxSize()
32 | ) {
33 |
34 | if (state.likedPoems.isEmpty()) {
35 | item {
36 | Text(
37 | text = "هنوز هیچ کرسیشعری رو لایک نکردی، وقتی لایک کنی میان اینجا.",
38 | textAlign = TextAlign.Right,
39 | color = Color(state.colors.second),
40 | modifier = Modifier.padding(16.dp),
41 | fontSize = 16.sp
42 | )
43 | }
44 | } else {
45 | items(
46 | count = state.likedPoems.size,
47 | key = {
48 | state.likedPoems[it].id
49 | }
50 | ) {
51 | val poemItem = state.likedPoems[it]
52 | PoemComponent(
53 | verse1 = poemItem.verse1,
54 | verse2 = poemItem.verse2,
55 | poet = poemItem.poet,
56 | textColor = Color(state.colors.second),
57 | poemCopyText = poemItem.getTextForShare(),
58 | onFavoriteClicked = null,
59 | isLiked = true
60 | )
61 | }
62 |
63 | }
64 | }
65 | }
--------------------------------------------------------------------------------
/androidApp/src/main/java/korsi/sher/android/MainActivity.kt:
--------------------------------------------------------------------------------
1 | package korsi.sher.android
2 |
3 | import android.os.Bundle
4 | import androidx.activity.ComponentActivity
5 | import androidx.activity.compose.setContent
6 | import androidx.compose.foundation.layout.fillMaxSize
7 | import androidx.compose.material.*
8 | import androidx.compose.runtime.Composable
9 | import androidx.compose.runtime.collectAsState
10 | import androidx.compose.runtime.getValue
11 | import androidx.compose.ui.Modifier
12 | import androidx.hilt.navigation.compose.hiltViewModel
13 | import androidx.navigation.compose.NavHost
14 | import androidx.navigation.compose.composable
15 | import androidx.navigation.compose.rememberNavController
16 | import dagger.hilt.android.AndroidEntryPoint
17 | import korsi.sher.android.core.presentation.Routes
18 | import korsi.sher.android.like.presentation.AndroidLikeViewModel
19 | import korsi.sher.android.like.presentation.LikeScreen
20 | import korsi.sher.android.poem.presentation.AndroidPoemViewModel
21 | import korsi.sher.android.poem.presentation.PoemScreen
22 |
23 | @AndroidEntryPoint
24 | class MainActivity : ComponentActivity() {
25 | override fun onCreate(savedInstanceState: Bundle?) {
26 | super.onCreate(savedInstanceState)
27 | setContent {
28 | MyApplicationTheme {
29 | Surface(
30 | modifier = Modifier.fillMaxSize(),
31 | color = MaterialTheme.colors.background
32 | ) {
33 | PoemRoot()
34 | }
35 | }
36 | }
37 | }
38 | }
39 |
40 | @Composable
41 | fun PoemRoot() {
42 | val navController = rememberNavController()
43 | NavHost(
44 | navController = navController,
45 | startDestination = Routes.POEM
46 | ) {
47 | composable(route = Routes.POEM) {
48 | val viewModel = hiltViewModel()
49 | val state by viewModel.state.collectAsState()
50 | PoemScreen(
51 | state = state,
52 | onEvent = viewModel::onEvent,
53 | onLikedScreenClicked = {
54 | navController.navigate(Routes.LIKE)
55 | }
56 | )
57 | }
58 | composable(route = Routes.LIKE) {
59 | val viewModel = hiltViewModel()
60 | val state by viewModel.state.collectAsState()
61 | LikeScreen(
62 | state = state,
63 | onEvent = viewModel::onEvent
64 | )
65 | }
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @rem
2 | @rem Copyright 2015 the original author or authors.
3 | @rem
4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
5 | @rem you may not use this file except in compliance with the License.
6 | @rem You may obtain a copy of the License at
7 | @rem
8 | @rem https://www.apache.org/licenses/LICENSE-2.0
9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 |
17 | @if "%DEBUG%" == "" @echo off
18 | @rem ##########################################################################
19 | @rem
20 | @rem Gradle startup script for Windows
21 | @rem
22 | @rem ##########################################################################
23 |
24 | @rem Set local scope for the variables with windows NT shell
25 | if "%OS%"=="Windows_NT" setlocal
26 |
27 | set DIRNAME=%~dp0
28 | if "%DIRNAME%" == "" set DIRNAME=.
29 | set APP_BASE_NAME=%~n0
30 | set APP_HOME=%DIRNAME%
31 |
32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter.
33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
34 |
35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
37 |
38 | @rem Find java.exe
39 | if defined JAVA_HOME goto findJavaFromJavaHome
40 |
41 | set JAVA_EXE=java.exe
42 | %JAVA_EXE% -version >NUL 2>&1
43 | if "%ERRORLEVEL%" == "0" goto execute
44 |
45 | echo.
46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
47 | echo.
48 | echo Please set the JAVA_HOME variable in your environment to match the
49 | echo location of your Java installation.
50 |
51 | goto fail
52 |
53 | :findJavaFromJavaHome
54 | set JAVA_HOME=%JAVA_HOME:"=%
55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
56 |
57 | if exist "%JAVA_EXE%" goto execute
58 |
59 | echo.
60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
61 | echo.
62 | echo Please set the JAVA_HOME variable in your environment to match the
63 | echo location of your Java installation.
64 |
65 | goto fail
66 |
67 | :execute
68 | @rem Setup the command line
69 |
70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
71 |
72 |
73 | @rem Execute Gradle
74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
75 |
76 | :end
77 | @rem End local scope for the variables with windows NT shell
78 | if "%ERRORLEVEL%"=="0" goto mainEnd
79 |
80 | :fail
81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
82 | rem the _cmd.exe /c_ return code!
83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
84 | exit /b 1
85 |
86 | :mainEnd
87 | if "%OS%"=="Windows_NT" endlocal
88 |
89 | :omega
90 |
--------------------------------------------------------------------------------
/shared/build.gradle.kts:
--------------------------------------------------------------------------------
1 | plugins {
2 | kotlin("multiplatform")
3 | kotlin("native.cocoapods")
4 | id("com.android.library")
5 | kotlin("plugin.serialization") version Deps.kotlinVersion
6 | id("com.squareup.sqldelight")
7 | }
8 |
9 | kotlin {
10 | android {
11 | compilations.all {
12 | kotlinOptions {
13 | jvmTarget = "1.8"
14 | }
15 | }
16 | }
17 | iosX64()
18 | iosArm64()
19 | iosSimulatorArm64()
20 |
21 | cocoapods {
22 | summary = "Some description for the Shared Module"
23 | homepage = "Link to the Shared Module homepage"
24 | version = "1.1"
25 | ios.deploymentTarget = "14.1"
26 | podfile = project.file("../iosApp/Podfile")
27 | framework {
28 | isStatic = false
29 | baseName = "shared"
30 | }
31 | }
32 |
33 | sourceSets {
34 | val commonMain by getting {
35 | dependencies {
36 | implementation(Deps.ktorCore)
37 | implementation(Deps.ktorSerialization)
38 | implementation(Deps.ktorSerializationJson)
39 | implementation(Deps.sqlDelightRuntime)
40 | implementation(Deps.sqlDelightCoroutinesExtensions)
41 | implementation(Deps.kotlinDateTime)
42 | }
43 | }
44 | val commonTest by getting {
45 | dependencies {
46 | implementation(kotlin("test"))
47 | implementation(Deps.assertK)
48 | implementation(Deps.turbine)
49 | }
50 | }
51 | val androidMain by getting {
52 | dependencies {
53 | implementation(Deps.ktorAndroid)
54 | implementation(Deps.sqlDelightAndroidDriver)
55 | }
56 | }
57 | val iosX64Main by getting
58 | val iosArm64Main by getting
59 | val iosSimulatorArm64Main by getting
60 | val iosMain by creating {
61 | dependsOn(commonMain)
62 | iosX64Main.dependsOn(this)
63 | iosArm64Main.dependsOn(this)
64 | iosSimulatorArm64Main.dependsOn(this)
65 |
66 | dependencies {
67 | implementation(Deps.ktorIOS)
68 | implementation(Deps.sqlDelightNativeDriver)
69 | }
70 | }
71 | val iosX64Test by getting
72 | val iosArm64Test by getting
73 | val iosSimulatorArm64Test by getting
74 | val iosTest by creating {
75 | dependsOn(commonTest)
76 | iosX64Test.dependsOn(this)
77 | iosArm64Test.dependsOn(this)
78 | iosSimulatorArm64Test.dependsOn(this)
79 | }
80 | }
81 | }
82 |
83 | android {
84 | namespace = "korsi.sher"
85 | compileSdk = 33
86 | defaultConfig {
87 | minSdk = 24
88 | }
89 | }
90 |
91 | sqldelight {
92 | database("PoemDatabase") {
93 | packageName = "korsi.sher.database"
94 | sourceFolders = listOf("sqldelight")
95 | }
96 | }
--------------------------------------------------------------------------------
/shared/src/commonMain/kotlin/korsi/sher/poem/presentation/like/LikeViewModel.kt:
--------------------------------------------------------------------------------
1 | package korsi.sher.poem.presentation.like
2 |
3 | import korsi.sher.core.domain.util.Resource
4 | import korsi.sher.core.domain.util.toCommonStateFlow
5 | import korsi.sher.poem.domain.history.LikeUseCase
6 | import korsi.sher.poem.domain.history.PoemHistoryDataSource
7 | import korsi.sher.poem.domain.history.PoemItem
8 | import korsi.sher.poem.domain.poem.PoemException
9 | import korsi.sher.poem.presentation.util.generateRandomColors
10 | import kotlinx.coroutines.CoroutineScope
11 | import kotlinx.coroutines.Dispatchers
12 | import kotlinx.coroutines.flow.MutableStateFlow
13 | import kotlinx.coroutines.flow.SharingStarted
14 | import kotlinx.coroutines.flow.combine
15 | import kotlinx.coroutines.flow.stateIn
16 | import kotlinx.coroutines.flow.update
17 | import kotlinx.coroutines.launch
18 |
19 | class LikeViewModel(
20 | private val likeUseCase: LikeUseCase,
21 | private val poemHistoryDataSource: PoemHistoryDataSource,
22 | private val coroutineScope: CoroutineScope?
23 | ) {
24 |
25 | private val viewModelScope = coroutineScope ?: CoroutineScope(Dispatchers.Main)
26 |
27 | private val _state = MutableStateFlow(LikeState())
28 | val state = combine(
29 | _state,
30 | poemHistoryDataSource.getHistory()
31 | ) { state, likedPoems ->
32 | if (state.likedPoems != likedPoems) {
33 | state.copy(
34 | likedPoems = likedPoems,
35 | colors = generateRandomColors()
36 | )
37 | } else state
38 | }.stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), LikeState())
39 | .toCommonStateFlow()
40 |
41 | fun onEvent(event: LikeEvent) {
42 | when (event) {
43 | LikeEvent.OnErrorSeen -> {
44 | _state.update {
45 | it.copy(
46 | error = null
47 | )
48 | }
49 | }
50 | is LikeEvent.SharePoem -> TODO()
51 | }
52 | }
53 |
54 | private fun unLikePoem(poemItem: PoemItem) {
55 | if (state.value.isLoading) {
56 | return
57 | }
58 | viewModelScope.launch {
59 | _state.update {
60 | it.copy(
61 | isLoading = true
62 | )
63 | }
64 | when (val result = likeUseCase.execute(poemItem)) {
65 | is Resource.Success -> {
66 | _state.update {
67 | it.copy(
68 | isLoading = false,
69 | colors = generateRandomColors()
70 | )
71 | }
72 | }
73 | is Resource.Error -> {
74 | _state.update {
75 | it.copy(
76 | isLoading = false,
77 | error = (result.throwable as? PoemException)?.error
78 | )
79 | }
80 | }
81 | }
82 | }
83 | }
84 | }
--------------------------------------------------------------------------------
/Readme.md:
--------------------------------------------------------------------------------
1 | # KorsiSher 📜
2 |
3 | KorsiSher brings the enchanting world of Persian poetry right to your fingertips. Dive into a vast collection of random Persian poems, save your favorites, and share them with the world. Crafted meticulously with modern technologies for both Android and iOS platforms.
4 |
5 | ## Features ✨
6 |
7 | - **Discover Random Poems**: Stumble upon beautiful Persian poems from various poets every time you launch the app.
8 | - **Favorites**: Found a poem that resonates with your soul? Save it to your favorites for easy access.
9 | - **Sharing**: Share the beauty of Persian poetry with your friends and family with just a click.
10 |
11 | ## Challenges & Solutions 🧠
12 |
13 | Building KorsiSher was not only about delivering Persian poetry to users but also navigating through various technical challenges:
14 |
15 | 1. **Dependency Injection Across Platforms**:
16 | - **Android**: Used Hilt for DI, maximizing its seamless integration and scalability.
17 | - **iOS**: Crafted a pattern to mirror Hilt's functionality in iOS, ensuring consistent DI across platforms.
18 |
19 | 2. **Database Management**:
20 | - **Android**: Employed Room for a robust SQLite object mapping experience.
21 | - **iOS**: Integrated SqlDelight, facilitating smooth database interactions and shared SQL code.
22 |
23 | 3. **Unified Business Logic**:
24 | - Aiming to share as much business logic as possible, including ViewModels. With Android ViewModel offering distinct advantages, adapting this logic to iOS posed challenges and required thoughtful solutions.
25 |
26 | 4. **Kotlin Asynchrony & iOS**:
27 | - Kotlin's Flow and Coroutine are go-to tools for asynchronous tasks on Android. To utilize these on iOS, we designed custom wrappers ensuring smooth asynchronous operations on both platforms.
28 |
29 | 5. **Cross-platform Networking with Ktor**:
30 | - Implementing Ktor for networking was a significant step in maintaining consistent data interactions between Android and iOS. It required a deep understanding and adjustments to address platform-specific nuances.
31 |
32 | ## Built With 🛠️
33 |
34 | - **Kotlin Multiplatform**: Shared business logic across Android and iOS, ensuring consistent behavior and minimized code duplication.
35 | - **Android**:
36 | - Jetpack Compose for a contemporary UI.
37 | - Hilt for dependency injection.
38 | - Clean Architecture for a structured, maintainable framework.
39 | - **iOS**:
40 | - SwiftUI for a native and fluid UI experience.
41 |
42 | ## Screenshots 📱
43 |
44 | | Android Main Screen | iOS Main Screen | Favorites Screen |
45 | |--------------------|-------------------|------------------|
46 | |  |  |  |
47 |
48 | ## Installation 📥
49 |
50 | ### Android:
51 |
52 | 1. Download from Play Store [PlayStore](https://play.google.com/store/apps/details?id=korsi.sher.android&hl=en&gl=US).
53 |
54 | ### iOS:
55 |
56 | 1. Coming Soon...
57 |
58 | ## Contribution 🤝
59 |
60 | Contributions from the community are always welcome. Be it a bug fix, feature enhancement, or documentation update, we value your input! Dive into our [Contribution Guide](link_to_contributing.md) to get started.
61 |
62 | ## License 📄
63 |
64 | This project is under the MIT License. Refer to the [LICENSE.md](link_to_license.md) file for more details.
65 |
66 | ## Acknowledgments 🙏
67 |
68 | - To the poets who've enriched our world with their beautiful words.
69 | - Special tnx to [Ganjoor](https://ganjoor.net/) for random poem API.
--------------------------------------------------------------------------------
/shared/src/commonMain/kotlin/korsi/sher/poem/presentation/poem/PoemViewModel.kt:
--------------------------------------------------------------------------------
1 | package korsi.sher.poem.presentation.poem
2 |
3 | import korsi.sher.core.domain.util.Resource
4 | import korsi.sher.core.domain.util.toCommonStateFlow
5 | import korsi.sher.poem.domain.history.LikeUseCase
6 | import korsi.sher.poem.domain.history.PoemHistoryDataSource
7 | import korsi.sher.poem.domain.history.PoemItem
8 | import korsi.sher.poem.domain.poem.PoemException
9 | import korsi.sher.poem.domain.poem.PoemUseCase
10 | import korsi.sher.poem.presentation.util.generateRandomColors
11 | import kotlinx.coroutines.CoroutineScope
12 | import kotlinx.coroutines.Dispatchers
13 | import kotlinx.coroutines.flow.MutableStateFlow
14 | import kotlinx.coroutines.flow.SharingStarted
15 | import kotlinx.coroutines.flow.combine
16 | import kotlinx.coroutines.flow.stateIn
17 | import kotlinx.coroutines.flow.update
18 | import kotlinx.coroutines.launch
19 |
20 | class PoemViewModel(
21 | private val poemUseCase: PoemUseCase,
22 | private val likeUseCase: LikeUseCase,
23 | private val poemHistoryDataSource: PoemHistoryDataSource,
24 | private val coroutineScope: CoroutineScope?
25 | ) {
26 |
27 | private val viewModelScope = coroutineScope ?: CoroutineScope(Dispatchers.Main)
28 |
29 | private val _state = MutableStateFlow(PoemState())
30 | val state = combine(
31 | _state,
32 | poemHistoryDataSource.getHistory()
33 | ) { state, history ->
34 | if (state.history != history) {
35 | state.copy(
36 | poemItem = state.poemItem?.copy(
37 | isLiked = history.any { it.id == state.poemItem.id }
38 | ),
39 | history = history
40 | )
41 | } else state
42 | }.stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), PoemState())
43 | .toCommonStateFlow()
44 |
45 | fun onEvent(event: PoemEvent) {
46 | when(event) {
47 | PoemEvent.OnErrorSeen -> {
48 | _state.update {
49 | it.copy(
50 | isLoading = true
51 | )
52 | }
53 | }
54 | PoemEvent.RandomPoem -> {
55 | randomPoem()
56 | }
57 | is PoemEvent.SharePoem -> {
58 | TODO()
59 | }
60 | is PoemEvent.LikePoem -> {
61 | likePoem(event.poem)
62 | }
63 | }
64 | }
65 |
66 | private fun randomPoem() {
67 | if (state.value.isLoading) {
68 | return
69 | }
70 | viewModelScope.launch {
71 | _state.update {
72 | it.copy(
73 | isLoading = true
74 | )
75 | }
76 | when (val result = poemUseCase.execute()) {
77 | is Resource.Success -> {
78 | _state.update {
79 | it.copy(
80 | isLoading = false,
81 | poemItem = result.data,
82 | colors = generateRandomColors()
83 | )
84 | }
85 | }
86 | is Resource.Error -> {
87 | _state.update {
88 | it.copy(
89 | isLoading = false,
90 | error = (result.throwable as? PoemException)?.error
91 | )
92 | }
93 | }
94 | }
95 | }
96 | }
97 |
98 | private fun likePoem(poemItem: PoemItem) {
99 | if (state.value.isLoading) {
100 | return
101 | }
102 | viewModelScope.launch {
103 | likeUseCase.execute(poemItem)
104 | }
105 | }
106 |
107 | }
--------------------------------------------------------------------------------
/androidApp/src/main/java/korsi/sher/android/poem/presentation/PoemScreen.kt:
--------------------------------------------------------------------------------
1 | package korsi.sher.android.poem.presentation
2 |
3 | import android.widget.Toast
4 | import androidx.compose.foundation.background
5 | import androidx.compose.foundation.layout.Arrangement
6 | import androidx.compose.foundation.layout.Column
7 | import androidx.compose.foundation.layout.Spacer
8 | import androidx.compose.foundation.layout.fillMaxSize
9 | import androidx.compose.foundation.layout.padding
10 | import androidx.compose.foundation.layout.size
11 | import androidx.compose.foundation.shape.RoundedCornerShape
12 | import androidx.compose.material.Button
13 | import androidx.compose.material.ButtonDefaults
14 | import androidx.compose.material.Text
15 | import androidx.compose.runtime.Composable
16 | import androidx.compose.runtime.getValue
17 | import androidx.compose.runtime.mutableStateOf
18 | import androidx.compose.runtime.remember
19 | import androidx.compose.runtime.setValue
20 | import androidx.compose.ui.Alignment
21 | import androidx.compose.ui.Modifier
22 | import androidx.compose.ui.graphics.Color
23 | import androidx.compose.ui.platform.ClipboardManager
24 | import androidx.compose.ui.platform.LocalClipboardManager
25 | import androidx.compose.ui.platform.LocalContext
26 | import androidx.compose.ui.text.AnnotatedString
27 | import androidx.compose.ui.text.TextStyle
28 | import androidx.compose.ui.text.style.TextAlign
29 | import androidx.compose.ui.unit.dp
30 | import androidx.compose.ui.unit.sp
31 | import korsi.sher.android.core.presentation.components.PoemComponent
32 | import korsi.sher.android.poem.presentation.components.ProgressButton
33 | import korsi.sher.poem.presentation.poem.PoemEvent
34 | import korsi.sher.poem.presentation.poem.PoemState
35 |
36 | @Composable
37 | fun PoemScreen(
38 | state: PoemState,
39 | onEvent: (PoemEvent) -> Unit,
40 | onLikedScreenClicked: () -> Unit
41 | ) {
42 | Column(
43 | verticalArrangement = Arrangement.Center,
44 | horizontalAlignment = Alignment.CenterHorizontally,
45 | modifier = Modifier
46 | .background(Color(state.colors.first))
47 | .padding(16.dp)
48 | .fillMaxSize()
49 | ) {
50 |
51 | if (state.poemItem == null) {
52 | Text(
53 | text = "در قدیم در منطقه (طالقان)، مردان دور کرسی جمع می شدند و مشاعره می کردند.. بعد از چند دور که اشعار در ذهن کم می شد، بعضی از خودشان شعر می گفتند! دیگران می گفتند که فلانی کرسی شعر گفت! (در لفظ: برو بابا بازم کرسی شعر گفتی)",
54 | textAlign = TextAlign.Right,
55 | color = Color(state.colors.second),
56 | modifier = Modifier.padding(16.dp),
57 | fontSize = 16.sp
58 | )
59 | } else {
60 | state.poemItem?.let {
61 | PoemComponent(
62 | verse1 = it.verse1,
63 | verse2 = it.verse2,
64 | poet = it.poet,
65 | isLiked = it.isLiked,
66 | textColor = Color(state.colors.second),
67 | poemCopyText = it.getTextForShare(),
68 | onFavoriteClicked = {
69 | onEvent(PoemEvent.LikePoem(it))
70 | }
71 | )
72 | }
73 | }
74 | Spacer(modifier = Modifier.size(16.dp))
75 |
76 | ProgressButton(
77 | text = "📝 یه بیت دیگه بگو",
78 | isLoading = state.isLoading,
79 | onClick = { onEvent(PoemEvent.RandomPoem) }
80 | )
81 | Button(
82 | onClick = {
83 | onLikedScreenClicked()
84 | },
85 | shape = RoundedCornerShape(50),
86 | colors = ButtonDefaults.outlinedButtonColors(backgroundColor = Color.DarkGray,contentColor = Color.White)
87 | ){
88 | Text(
89 | text = "❤️ قلبیشدهها ",
90 | style = TextStyle(
91 | color = Color.White,
92 | fontSize = 14.sp
93 | )
94 | )
95 | }
96 | }
97 | }
--------------------------------------------------------------------------------
/androidApp/src/main/java/korsi/sher/android/core/presentation/components/PoemComponent.kt:
--------------------------------------------------------------------------------
1 | package korsi.sher.android.core.presentation.components
2 |
3 | import android.widget.Toast
4 | import androidx.compose.foundation.border
5 | import androidx.compose.foundation.clickable
6 | import androidx.compose.foundation.interaction.MutableInteractionSource
7 | import androidx.compose.foundation.layout.Arrangement
8 | import androidx.compose.foundation.layout.Column
9 | import androidx.compose.foundation.layout.Row
10 | import androidx.compose.foundation.layout.Spacer
11 | import androidx.compose.foundation.layout.padding
12 | import androidx.compose.foundation.layout.size
13 | import androidx.compose.foundation.shape.RoundedCornerShape
14 | import androidx.compose.material.Icon
15 | import androidx.compose.material.IconButton
16 | import androidx.compose.material.IconToggleButton
17 | import androidx.compose.material.Text
18 | import androidx.compose.material.icons.Icons
19 | import androidx.compose.material.icons.filled.ContentCopy
20 | import androidx.compose.material.icons.filled.Favorite
21 | import androidx.compose.material.icons.filled.FavoriteBorder
22 | import androidx.compose.runtime.Composable
23 | import androidx.compose.runtime.getValue
24 | import androidx.compose.runtime.mutableStateOf
25 | import androidx.compose.runtime.remember
26 | import androidx.compose.runtime.setValue
27 | import androidx.compose.ui.Alignment
28 | import androidx.compose.ui.Modifier
29 | import androidx.compose.ui.graphics.Color
30 | import androidx.compose.ui.platform.ClipboardManager
31 | import androidx.compose.ui.platform.LocalClipboardManager
32 | import androidx.compose.ui.platform.LocalContext
33 | import androidx.compose.ui.text.AnnotatedString
34 | import androidx.compose.ui.unit.dp
35 | import androidx.compose.ui.unit.sp
36 |
37 | @Composable
38 | fun PoemComponent(
39 | verse1: String,
40 | verse2: String,
41 | poet: String,
42 | isLiked: Boolean,
43 | textColor: Color,
44 | poemCopyText: String,
45 | onFavoriteClicked: (() -> Unit)?
46 | ) {
47 | val context = LocalContext.current
48 | val clipboardManager: ClipboardManager = LocalClipboardManager.current
49 |
50 | // this is used to disable the ripple effect
51 | val interactionSource = remember {
52 | MutableInteractionSource()
53 | }
54 | Column(
55 | verticalArrangement = Arrangement.Center,
56 | horizontalAlignment = Alignment.CenterHorizontally,
57 | modifier = Modifier
58 | .border(width = 1.dp, color = Color.White, shape = RoundedCornerShape(8.dp))
59 | .padding(32.dp)
60 |
61 | ) {
62 | Text(
63 | text = verse1,
64 | color = textColor,
65 | fontSize = 20.sp
66 | )
67 | Spacer(modifier = Modifier.size(16.dp))
68 | Text(
69 | text = verse2,
70 | color = textColor,
71 | fontSize = 20.sp
72 | )
73 | Spacer(modifier = Modifier.size(16.dp))
74 | Text(
75 | text = "« $poet »",
76 | color = textColor,
77 | fontSize = 16.sp
78 | )
79 |
80 | Spacer(modifier = Modifier.size(32.dp))
81 |
82 | Row {
83 | IconButton(
84 | onClick = {
85 | clipboardManager.setText(AnnotatedString(poemCopyText))
86 | Toast.makeText(context, "کپی شد :)", Toast.LENGTH_SHORT).show()
87 | }
88 | ) {
89 | Icon(
90 | imageVector = Icons.Default.ContentCopy,
91 | contentDescription = "Copy Poem",
92 | tint = Color.White
93 | )
94 | }
95 | if (onFavoriteClicked != null) {
96 | Spacer(modifier = Modifier.size(8.dp))
97 |
98 |
99 | Spacer(modifier = Modifier.size(8.dp))
100 |
101 | IconToggleButton(
102 | checked = isLiked,
103 | onCheckedChange = {
104 | }
105 | ) {
106 | Icon(
107 | imageVector = if (isLiked) Icons.Default.Favorite else Icons.Default.FavoriteBorder,
108 | contentDescription = "Favorite Item",
109 | modifier = Modifier
110 | .clickable(
111 | indication = null, // assign null to disable the ripple effect
112 | interactionSource = interactionSource
113 | ) {
114 | onFavoriteClicked()
115 | }
116 | .size(24.dp),
117 | tint = if (isLiked) Color.Red else Color.White
118 | )
119 | }
120 | }
121 | }
122 | }
123 | }
--------------------------------------------------------------------------------
/iosApp/iosApp/poem/presentation/PoemScreen.swift:
--------------------------------------------------------------------------------
1 | //
2 | // PoemScreen.swift
3 | // iosApp
4 | //
5 | // Created by Hamidreza Sahraei on 7/2/23.
6 | // Copyright © 2023 orgName. All rights reserved.
7 | //
8 |
9 | import SwiftUI
10 | import shared
11 |
12 | struct PoemScreen: View {
13 |
14 | private var poemHistoryDataSource: PoemHistoryDataSource
15 | private var poemUseCase: PoemUseCase
16 | private var likeUseCase: LikeUseCase
17 | @ObservedObject var viewModel: IOSPoemViewModel
18 |
19 | private let appModule = AppModule()
20 |
21 | @State private var showCopyAlert = false
22 |
23 | init(poemHistoryDataSource: PoemHistoryDataSource, poemUseCase: PoemUseCase, likeUseCase: LikeUseCase) {
24 | self.poemHistoryDataSource = poemHistoryDataSource
25 | self.poemUseCase = poemUseCase
26 | self.likeUseCase = likeUseCase
27 | self.viewModel = IOSPoemViewModel(historyDataSource: poemHistoryDataSource, poemUseCase: poemUseCase, likeUseCase: likeUseCase)
28 | }
29 |
30 | var body: some View {
31 | let backgroundColor = Color(hex: viewModel.state.colors.first as! Int64)
32 | let textColor = Color(hex: viewModel.state.colors.second as! Int64)
33 | let liked = viewModel.state.poemItem?.isLiked ?? false
34 |
35 | VStack {
36 | if viewModel.state.poemItem == nil {
37 | Text("در قدیم در منطقه (طالقان)، مردان دور کرسی جمع می شدند و مشاعره می کردند.. بعد از چند دور که اشعار در ذهن کم می شد، بعضی از خودشان شعر می گفتند! دیگران می گفتند که فلانی کرسی شعر گفت! (در لفظ: برو بابا بازم کرسی شعر گفتی)")
38 | .multilineTextAlignment(.trailing)
39 | .foregroundColor(textColor)
40 | .padding()
41 | .font(.system(size: 16))
42 | } else {
43 | if let poemItem = viewModel.state.poemItem {
44 | VStack(spacing: 16) {
45 | Text(poemItem.verse1)
46 | .foregroundColor(textColor)
47 | .font(.system(size: 20))
48 |
49 | Text(poemItem.verse2)
50 | .foregroundColor(textColor)
51 | .font(.system(size: 20))
52 |
53 | Text("« \(poemItem.poet) »")
54 | .foregroundColor(textColor)
55 | .font(.system(size: 16))
56 | HStack(spacing: 16) {
57 | Button(action: {
58 | copyToClipboard(text: poemItem.getTextForShare())
59 | showCopyAlert = true
60 | }
61 | ) {
62 | Image(systemName: "square.and.pencil")
63 | .resizable()
64 | .frame(width: 18, height: 18)
65 | .foregroundColor(.white)
66 | }
67 | .padding()
68 | .alert(isPresented: $showCopyAlert) {
69 | Alert(title: Text("کپی شد!"), message: Text("شعر رو می تونی هرجا میخوای پیست کنی!"), dismissButton: .default(Text("باشه")))
70 | }
71 | Button(action: {
72 | if let poemItem = viewModel.state.poemItem {
73 | viewModel.onEvent(event: PoemEvent.LikePoem(poem: poemItem))
74 | }
75 | }
76 | ) {
77 | Image(systemName: liked ? "heart.fill" : "heart")
78 | .resizable()
79 | .frame(width: 18, height: 18)
80 | .foregroundColor(.white)
81 | }
82 | .padding()
83 | }
84 | }
85 | .padding()
86 | .cornerRadius(20)
87 | .overlay(
88 | RoundedRectangle(cornerRadius: 20)
89 | .stroke(.white, lineWidth: 1)
90 | )
91 | }
92 | }
93 |
94 | ProgressButton(text: "یه بیت دیگه بگو 📝",
95 | isLoading: viewModel.state.isLoading,
96 | onClick: { viewModel.onEvent(event: PoemEvent.RandomPoem())})
97 | .foregroundColor(Color.white)
98 | .padding()
99 |
100 | NavigationLink(destination: LikeScreen(poemHistoryDataSource: poemHistoryDataSource, likeUseCase: likeUseCase)) {
101 | Text("قلبی شدهها ❤️")
102 | .padding(.horizontal)
103 | .padding(.vertical, 5)
104 | .background(Color(hex: 0xFF444444))
105 | .foregroundColor(.white)
106 | .cornerRadius(100)
107 | }
108 | }
109 | .frame(maxWidth: .infinity, maxHeight: .infinity)
110 | .background(backgroundColor)
111 | .onAppear {
112 | viewModel.startObserving()
113 | }
114 | .onDisappear {
115 | viewModel.dispose()
116 | }
117 | }
118 |
119 | func copyToClipboard(text: String) {
120 | UIPasteboard.general.string = text
121 | }
122 | }
123 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | #
4 | # Copyright 2015 the original author or authors.
5 | #
6 | # Licensed under the Apache License, Version 2.0 (the "License");
7 | # you may not use this file except in compliance with the License.
8 | # You may obtain a copy of the License at
9 | #
10 | # https://www.apache.org/licenses/LICENSE-2.0
11 | #
12 | # Unless required by applicable law or agreed to in writing, software
13 | # distributed under the License is distributed on an "AS IS" BASIS,
14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | # See the License for the specific language governing permissions and
16 | # limitations under the License.
17 | #
18 |
19 | ##############################################################################
20 | ##
21 | ## Gradle start up script for UN*X
22 | ##
23 | ##############################################################################
24 |
25 | # Attempt to set APP_HOME
26 | # Resolve links: $0 may be a link
27 | PRG="$0"
28 | # Need this for relative symlinks.
29 | while [ -h "$PRG" ] ; do
30 | ls=`ls -ld "$PRG"`
31 | link=`expr "$ls" : '.*-> \(.*\)$'`
32 | if expr "$link" : '/.*' > /dev/null; then
33 | PRG="$link"
34 | else
35 | PRG=`dirname "$PRG"`"/$link"
36 | fi
37 | done
38 | SAVED="`pwd`"
39 | cd "`dirname \"$PRG\"`/" >/dev/null
40 | APP_HOME="`pwd -P`"
41 | cd "$SAVED" >/dev/null
42 |
43 | APP_NAME="Gradle"
44 | APP_BASE_NAME=`basename "$0"`
45 |
46 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
47 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
48 |
49 | # Use the maximum available, or set MAX_FD != -1 to use that value.
50 | MAX_FD="maximum"
51 |
52 | warn () {
53 | echo "$*"
54 | }
55 |
56 | die () {
57 | echo
58 | echo "$*"
59 | echo
60 | exit 1
61 | }
62 |
63 | # OS specific support (must be 'true' or 'false').
64 | cygwin=false
65 | msys=false
66 | darwin=false
67 | nonstop=false
68 | case "`uname`" in
69 | CYGWIN* )
70 | cygwin=true
71 | ;;
72 | Darwin* )
73 | darwin=true
74 | ;;
75 | MINGW* )
76 | msys=true
77 | ;;
78 | NONSTOP* )
79 | nonstop=true
80 | ;;
81 | esac
82 |
83 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
84 |
85 |
86 | # Determine the Java command to use to start the JVM.
87 | if [ -n "$JAVA_HOME" ] ; then
88 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
89 | # IBM's JDK on AIX uses strange locations for the executables
90 | JAVACMD="$JAVA_HOME/jre/sh/java"
91 | else
92 | JAVACMD="$JAVA_HOME/bin/java"
93 | fi
94 | if [ ! -x "$JAVACMD" ] ; then
95 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
96 |
97 | Please set the JAVA_HOME variable in your environment to match the
98 | location of your Java installation."
99 | fi
100 | else
101 | JAVACMD="java"
102 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
103 |
104 | Please set the JAVA_HOME variable in your environment to match the
105 | location of your Java installation."
106 | fi
107 |
108 | # Increase the maximum file descriptors if we can.
109 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
110 | MAX_FD_LIMIT=`ulimit -H -n`
111 | if [ $? -eq 0 ] ; then
112 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
113 | MAX_FD="$MAX_FD_LIMIT"
114 | fi
115 | ulimit -n $MAX_FD
116 | if [ $? -ne 0 ] ; then
117 | warn "Could not set maximum file descriptor limit: $MAX_FD"
118 | fi
119 | else
120 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
121 | fi
122 | fi
123 |
124 | # For Darwin, add options to specify how the application appears in the dock
125 | if $darwin; then
126 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
127 | fi
128 |
129 | # For Cygwin or MSYS, switch paths to Windows format before running java
130 | if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
131 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
132 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
133 |
134 | JAVACMD=`cygpath --unix "$JAVACMD"`
135 |
136 | # We build the pattern for arguments to be converted via cygpath
137 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
138 | SEP=""
139 | for dir in $ROOTDIRSRAW ; do
140 | ROOTDIRS="$ROOTDIRS$SEP$dir"
141 | SEP="|"
142 | done
143 | OURCYGPATTERN="(^($ROOTDIRS))"
144 | # Add a user-defined pattern to the cygpath arguments
145 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
146 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
147 | fi
148 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
149 | i=0
150 | for arg in "$@" ; do
151 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
152 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
153 |
154 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
155 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
156 | else
157 | eval `echo args$i`="\"$arg\""
158 | fi
159 | i=`expr $i + 1`
160 | done
161 | case $i in
162 | 0) set -- ;;
163 | 1) set -- "$args0" ;;
164 | 2) set -- "$args0" "$args1" ;;
165 | 3) set -- "$args0" "$args1" "$args2" ;;
166 | 4) set -- "$args0" "$args1" "$args2" "$args3" ;;
167 | 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
168 | 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
169 | 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
170 | 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
171 | 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
172 | esac
173 | fi
174 |
175 | # Escape application args
176 | save () {
177 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
178 | echo " "
179 | }
180 | APP_ARGS=`save "$@"`
181 |
182 | # Collect all arguments for the java command, following the shell quoting and substitution rules
183 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
184 |
185 | exec "$JAVACMD" "$@"
186 |
--------------------------------------------------------------------------------
/iosApp/Pods/Target Support Files/Pods-iosApp/Pods-iosApp-frameworks.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | set -e
3 | set -u
4 | set -o pipefail
5 |
6 | function on_error {
7 | echo "$(realpath -mq "${0}"):$1: error: Unexpected failure"
8 | }
9 | trap 'on_error $LINENO' ERR
10 |
11 | if [ -z ${FRAMEWORKS_FOLDER_PATH+x} ]; then
12 | # If FRAMEWORKS_FOLDER_PATH is not set, then there's nowhere for us to copy
13 | # frameworks to, so exit 0 (signalling the script phase was successful).
14 | exit 0
15 | fi
16 |
17 | echo "mkdir -p ${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
18 | mkdir -p "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
19 |
20 | COCOAPODS_PARALLEL_CODE_SIGN="${COCOAPODS_PARALLEL_CODE_SIGN:-false}"
21 | SWIFT_STDLIB_PATH="${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}"
22 | BCSYMBOLMAP_DIR="BCSymbolMaps"
23 |
24 |
25 | # This protects against multiple targets copying the same framework dependency at the same time. The solution
26 | # was originally proposed here: https://lists.samba.org/archive/rsync/2008-February/020158.html
27 | RSYNC_PROTECT_TMP_FILES=(--filter "P .*.??????")
28 |
29 | # Copies and strips a vendored framework
30 | install_framework()
31 | {
32 | if [ -r "${BUILT_PRODUCTS_DIR}/$1" ]; then
33 | local source="${BUILT_PRODUCTS_DIR}/$1"
34 | elif [ -r "${BUILT_PRODUCTS_DIR}/$(basename "$1")" ]; then
35 | local source="${BUILT_PRODUCTS_DIR}/$(basename "$1")"
36 | elif [ -r "$1" ]; then
37 | local source="$1"
38 | fi
39 |
40 | local destination="${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
41 |
42 | if [ -L "${source}" ]; then
43 | echo "Symlinked..."
44 | source="$(readlink -f "${source}")"
45 | fi
46 |
47 | if [ -d "${source}/${BCSYMBOLMAP_DIR}" ]; then
48 | # Locate and install any .bcsymbolmaps if present, and remove them from the .framework before the framework is copied
49 | find "${source}/${BCSYMBOLMAP_DIR}" -name "*.bcsymbolmap"|while read f; do
50 | echo "Installing $f"
51 | install_bcsymbolmap "$f" "$destination"
52 | rm "$f"
53 | done
54 | rmdir "${source}/${BCSYMBOLMAP_DIR}"
55 | fi
56 |
57 | # Use filter instead of exclude so missing patterns don't throw errors.
58 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --links --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${destination}\""
59 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --links --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${destination}"
60 |
61 | local basename
62 | basename="$(basename -s .framework "$1")"
63 | binary="${destination}/${basename}.framework/${basename}"
64 |
65 | if ! [ -r "$binary" ]; then
66 | binary="${destination}/${basename}"
67 | elif [ -L "${binary}" ]; then
68 | echo "Destination binary is symlinked..."
69 | dirname="$(dirname "${binary}")"
70 | binary="${dirname}/$(readlink "${binary}")"
71 | fi
72 |
73 | # Strip invalid architectures so "fat" simulator / device frameworks work on device
74 | if [[ "$(file "$binary")" == *"dynamically linked shared library"* ]]; then
75 | strip_invalid_archs "$binary"
76 | fi
77 |
78 | # Resign the code if required by the build settings to avoid unstable apps
79 | code_sign_if_enabled "${destination}/$(basename "$1")"
80 |
81 | # Embed linked Swift runtime libraries. No longer necessary as of Xcode 7.
82 | if [ "${XCODE_VERSION_MAJOR}" -lt 7 ]; then
83 | local swift_runtime_libs
84 | swift_runtime_libs=$(xcrun otool -LX "$binary" | grep --color=never @rpath/libswift | sed -E s/@rpath\\/\(.+dylib\).*/\\1/g | uniq -u)
85 | for lib in $swift_runtime_libs; do
86 | echo "rsync -auv \"${SWIFT_STDLIB_PATH}/${lib}\" \"${destination}\""
87 | rsync -auv "${SWIFT_STDLIB_PATH}/${lib}" "${destination}"
88 | code_sign_if_enabled "${destination}/${lib}"
89 | done
90 | fi
91 | }
92 | # Copies and strips a vendored dSYM
93 | install_dsym() {
94 | local source="$1"
95 | warn_missing_arch=${2:-true}
96 | if [ -r "$source" ]; then
97 | # Copy the dSYM into the targets temp dir.
98 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${DERIVED_FILES_DIR}\""
99 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${DERIVED_FILES_DIR}"
100 |
101 | local basename
102 | basename="$(basename -s .dSYM "$source")"
103 | binary_name="$(ls "$source/Contents/Resources/DWARF")"
104 | binary="${DERIVED_FILES_DIR}/${basename}.dSYM/Contents/Resources/DWARF/${binary_name}"
105 |
106 | # Strip invalid architectures from the dSYM.
107 | if [[ "$(file "$binary")" == *"Mach-O "*"dSYM companion"* ]]; then
108 | strip_invalid_archs "$binary" "$warn_missing_arch"
109 | fi
110 | if [[ $STRIP_BINARY_RETVAL == 0 ]]; then
111 | # Move the stripped file into its final destination.
112 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --links --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${DERIVED_FILES_DIR}/${basename}.framework.dSYM\" \"${DWARF_DSYM_FOLDER_PATH}\""
113 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --links --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${DERIVED_FILES_DIR}/${basename}.dSYM" "${DWARF_DSYM_FOLDER_PATH}"
114 | else
115 | # The dSYM was not stripped at all, in this case touch a fake folder so the input/output paths from Xcode do not reexecute this script because the file is missing.
116 | mkdir -p "${DWARF_DSYM_FOLDER_PATH}"
117 | touch "${DWARF_DSYM_FOLDER_PATH}/${basename}.dSYM"
118 | fi
119 | fi
120 | }
121 |
122 | # Used as a return value for each invocation of `strip_invalid_archs` function.
123 | STRIP_BINARY_RETVAL=0
124 |
125 | # Strip invalid architectures
126 | strip_invalid_archs() {
127 | binary="$1"
128 | warn_missing_arch=${2:-true}
129 | # Get architectures for current target binary
130 | binary_archs="$(lipo -info "$binary" | rev | cut -d ':' -f1 | awk '{$1=$1;print}' | rev)"
131 | # Intersect them with the architectures we are building for
132 | intersected_archs="$(echo ${ARCHS[@]} ${binary_archs[@]} | tr ' ' '\n' | sort | uniq -d)"
133 | # If there are no archs supported by this binary then warn the user
134 | if [[ -z "$intersected_archs" ]]; then
135 | if [[ "$warn_missing_arch" == "true" ]]; then
136 | echo "warning: [CP] Vendored binary '$binary' contains architectures ($binary_archs) none of which match the current build architectures ($ARCHS)."
137 | fi
138 | STRIP_BINARY_RETVAL=1
139 | return
140 | fi
141 | stripped=""
142 | for arch in $binary_archs; do
143 | if ! [[ "${ARCHS}" == *"$arch"* ]]; then
144 | # Strip non-valid architectures in-place
145 | lipo -remove "$arch" -output "$binary" "$binary"
146 | stripped="$stripped $arch"
147 | fi
148 | done
149 | if [[ "$stripped" ]]; then
150 | echo "Stripped $binary of architectures:$stripped"
151 | fi
152 | STRIP_BINARY_RETVAL=0
153 | }
154 |
155 | # Copies the bcsymbolmap files of a vendored framework
156 | install_bcsymbolmap() {
157 | local bcsymbolmap_path="$1"
158 | local destination="${BUILT_PRODUCTS_DIR}"
159 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${bcsymbolmap_path}" "${destination}""
160 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${bcsymbolmap_path}" "${destination}"
161 | }
162 |
163 | # Signs a framework with the provided identity
164 | code_sign_if_enabled() {
165 | if [ -n "${EXPANDED_CODE_SIGN_IDENTITY:-}" -a "${CODE_SIGNING_REQUIRED:-}" != "NO" -a "${CODE_SIGNING_ALLOWED}" != "NO" ]; then
166 | # Use the current code_sign_identity
167 | echo "Code Signing $1 with Identity ${EXPANDED_CODE_SIGN_IDENTITY_NAME}"
168 | local code_sign_cmd="/usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} ${OTHER_CODE_SIGN_FLAGS:-} --preserve-metadata=identifier,entitlements '$1'"
169 |
170 | if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then
171 | code_sign_cmd="$code_sign_cmd &"
172 | fi
173 | echo "$code_sign_cmd"
174 | eval "$code_sign_cmd"
175 | fi
176 | }
177 |
178 | if [[ "$CONFIGURATION" == "Debug" ]]; then
179 | install_framework "${PODS_ROOT}/../../shared/build/cocoapods/framework/shared.framework"
180 | fi
181 | if [[ "$CONFIGURATION" == "Release" ]]; then
182 | install_framework "${PODS_ROOT}/../../shared/build/cocoapods/framework/shared.framework"
183 | fi
184 | if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then
185 | wait
186 | fi
187 |
--------------------------------------------------------------------------------
/iosApp/KorsiSher.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 51;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 058557BB273AAA24004C7B11 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 058557BA273AAA24004C7B11 /* Assets.xcassets */; };
11 | 058557D9273AAEEB004C7B11 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 058557D8273AAEEB004C7B11 /* Preview Assets.xcassets */; };
12 | 2152FB042600AC8F00CF470E /* iOSApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2152FB032600AC8F00CF470E /* iOSApp.swift */; };
13 | 56C7C5A184CAF71333F4428D /* Pods_iosApp.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FB71FA92C9D73822084EFA5A /* Pods_iosApp.framework */; };
14 | 7555FF83242A565900829871 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7555FF82242A565900829871 /* ContentView.swift */; };
15 | 796290852A51A32200A66007 /* ProgressButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 796290842A51A32200A66007 /* ProgressButton.swift */; };
16 | 796290892A52184B00A66007 /* IOSLikeViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 796290882A52184B00A66007 /* IOSLikeViewModel.swift */; };
17 | 7962908B2A5218AD00A66007 /* LikeScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7962908A2A5218AD00A66007 /* LikeScreen.swift */; };
18 | 798DBA2C2A50AABB009A9F41 /* Colors.swift in Sources */ = {isa = PBXBuildFile; fileRef = 798DBA2B2A50AABB009A9F41 /* Colors.swift */; };
19 | 798DBA312A50DD8A009A9F41 /* PoemScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 798DBA302A50DD8A009A9F41 /* PoemScreen.swift */; };
20 | 798DBA332A50EB5F009A9F41 /* IOSPoemViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 798DBA322A50EB5F009A9F41 /* IOSPoemViewModel.swift */; };
21 | /* End PBXBuildFile section */
22 |
23 | /* Begin PBXFileReference section */
24 | 058557BA273AAA24004C7B11 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
25 | 058557D8273AAEEB004C7B11 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; };
26 | 2152FB032600AC8F00CF470E /* iOSApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = iOSApp.swift; sourceTree = ""; };
27 | 7555FF7B242A565900829871 /* iosApp.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = iosApp.app; sourceTree = BUILT_PRODUCTS_DIR; };
28 | 7555FF82242A565900829871 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; };
29 | 7555FF8C242A565B00829871 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
30 | 796290842A51A32200A66007 /* ProgressButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProgressButton.swift; sourceTree = ""; };
31 | 796290882A52184B00A66007 /* IOSLikeViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IOSLikeViewModel.swift; sourceTree = ""; };
32 | 7962908A2A5218AD00A66007 /* LikeScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LikeScreen.swift; sourceTree = ""; };
33 | 798DBA2B2A50AABB009A9F41 /* Colors.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Colors.swift; sourceTree = ""; };
34 | 798DBA302A50DD8A009A9F41 /* PoemScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PoemScreen.swift; sourceTree = ""; };
35 | 798DBA322A50EB5F009A9F41 /* IOSPoemViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IOSPoemViewModel.swift; sourceTree = ""; };
36 | EE1EA440B7914087E92CD736 /* Pods-iosApp.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-iosApp.release.xcconfig"; path = "Target Support Files/Pods-iosApp/Pods-iosApp.release.xcconfig"; sourceTree = ""; };
37 | FB71FA92C9D73822084EFA5A /* Pods_iosApp.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_iosApp.framework; sourceTree = BUILT_PRODUCTS_DIR; };
38 | FF64F96337911B91021B9933 /* Pods-iosApp.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-iosApp.debug.xcconfig"; path = "Target Support Files/Pods-iosApp/Pods-iosApp.debug.xcconfig"; sourceTree = ""; };
39 | /* End PBXFileReference section */
40 |
41 | /* Begin PBXFrameworksBuildPhase section */
42 | 9A88A747D9D0C3AE26788AE0 /* Frameworks */ = {
43 | isa = PBXFrameworksBuildPhase;
44 | buildActionMask = 2147483647;
45 | files = (
46 | 56C7C5A184CAF71333F4428D /* Pods_iosApp.framework in Frameworks */,
47 | );
48 | runOnlyForDeploymentPostprocessing = 0;
49 | };
50 | /* End PBXFrameworksBuildPhase section */
51 |
52 | /* Begin PBXGroup section */
53 | 058557D7273AAEEB004C7B11 /* Preview Content */ = {
54 | isa = PBXGroup;
55 | children = (
56 | 058557D8273AAEEB004C7B11 /* Preview Assets.xcassets */,
57 | );
58 | path = "Preview Content";
59 | sourceTree = "";
60 | };
61 | 7555FF72242A565900829871 = {
62 | isa = PBXGroup;
63 | children = (
64 | 7555FF7D242A565900829871 /* iosApp */,
65 | 7555FF7C242A565900829871 /* Products */,
66 | F6C5DBDA95E54BD0060EB692 /* Pods */,
67 | A8CD82AFF0CD7DE135B5B0CF /* Frameworks */,
68 | );
69 | sourceTree = "";
70 | };
71 | 7555FF7C242A565900829871 /* Products */ = {
72 | isa = PBXGroup;
73 | children = (
74 | 7555FF7B242A565900829871 /* iosApp.app */,
75 | );
76 | name = Products;
77 | sourceTree = "";
78 | };
79 | 7555FF7D242A565900829871 /* iosApp */ = {
80 | isa = PBXGroup;
81 | children = (
82 | 796290862A52180400A66007 /* like */,
83 | 798DBA2E2A50DD61009A9F41 /* poem */,
84 | 798DBA2D2A50DD16009A9F41 /* core */,
85 | 058557BA273AAA24004C7B11 /* Assets.xcassets */,
86 | 7555FF82242A565900829871 /* ContentView.swift */,
87 | 7555FF8C242A565B00829871 /* Info.plist */,
88 | 2152FB032600AC8F00CF470E /* iOSApp.swift */,
89 | 058557D7273AAEEB004C7B11 /* Preview Content */,
90 | );
91 | path = iosApp;
92 | sourceTree = "";
93 | };
94 | 796290832A51A30F00A66007 /* components */ = {
95 | isa = PBXGroup;
96 | children = (
97 | 796290842A51A32200A66007 /* ProgressButton.swift */,
98 | );
99 | path = components;
100 | sourceTree = "";
101 | };
102 | 796290862A52180400A66007 /* like */ = {
103 | isa = PBXGroup;
104 | children = (
105 | 796290872A52182C00A66007 /* presentation */,
106 | );
107 | path = like;
108 | sourceTree = "";
109 | };
110 | 796290872A52182C00A66007 /* presentation */ = {
111 | isa = PBXGroup;
112 | children = (
113 | 796290882A52184B00A66007 /* IOSLikeViewModel.swift */,
114 | 7962908A2A5218AD00A66007 /* LikeScreen.swift */,
115 | );
116 | path = presentation;
117 | sourceTree = "";
118 | };
119 | 798DBA2D2A50DD16009A9F41 /* core */ = {
120 | isa = PBXGroup;
121 | children = (
122 | 79B3426B2A4F6B75001D5AE0 /* presentation */,
123 | );
124 | path = core;
125 | sourceTree = "";
126 | };
127 | 798DBA2E2A50DD61009A9F41 /* poem */ = {
128 | isa = PBXGroup;
129 | children = (
130 | 798DBA2F2A50DD67009A9F41 /* presentation */,
131 | );
132 | path = poem;
133 | sourceTree = "";
134 | };
135 | 798DBA2F2A50DD67009A9F41 /* presentation */ = {
136 | isa = PBXGroup;
137 | children = (
138 | 796290832A51A30F00A66007 /* components */,
139 | 798DBA302A50DD8A009A9F41 /* PoemScreen.swift */,
140 | 798DBA322A50EB5F009A9F41 /* IOSPoemViewModel.swift */,
141 | );
142 | path = presentation;
143 | sourceTree = "";
144 | };
145 | 79B3426B2A4F6B75001D5AE0 /* presentation */ = {
146 | isa = PBXGroup;
147 | children = (
148 | 798DBA2B2A50AABB009A9F41 /* Colors.swift */,
149 | );
150 | path = presentation;
151 | sourceTree = "";
152 | };
153 | A8CD82AFF0CD7DE135B5B0CF /* Frameworks */ = {
154 | isa = PBXGroup;
155 | children = (
156 | FB71FA92C9D73822084EFA5A /* Pods_iosApp.framework */,
157 | );
158 | name = Frameworks;
159 | sourceTree = "";
160 | };
161 | F6C5DBDA95E54BD0060EB692 /* Pods */ = {
162 | isa = PBXGroup;
163 | children = (
164 | FF64F96337911B91021B9933 /* Pods-iosApp.debug.xcconfig */,
165 | EE1EA440B7914087E92CD736 /* Pods-iosApp.release.xcconfig */,
166 | );
167 | path = Pods;
168 | sourceTree = "";
169 | };
170 | /* End PBXGroup section */
171 |
172 | /* Begin PBXNativeTarget section */
173 | 7555FF7A242A565900829871 /* iosApp */ = {
174 | isa = PBXNativeTarget;
175 | buildConfigurationList = 7555FFA5242A565B00829871 /* Build configuration list for PBXNativeTarget "iosApp" */;
176 | buildPhases = (
177 | 56134D43338734F0D0F6F1BD /* [CP] Check Pods Manifest.lock */,
178 | 79B342692A4EE092001D5AE0 /* Run Script */,
179 | 7555FF77242A565900829871 /* Sources */,
180 | 7555FF79242A565900829871 /* Resources */,
181 | 9A88A747D9D0C3AE26788AE0 /* Frameworks */,
182 | CCD8532632513AEC29CE2699 /* [CP] Embed Pods Frameworks */,
183 | );
184 | buildRules = (
185 | );
186 | dependencies = (
187 | );
188 | name = iosApp;
189 | productName = iosApp;
190 | productReference = 7555FF7B242A565900829871 /* iosApp.app */;
191 | productType = "com.apple.product-type.application";
192 | };
193 | /* End PBXNativeTarget section */
194 |
195 | /* Begin PBXProject section */
196 | 7555FF73242A565900829871 /* Project object */ = {
197 | isa = PBXProject;
198 | attributes = {
199 | LastSwiftUpdateCheck = 1130;
200 | LastUpgradeCheck = 1130;
201 | ORGANIZATIONNAME = orgName;
202 | TargetAttributes = {
203 | 7555FF7A242A565900829871 = {
204 | CreatedOnToolsVersion = 11.3.1;
205 | };
206 | };
207 | };
208 | buildConfigurationList = 7555FF76242A565900829871 /* Build configuration list for PBXProject "KorsiSher" */;
209 | compatibilityVersion = "Xcode 9.3";
210 | developmentRegion = en;
211 | hasScannedForEncodings = 0;
212 | knownRegions = (
213 | Base,
214 | en,
215 | );
216 | mainGroup = 7555FF72242A565900829871;
217 | productRefGroup = 7555FF7C242A565900829871 /* Products */;
218 | projectDirPath = "";
219 | projectRoot = "";
220 | targets = (
221 | 7555FF7A242A565900829871 /* iosApp */,
222 | );
223 | };
224 | /* End PBXProject section */
225 |
226 | /* Begin PBXResourcesBuildPhase section */
227 | 7555FF79242A565900829871 /* Resources */ = {
228 | isa = PBXResourcesBuildPhase;
229 | buildActionMask = 2147483647;
230 | files = (
231 | 058557D9273AAEEB004C7B11 /* Preview Assets.xcassets in Resources */,
232 | 058557BB273AAA24004C7B11 /* Assets.xcassets in Resources */,
233 | );
234 | runOnlyForDeploymentPostprocessing = 0;
235 | };
236 | /* End PBXResourcesBuildPhase section */
237 |
238 | /* Begin PBXShellScriptBuildPhase section */
239 | 56134D43338734F0D0F6F1BD /* [CP] Check Pods Manifest.lock */ = {
240 | isa = PBXShellScriptBuildPhase;
241 | buildActionMask = 2147483647;
242 | files = (
243 | );
244 | inputFileListPaths = (
245 | );
246 | inputPaths = (
247 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock",
248 | "${PODS_ROOT}/Manifest.lock",
249 | );
250 | name = "[CP] Check Pods Manifest.lock";
251 | outputFileListPaths = (
252 | );
253 | outputPaths = (
254 | "$(DERIVED_FILE_DIR)/Pods-iosApp-checkManifestLockResult.txt",
255 | );
256 | runOnlyForDeploymentPostprocessing = 0;
257 | shellPath = /bin/sh;
258 | shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
259 | showEnvVarsInLog = 0;
260 | };
261 | 79B342692A4EE092001D5AE0 /* Run Script */ = {
262 | isa = PBXShellScriptBuildPhase;
263 | buildActionMask = 2147483647;
264 | files = (
265 | );
266 | inputFileListPaths = (
267 | );
268 | inputPaths = (
269 | );
270 | name = "Run Script";
271 | outputFileListPaths = (
272 | );
273 | outputPaths = (
274 | );
275 | runOnlyForDeploymentPostprocessing = 0;
276 | shellPath = /bin/sh;
277 | shellScript = "cd \"$SRCROOT/..\"\n./gradlew :shared:embedAndSignPodAppleFrameworkForXcode\n";
278 | };
279 | CCD8532632513AEC29CE2699 /* [CP] Embed Pods Frameworks */ = {
280 | isa = PBXShellScriptBuildPhase;
281 | buildActionMask = 2147483647;
282 | files = (
283 | );
284 | inputFileListPaths = (
285 | "${PODS_ROOT}/Target Support Files/Pods-iosApp/Pods-iosApp-frameworks-${CONFIGURATION}-input-files.xcfilelist",
286 | );
287 | name = "[CP] Embed Pods Frameworks";
288 | outputFileListPaths = (
289 | "${PODS_ROOT}/Target Support Files/Pods-iosApp/Pods-iosApp-frameworks-${CONFIGURATION}-output-files.xcfilelist",
290 | );
291 | runOnlyForDeploymentPostprocessing = 0;
292 | shellPath = /bin/sh;
293 | shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-iosApp/Pods-iosApp-frameworks.sh\"\n";
294 | showEnvVarsInLog = 0;
295 | };
296 | /* End PBXShellScriptBuildPhase section */
297 |
298 | /* Begin PBXSourcesBuildPhase section */
299 | 7555FF77242A565900829871 /* Sources */ = {
300 | isa = PBXSourcesBuildPhase;
301 | buildActionMask = 2147483647;
302 | files = (
303 | 7962908B2A5218AD00A66007 /* LikeScreen.swift in Sources */,
304 | 796290852A51A32200A66007 /* ProgressButton.swift in Sources */,
305 | 796290892A52184B00A66007 /* IOSLikeViewModel.swift in Sources */,
306 | 798DBA312A50DD8A009A9F41 /* PoemScreen.swift in Sources */,
307 | 2152FB042600AC8F00CF470E /* iOSApp.swift in Sources */,
308 | 798DBA332A50EB5F009A9F41 /* IOSPoemViewModel.swift in Sources */,
309 | 798DBA2C2A50AABB009A9F41 /* Colors.swift in Sources */,
310 | 7555FF83242A565900829871 /* ContentView.swift in Sources */,
311 | );
312 | runOnlyForDeploymentPostprocessing = 0;
313 | };
314 | /* End PBXSourcesBuildPhase section */
315 |
316 | /* Begin XCBuildConfiguration section */
317 | 7555FFA3242A565B00829871 /* Debug */ = {
318 | isa = XCBuildConfiguration;
319 | buildSettings = {
320 | ALWAYS_SEARCH_USER_PATHS = NO;
321 | CLANG_ANALYZER_NONNULL = YES;
322 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
323 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
324 | CLANG_CXX_LIBRARY = "libc++";
325 | CLANG_ENABLE_MODULES = YES;
326 | CLANG_ENABLE_OBJC_ARC = YES;
327 | CLANG_ENABLE_OBJC_WEAK = YES;
328 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
329 | CLANG_WARN_BOOL_CONVERSION = YES;
330 | CLANG_WARN_COMMA = YES;
331 | CLANG_WARN_CONSTANT_CONVERSION = YES;
332 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
333 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
334 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
335 | CLANG_WARN_EMPTY_BODY = YES;
336 | CLANG_WARN_ENUM_CONVERSION = YES;
337 | CLANG_WARN_INFINITE_RECURSION = YES;
338 | CLANG_WARN_INT_CONVERSION = YES;
339 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
340 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
341 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
342 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
343 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
344 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
345 | CLANG_WARN_STRICT_PROTOTYPES = YES;
346 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
347 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
348 | CLANG_WARN_UNREACHABLE_CODE = YES;
349 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
350 | COPY_PHASE_STRIP = NO;
351 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
352 | ENABLE_STRICT_OBJC_MSGSEND = YES;
353 | ENABLE_TESTABILITY = YES;
354 | GCC_C_LANGUAGE_STANDARD = gnu11;
355 | GCC_DYNAMIC_NO_PIC = NO;
356 | GCC_NO_COMMON_BLOCKS = YES;
357 | GCC_OPTIMIZATION_LEVEL = 0;
358 | GCC_PREPROCESSOR_DEFINITIONS = (
359 | "DEBUG=1",
360 | "$(inherited)",
361 | );
362 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
363 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
364 | GCC_WARN_UNDECLARED_SELECTOR = YES;
365 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
366 | GCC_WARN_UNUSED_FUNCTION = YES;
367 | GCC_WARN_UNUSED_VARIABLE = YES;
368 | IPHONEOS_DEPLOYMENT_TARGET = 14.1;
369 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
370 | MTL_FAST_MATH = YES;
371 | ONLY_ACTIVE_ARCH = YES;
372 | SDKROOT = iphoneos;
373 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
374 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
375 | };
376 | name = Debug;
377 | };
378 | 7555FFA4242A565B00829871 /* Release */ = {
379 | isa = XCBuildConfiguration;
380 | buildSettings = {
381 | ALWAYS_SEARCH_USER_PATHS = NO;
382 | CLANG_ANALYZER_NONNULL = YES;
383 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
384 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
385 | CLANG_CXX_LIBRARY = "libc++";
386 | CLANG_ENABLE_MODULES = YES;
387 | CLANG_ENABLE_OBJC_ARC = YES;
388 | CLANG_ENABLE_OBJC_WEAK = YES;
389 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
390 | CLANG_WARN_BOOL_CONVERSION = YES;
391 | CLANG_WARN_COMMA = YES;
392 | CLANG_WARN_CONSTANT_CONVERSION = YES;
393 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
394 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
395 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
396 | CLANG_WARN_EMPTY_BODY = YES;
397 | CLANG_WARN_ENUM_CONVERSION = YES;
398 | CLANG_WARN_INFINITE_RECURSION = YES;
399 | CLANG_WARN_INT_CONVERSION = YES;
400 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
401 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
402 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
403 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
404 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
405 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
406 | CLANG_WARN_STRICT_PROTOTYPES = YES;
407 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
408 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
409 | CLANG_WARN_UNREACHABLE_CODE = YES;
410 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
411 | COPY_PHASE_STRIP = NO;
412 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
413 | ENABLE_NS_ASSERTIONS = NO;
414 | ENABLE_STRICT_OBJC_MSGSEND = YES;
415 | GCC_C_LANGUAGE_STANDARD = gnu11;
416 | GCC_NO_COMMON_BLOCKS = YES;
417 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
418 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
419 | GCC_WARN_UNDECLARED_SELECTOR = YES;
420 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
421 | GCC_WARN_UNUSED_FUNCTION = YES;
422 | GCC_WARN_UNUSED_VARIABLE = YES;
423 | IPHONEOS_DEPLOYMENT_TARGET = 14.1;
424 | MTL_ENABLE_DEBUG_INFO = NO;
425 | MTL_FAST_MATH = YES;
426 | SDKROOT = iphoneos;
427 | SWIFT_COMPILATION_MODE = wholemodule;
428 | SWIFT_OPTIMIZATION_LEVEL = "-O";
429 | VALIDATE_PRODUCT = YES;
430 | };
431 | name = Release;
432 | };
433 | 7555FFA6242A565B00829871 /* Debug */ = {
434 | isa = XCBuildConfiguration;
435 | baseConfigurationReference = FF64F96337911B91021B9933 /* Pods-iosApp.debug.xcconfig */;
436 | buildSettings = {
437 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
438 | ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = YES;
439 | CODE_SIGN_STYLE = Automatic;
440 | CURRENT_PROJECT_VERSION = 1;
441 | DEVELOPMENT_ASSET_PATHS = "\"iosApp/Preview Content\"";
442 | DEVELOPMENT_TEAM = V5X794G7A7;
443 | ENABLE_PREVIEWS = YES;
444 | FRAMEWORK_SEARCH_PATHS = (
445 | "$(inherited)",
446 | "\"${PODS_ROOT}/../../shared/build/cocoapods/framework\"",
447 | "$(SRCROOT)/../shared/build/xcode-frameworks/$(CONFIGURATION)/$(SDK_NAME)",
448 | );
449 | INFOPLIST_FILE = iosApp/Info.plist;
450 | INFOPLIST_KEY_CFBundleDisplayName = KorsiSher;
451 | INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.entertainment";
452 | IPHONEOS_DEPLOYMENT_TARGET = 15.0;
453 | LD_RUNPATH_SEARCH_PATHS = (
454 | "$(inherited)",
455 | "@executable_path/Frameworks",
456 | );
457 | MARKETING_VERSION = 1.0;
458 | OTHER_LDFLAGS = (
459 | "$(inherited)",
460 | "-ObjC",
461 | "-l\"c++\"",
462 | "-framework",
463 | "\"shared\"",
464 | "$(inherited)",
465 | "-framework",
466 | shared,
467 | "$(inherited)",
468 | "-framework",
469 | shared,
470 | "-lsqlite3",
471 | );
472 | PRODUCT_BUNDLE_IDENTIFIER = korsi.sher.ios;
473 | PRODUCT_NAME = "$(TARGET_NAME)";
474 | SWIFT_VERSION = 5.0;
475 | TARGETED_DEVICE_FAMILY = "1,2";
476 | };
477 | name = Debug;
478 | };
479 | 7555FFA7242A565B00829871 /* Release */ = {
480 | isa = XCBuildConfiguration;
481 | baseConfigurationReference = EE1EA440B7914087E92CD736 /* Pods-iosApp.release.xcconfig */;
482 | buildSettings = {
483 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
484 | ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = YES;
485 | CODE_SIGN_STYLE = Automatic;
486 | CURRENT_PROJECT_VERSION = 1;
487 | DEVELOPMENT_ASSET_PATHS = "\"iosApp/Preview Content\"";
488 | DEVELOPMENT_TEAM = V5X794G7A7;
489 | ENABLE_PREVIEWS = YES;
490 | FRAMEWORK_SEARCH_PATHS = (
491 | "$(inherited)",
492 | "\"${PODS_ROOT}/../../shared/build/cocoapods/framework\"",
493 | "$(SRCROOT)/../shared/build/xcode-frameworks/$(CONFIGURATION)/$(SDK_NAME)",
494 | );
495 | INFOPLIST_FILE = iosApp/Info.plist;
496 | INFOPLIST_KEY_CFBundleDisplayName = KorsiSher;
497 | INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.entertainment";
498 | IPHONEOS_DEPLOYMENT_TARGET = 15.0;
499 | LD_RUNPATH_SEARCH_PATHS = (
500 | "$(inherited)",
501 | "@executable_path/Frameworks",
502 | );
503 | MARKETING_VERSION = 1.0;
504 | OTHER_LDFLAGS = (
505 | "$(inherited)",
506 | "-ObjC",
507 | "-l\"c++\"",
508 | "-framework",
509 | "\"shared\"",
510 | "$(inherited)",
511 | "-framework",
512 | shared,
513 | "$(inherited)",
514 | "-framework",
515 | shared,
516 | "-lsqlite3",
517 | );
518 | PRODUCT_BUNDLE_IDENTIFIER = korsi.sher.ios;
519 | PRODUCT_NAME = "$(TARGET_NAME)";
520 | SWIFT_VERSION = 5.0;
521 | TARGETED_DEVICE_FAMILY = "1,2";
522 | };
523 | name = Release;
524 | };
525 | /* End XCBuildConfiguration section */
526 |
527 | /* Begin XCConfigurationList section */
528 | 7555FF76242A565900829871 /* Build configuration list for PBXProject "KorsiSher" */ = {
529 | isa = XCConfigurationList;
530 | buildConfigurations = (
531 | 7555FFA3242A565B00829871 /* Debug */,
532 | 7555FFA4242A565B00829871 /* Release */,
533 | );
534 | defaultConfigurationIsVisible = 0;
535 | defaultConfigurationName = Release;
536 | };
537 | 7555FFA5242A565B00829871 /* Build configuration list for PBXNativeTarget "iosApp" */ = {
538 | isa = XCConfigurationList;
539 | buildConfigurations = (
540 | 7555FFA6242A565B00829871 /* Debug */,
541 | 7555FFA7242A565B00829871 /* Release */,
542 | );
543 | defaultConfigurationIsVisible = 0;
544 | defaultConfigurationName = Release;
545 | };
546 | /* End XCConfigurationList section */
547 | };
548 | rootObject = 7555FF73242A565900829871 /* Project object */;
549 | }
550 |
--------------------------------------------------------------------------------
/iosApp/Pods/Pods.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 51;
7 | objects = {
8 |
9 | /* Begin PBXAggregateTarget section */
10 | 8777C9F6889E59EFFD631D80AEE9048B /* shared */ = {
11 | isa = PBXAggregateTarget;
12 | buildConfigurationList = 8349D8E2EC974421A14EF8ABFF6AD6DC /* Build configuration list for PBXAggregateTarget "shared" */;
13 | buildPhases = (
14 | BEA8885189D408D600647BDC228A6A20 /* [CP-User] Build shared */,
15 | );
16 | dependencies = (
17 | );
18 | name = shared;
19 | };
20 | /* End PBXAggregateTarget section */
21 |
22 | /* Begin PBXBuildFile section */
23 | 648F16425FEF89525AE0325F5A984B86 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 73010CC983E3809BECEE5348DA1BB8C6 /* Foundation.framework */; };
24 | 8749C8E8DC500B064FA0BC7A78C38A2A /* Pods-iosApp-dummy.m in Sources */ = {isa = PBXBuildFile; fileRef = 54DC7F9924F99FEE67A9AD3BEE09A10C /* Pods-iosApp-dummy.m */; };
25 | 8801CBFD38B946597BD07145B2EEFC9F /* Pods-iosApp-umbrella.h in Headers */ = {isa = PBXBuildFile; fileRef = F87A626222A8D9B26448A9FEB04FD0DF /* Pods-iosApp-umbrella.h */; settings = {ATTRIBUTES = (Public, ); }; };
26 | /* End PBXBuildFile section */
27 |
28 | /* Begin PBXContainerItemProxy section */
29 | C1E4F2F8101E860063100BCC8448BC3B /* PBXContainerItemProxy */ = {
30 | isa = PBXContainerItemProxy;
31 | containerPortal = BFDFE7DC352907FC980B868725387E98 /* Project object */;
32 | proxyType = 1;
33 | remoteGlobalIDString = 8777C9F6889E59EFFD631D80AEE9048B;
34 | remoteInfo = shared;
35 | };
36 | /* End PBXContainerItemProxy section */
37 |
38 | /* Begin PBXFileReference section */
39 | 0187F135D5F61750CD24C3E04B6E8B64 /* Pods-iosApp-frameworks.sh */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.script.sh; path = "Pods-iosApp-frameworks.sh"; sourceTree = ""; };
40 | 35548E3BD8DA30925E8FE97E67B84868 /* shared.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = shared.release.xcconfig; sourceTree = ""; };
41 | 3F64BADB16C311E9D09DAD0116F684F4 /* Pods-iosApp.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Pods-iosApp.debug.xcconfig"; sourceTree = ""; };
42 | 54DC7F9924F99FEE67A9AD3BEE09A10C /* Pods-iosApp-dummy.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; path = "Pods-iosApp-dummy.m"; sourceTree = ""; };
43 | 5AC974169B09D4545F741E9A2147610E /* Pods-iosApp-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "Pods-iosApp-Info.plist"; sourceTree = ""; };
44 | 73010CC983E3809BECEE5348DA1BB8C6 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS14.0.sdk/System/Library/Frameworks/Foundation.framework; sourceTree = DEVELOPER_DIR; };
45 | 73D4D08B8C9FAD17B10E8E5C0EB49A76 /* shared.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = shared.framework; path = build/cocoapods/framework/shared.framework; sourceTree = ""; };
46 | 8B524AABE529FB8A2D151B05321336E0 /* Pods-iosApp.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = "Pods-iosApp.modulemap"; sourceTree = ""; };
47 | 95B09EA82E7AF9ACCCCAF3E55C859116 /* shared.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = shared.debug.xcconfig; sourceTree = ""; };
48 | 9BB0B8B698D4C35D4F9A07EF70910170 /* Pods-iosApp-acknowledgements.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; path = "Pods-iosApp-acknowledgements.plist"; sourceTree = ""; };
49 | 9D940727FF8FB9C785EB98E56350EF41 /* Podfile */ = {isa = PBXFileReference; explicitFileType = text.script.ruby; includeInIndex = 1; indentWidth = 2; lastKnownFileType = text; name = Podfile; path = ../Podfile; sourceTree = SOURCE_ROOT; tabWidth = 2; xcLanguageSpecificationIdentifier = xcode.lang.ruby; };
50 | 9F1FFC8B10F4D7D4F37606E8959B3F29 /* Pods-iosApp-acknowledgements.markdown */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text; path = "Pods-iosApp-acknowledgements.markdown"; sourceTree = ""; };
51 | 9FECCB5AFF87D121F15BA01E683C7932 /* Pods-iosApp.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = "Pods-iosApp.release.xcconfig"; sourceTree = ""; };
52 | B097DD7534E741D5C41838011D755842 /* Pods-iosApp */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = "Pods-iosApp"; path = Pods_iosApp.framework; sourceTree = BUILT_PRODUCTS_DIR; };
53 | F87A626222A8D9B26448A9FEB04FD0DF /* Pods-iosApp-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "Pods-iosApp-umbrella.h"; sourceTree = ""; };
54 | FB1BF8BE937671FB0F330C2D28634477 /* shared.podspec */ = {isa = PBXFileReference; explicitFileType = text.script.ruby; includeInIndex = 1; indentWidth = 2; lastKnownFileType = text; path = shared.podspec; sourceTree = ""; tabWidth = 2; xcLanguageSpecificationIdentifier = xcode.lang.ruby; };
55 | /* End PBXFileReference section */
56 |
57 | /* Begin PBXFrameworksBuildPhase section */
58 | CC3CD5459C4A5476C5A93268587E63E7 /* Frameworks */ = {
59 | isa = PBXFrameworksBuildPhase;
60 | buildActionMask = 2147483647;
61 | files = (
62 | 648F16425FEF89525AE0325F5A984B86 /* Foundation.framework in Frameworks */,
63 | );
64 | runOnlyForDeploymentPostprocessing = 0;
65 | };
66 | /* End PBXFrameworksBuildPhase section */
67 |
68 | /* Begin PBXGroup section */
69 | 11C970DEAE48C6D0282DFE54684F53F1 /* Targets Support Files */ = {
70 | isa = PBXGroup;
71 | children = (
72 | 52A898E555C2DBD7D25A7E44754C3FC6 /* Pods-iosApp */,
73 | );
74 | name = "Targets Support Files";
75 | sourceTree = "";
76 | };
77 | 1F86AA6785DF34AFD5A71790761717DE /* Products */ = {
78 | isa = PBXGroup;
79 | children = (
80 | B097DD7534E741D5C41838011D755842 /* Pods-iosApp */,
81 | );
82 | name = Products;
83 | sourceTree = "";
84 | };
85 | 313FE5FE915A4A924C55AAC02A910D61 /* Development Pods */ = {
86 | isa = PBXGroup;
87 | children = (
88 | EEF3277DCE2E4B31CF76A57AB68C2BA1 /* shared */,
89 | );
90 | name = "Development Pods";
91 | sourceTree = "";
92 | };
93 | 52A898E555C2DBD7D25A7E44754C3FC6 /* Pods-iosApp */ = {
94 | isa = PBXGroup;
95 | children = (
96 | 8B524AABE529FB8A2D151B05321336E0 /* Pods-iosApp.modulemap */,
97 | 9F1FFC8B10F4D7D4F37606E8959B3F29 /* Pods-iosApp-acknowledgements.markdown */,
98 | 9BB0B8B698D4C35D4F9A07EF70910170 /* Pods-iosApp-acknowledgements.plist */,
99 | 54DC7F9924F99FEE67A9AD3BEE09A10C /* Pods-iosApp-dummy.m */,
100 | 0187F135D5F61750CD24C3E04B6E8B64 /* Pods-iosApp-frameworks.sh */,
101 | 5AC974169B09D4545F741E9A2147610E /* Pods-iosApp-Info.plist */,
102 | F87A626222A8D9B26448A9FEB04FD0DF /* Pods-iosApp-umbrella.h */,
103 | 3F64BADB16C311E9D09DAD0116F684F4 /* Pods-iosApp.debug.xcconfig */,
104 | 9FECCB5AFF87D121F15BA01E683C7932 /* Pods-iosApp.release.xcconfig */,
105 | );
106 | name = "Pods-iosApp";
107 | path = "Target Support Files/Pods-iosApp";
108 | sourceTree = "";
109 | };
110 | 569B56E5B05425CAE32676C6049DC8CB /* Pod */ = {
111 | isa = PBXGroup;
112 | children = (
113 | FB1BF8BE937671FB0F330C2D28634477 /* shared.podspec */,
114 | );
115 | name = Pod;
116 | sourceTree = "";
117 | };
118 | 578452D2E740E91742655AC8F1636D1F /* iOS */ = {
119 | isa = PBXGroup;
120 | children = (
121 | 73010CC983E3809BECEE5348DA1BB8C6 /* Foundation.framework */,
122 | );
123 | name = iOS;
124 | sourceTree = "";
125 | };
126 | 5CB66AAACA3977B45E9869C360E9F289 /* Support Files */ = {
127 | isa = PBXGroup;
128 | children = (
129 | 95B09EA82E7AF9ACCCCAF3E55C859116 /* shared.debug.xcconfig */,
130 | 35548E3BD8DA30925E8FE97E67B84868 /* shared.release.xcconfig */,
131 | );
132 | name = "Support Files";
133 | path = "../iosApp/Pods/Target Support Files/shared";
134 | sourceTree = "";
135 | };
136 | 7DBF81461E18ACE1B4BD971BAC841CF7 /* Frameworks */ = {
137 | isa = PBXGroup;
138 | children = (
139 | 73D4D08B8C9FAD17B10E8E5C0EB49A76 /* shared.framework */,
140 | );
141 | name = Frameworks;
142 | sourceTree = "";
143 | };
144 | CF1408CF629C7361332E53B88F7BD30C = {
145 | isa = PBXGroup;
146 | children = (
147 | 9D940727FF8FB9C785EB98E56350EF41 /* Podfile */,
148 | 313FE5FE915A4A924C55AAC02A910D61 /* Development Pods */,
149 | D210D550F4EA176C3123ED886F8F87F5 /* Frameworks */,
150 | 1F86AA6785DF34AFD5A71790761717DE /* Products */,
151 | 11C970DEAE48C6D0282DFE54684F53F1 /* Targets Support Files */,
152 | );
153 | sourceTree = "";
154 | };
155 | D210D550F4EA176C3123ED886F8F87F5 /* Frameworks */ = {
156 | isa = PBXGroup;
157 | children = (
158 | 578452D2E740E91742655AC8F1636D1F /* iOS */,
159 | );
160 | name = Frameworks;
161 | sourceTree = "";
162 | };
163 | EEF3277DCE2E4B31CF76A57AB68C2BA1 /* shared */ = {
164 | isa = PBXGroup;
165 | children = (
166 | 7DBF81461E18ACE1B4BD971BAC841CF7 /* Frameworks */,
167 | 569B56E5B05425CAE32676C6049DC8CB /* Pod */,
168 | 5CB66AAACA3977B45E9869C360E9F289 /* Support Files */,
169 | );
170 | name = shared;
171 | path = ../../shared;
172 | sourceTree = "";
173 | };
174 | /* End PBXGroup section */
175 |
176 | /* Begin PBXHeadersBuildPhase section */
177 | DA71CB665A4F7860DB550FAA48FB6AD2 /* Headers */ = {
178 | isa = PBXHeadersBuildPhase;
179 | buildActionMask = 2147483647;
180 | files = (
181 | 8801CBFD38B946597BD07145B2EEFC9F /* Pods-iosApp-umbrella.h in Headers */,
182 | );
183 | runOnlyForDeploymentPostprocessing = 0;
184 | };
185 | /* End PBXHeadersBuildPhase section */
186 |
187 | /* Begin PBXNativeTarget section */
188 | ED39C638569286489CD697A6C8964146 /* Pods-iosApp */ = {
189 | isa = PBXNativeTarget;
190 | buildConfigurationList = 9F1E85ECB672A0CC96333A6C6DF60EE6 /* Build configuration list for PBXNativeTarget "Pods-iosApp" */;
191 | buildPhases = (
192 | DA71CB665A4F7860DB550FAA48FB6AD2 /* Headers */,
193 | EB28A529759E3D2117E28CE3CB8387D3 /* Sources */,
194 | CC3CD5459C4A5476C5A93268587E63E7 /* Frameworks */,
195 | 0EC1C62FF9B25EAB2D236D122EAF4C98 /* Resources */,
196 | );
197 | buildRules = (
198 | );
199 | dependencies = (
200 | 4A9525469F8E46F3883CC6599FCCFEDB /* PBXTargetDependency */,
201 | );
202 | name = "Pods-iosApp";
203 | productName = Pods_iosApp;
204 | productReference = B097DD7534E741D5C41838011D755842 /* Pods-iosApp */;
205 | productType = "com.apple.product-type.framework";
206 | };
207 | /* End PBXNativeTarget section */
208 |
209 | /* Begin PBXProject section */
210 | BFDFE7DC352907FC980B868725387E98 /* Project object */ = {
211 | isa = PBXProject;
212 | attributes = {
213 | LastSwiftUpdateCheck = 1300;
214 | LastUpgradeCheck = 1300;
215 | };
216 | buildConfigurationList = 4821239608C13582E20E6DA73FD5F1F9 /* Build configuration list for PBXProject "Pods" */;
217 | compatibilityVersion = "Xcode 10.0";
218 | developmentRegion = en;
219 | hasScannedForEncodings = 0;
220 | knownRegions = (
221 | Base,
222 | en,
223 | );
224 | mainGroup = CF1408CF629C7361332E53B88F7BD30C;
225 | productRefGroup = 1F86AA6785DF34AFD5A71790761717DE /* Products */;
226 | projectDirPath = "";
227 | projectRoot = "";
228 | targets = (
229 | ED39C638569286489CD697A6C8964146 /* Pods-iosApp */,
230 | 8777C9F6889E59EFFD631D80AEE9048B /* shared */,
231 | );
232 | };
233 | /* End PBXProject section */
234 |
235 | /* Begin PBXResourcesBuildPhase section */
236 | 0EC1C62FF9B25EAB2D236D122EAF4C98 /* Resources */ = {
237 | isa = PBXResourcesBuildPhase;
238 | buildActionMask = 2147483647;
239 | files = (
240 | );
241 | runOnlyForDeploymentPostprocessing = 0;
242 | };
243 | /* End PBXResourcesBuildPhase section */
244 |
245 | /* Begin PBXShellScriptBuildPhase section */
246 | BEA8885189D408D600647BDC228A6A20 /* [CP-User] Build shared */ = {
247 | isa = PBXShellScriptBuildPhase;
248 | buildActionMask = 2147483647;
249 | files = (
250 | );
251 | name = "[CP-User] Build shared";
252 | runOnlyForDeploymentPostprocessing = 0;
253 | shellPath = /bin/sh;
254 | shellScript = " if [ \"YES\" = \"$OVERRIDE_KOTLIN_BUILD_IDE_SUPPORTED\" ]; then\n echo \"Skipping Gradle build task invocation due to OVERRIDE_KOTLIN_BUILD_IDE_SUPPORTED environment variable set to \"YES\"\"\n exit 0\n fi\n set -ev\n REPO_ROOT=\"$PODS_TARGET_SRCROOT\"\n \"$REPO_ROOT/../gradlew\" -p \"$REPO_ROOT\" $KOTLIN_PROJECT_PATH:syncFramework -Pkotlin.native.cocoapods.platform=$PLATFORM_NAME -Pkotlin.native.cocoapods.archs=\"$ARCHS\" -Pkotlin.native.cocoapods.configuration=\"$CONFIGURATION\"\n";
255 | };
256 | /* End PBXShellScriptBuildPhase section */
257 |
258 | /* Begin PBXSourcesBuildPhase section */
259 | EB28A529759E3D2117E28CE3CB8387D3 /* Sources */ = {
260 | isa = PBXSourcesBuildPhase;
261 | buildActionMask = 2147483647;
262 | files = (
263 | 8749C8E8DC500B064FA0BC7A78C38A2A /* Pods-iosApp-dummy.m in Sources */,
264 | );
265 | runOnlyForDeploymentPostprocessing = 0;
266 | };
267 | /* End PBXSourcesBuildPhase section */
268 |
269 | /* Begin PBXTargetDependency section */
270 | 4A9525469F8E46F3883CC6599FCCFEDB /* PBXTargetDependency */ = {
271 | isa = PBXTargetDependency;
272 | name = shared;
273 | target = 8777C9F6889E59EFFD631D80AEE9048B /* shared */;
274 | targetProxy = C1E4F2F8101E860063100BCC8448BC3B /* PBXContainerItemProxy */;
275 | };
276 | /* End PBXTargetDependency section */
277 |
278 | /* Begin XCBuildConfiguration section */
279 | 02DDCCED053337F381DEBAFDEC6F354F /* Release */ = {
280 | isa = XCBuildConfiguration;
281 | baseConfigurationReference = 9FECCB5AFF87D121F15BA01E683C7932 /* Pods-iosApp.release.xcconfig */;
282 | buildSettings = {
283 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO;
284 | CLANG_ENABLE_OBJC_WEAK = NO;
285 | "CODE_SIGN_IDENTITY[sdk=appletvos*]" = "";
286 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
287 | "CODE_SIGN_IDENTITY[sdk=watchos*]" = "";
288 | CURRENT_PROJECT_VERSION = 1;
289 | DEFINES_MODULE = YES;
290 | DYLIB_COMPATIBILITY_VERSION = 1;
291 | DYLIB_CURRENT_VERSION = 1;
292 | DYLIB_INSTALL_NAME_BASE = "@rpath";
293 | INFOPLIST_FILE = "Target Support Files/Pods-iosApp/Pods-iosApp-Info.plist";
294 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
295 | IPHONEOS_DEPLOYMENT_TARGET = 14.1;
296 | LD_RUNPATH_SEARCH_PATHS = (
297 | "$(inherited)",
298 | "@executable_path/Frameworks",
299 | "@loader_path/Frameworks",
300 | );
301 | MACH_O_TYPE = staticlib;
302 | MODULEMAP_FILE = "Target Support Files/Pods-iosApp/Pods-iosApp.modulemap";
303 | OTHER_LDFLAGS = "";
304 | OTHER_LIBTOOLFLAGS = "";
305 | PODS_ROOT = "$(SRCROOT)";
306 | PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.${PRODUCT_NAME:rfc1034identifier}";
307 | PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
308 | SDKROOT = iphoneos;
309 | SKIP_INSTALL = YES;
310 | TARGETED_DEVICE_FAMILY = "1,2";
311 | VALIDATE_PRODUCT = YES;
312 | VERSIONING_SYSTEM = "apple-generic";
313 | VERSION_INFO_PREFIX = "";
314 | };
315 | name = Release;
316 | };
317 | 593F10BFFA94DAC7D6E17FB8A7F32D72 /* Release */ = {
318 | isa = XCBuildConfiguration;
319 | buildSettings = {
320 | ALWAYS_SEARCH_USER_PATHS = NO;
321 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
322 | CLANG_ANALYZER_NONNULL = YES;
323 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
324 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
325 | CLANG_CXX_LIBRARY = "libc++";
326 | CLANG_ENABLE_MODULES = YES;
327 | CLANG_ENABLE_OBJC_ARC = YES;
328 | CLANG_ENABLE_OBJC_WEAK = YES;
329 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
330 | CLANG_WARN_BOOL_CONVERSION = YES;
331 | CLANG_WARN_COMMA = YES;
332 | CLANG_WARN_CONSTANT_CONVERSION = YES;
333 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
334 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
335 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
336 | CLANG_WARN_EMPTY_BODY = YES;
337 | CLANG_WARN_ENUM_CONVERSION = YES;
338 | CLANG_WARN_INFINITE_RECURSION = YES;
339 | CLANG_WARN_INT_CONVERSION = YES;
340 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
341 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
342 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
343 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
344 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
345 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
346 | CLANG_WARN_STRICT_PROTOTYPES = YES;
347 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
348 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
349 | CLANG_WARN_UNREACHABLE_CODE = YES;
350 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
351 | COPY_PHASE_STRIP = NO;
352 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
353 | ENABLE_NS_ASSERTIONS = NO;
354 | ENABLE_STRICT_OBJC_MSGSEND = YES;
355 | GCC_C_LANGUAGE_STANDARD = gnu11;
356 | GCC_NO_COMMON_BLOCKS = YES;
357 | GCC_PREPROCESSOR_DEFINITIONS = (
358 | "POD_CONFIGURATION_RELEASE=1",
359 | "$(inherited)",
360 | );
361 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
362 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
363 | GCC_WARN_UNDECLARED_SELECTOR = YES;
364 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
365 | GCC_WARN_UNUSED_FUNCTION = YES;
366 | GCC_WARN_UNUSED_VARIABLE = YES;
367 | IPHONEOS_DEPLOYMENT_TARGET = 14.1;
368 | MTL_ENABLE_DEBUG_INFO = NO;
369 | MTL_FAST_MATH = YES;
370 | PRODUCT_NAME = "$(TARGET_NAME)";
371 | STRIP_INSTALLED_PRODUCT = NO;
372 | SWIFT_COMPILATION_MODE = wholemodule;
373 | SWIFT_OPTIMIZATION_LEVEL = "-O";
374 | SWIFT_VERSION = 5.0;
375 | SYMROOT = "${SRCROOT}/../build";
376 | };
377 | name = Release;
378 | };
379 | A0374B8CF9A7D6A45F6D116D698D1C19 /* Debug */ = {
380 | isa = XCBuildConfiguration;
381 | buildSettings = {
382 | ALWAYS_SEARCH_USER_PATHS = NO;
383 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
384 | CLANG_ANALYZER_NONNULL = YES;
385 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
386 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
387 | CLANG_CXX_LIBRARY = "libc++";
388 | CLANG_ENABLE_MODULES = YES;
389 | CLANG_ENABLE_OBJC_ARC = YES;
390 | CLANG_ENABLE_OBJC_WEAK = YES;
391 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
392 | CLANG_WARN_BOOL_CONVERSION = YES;
393 | CLANG_WARN_COMMA = YES;
394 | CLANG_WARN_CONSTANT_CONVERSION = YES;
395 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
396 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
397 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
398 | CLANG_WARN_EMPTY_BODY = YES;
399 | CLANG_WARN_ENUM_CONVERSION = YES;
400 | CLANG_WARN_INFINITE_RECURSION = YES;
401 | CLANG_WARN_INT_CONVERSION = YES;
402 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
403 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
404 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
405 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
406 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
407 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
408 | CLANG_WARN_STRICT_PROTOTYPES = YES;
409 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
410 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
411 | CLANG_WARN_UNREACHABLE_CODE = YES;
412 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
413 | COPY_PHASE_STRIP = NO;
414 | DEBUG_INFORMATION_FORMAT = dwarf;
415 | ENABLE_STRICT_OBJC_MSGSEND = YES;
416 | ENABLE_TESTABILITY = YES;
417 | GCC_C_LANGUAGE_STANDARD = gnu11;
418 | GCC_DYNAMIC_NO_PIC = NO;
419 | GCC_NO_COMMON_BLOCKS = YES;
420 | GCC_OPTIMIZATION_LEVEL = 0;
421 | GCC_PREPROCESSOR_DEFINITIONS = (
422 | "POD_CONFIGURATION_DEBUG=1",
423 | "DEBUG=1",
424 | "$(inherited)",
425 | );
426 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
427 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
428 | GCC_WARN_UNDECLARED_SELECTOR = YES;
429 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
430 | GCC_WARN_UNUSED_FUNCTION = YES;
431 | GCC_WARN_UNUSED_VARIABLE = YES;
432 | IPHONEOS_DEPLOYMENT_TARGET = 14.1;
433 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
434 | MTL_FAST_MATH = YES;
435 | ONLY_ACTIVE_ARCH = YES;
436 | PRODUCT_NAME = "$(TARGET_NAME)";
437 | STRIP_INSTALLED_PRODUCT = NO;
438 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
439 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
440 | SWIFT_VERSION = 5.0;
441 | SYMROOT = "${SRCROOT}/../build";
442 | };
443 | name = Debug;
444 | };
445 | A7B4967B71249851CABD6EC29251E481 /* Debug */ = {
446 | isa = XCBuildConfiguration;
447 | baseConfigurationReference = 95B09EA82E7AF9ACCCCAF3E55C859116 /* shared.debug.xcconfig */;
448 | buildSettings = {
449 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
450 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
451 | CLANG_ENABLE_OBJC_WEAK = NO;
452 | IPHONEOS_DEPLOYMENT_TARGET = 14.1;
453 | LD_RUNPATH_SEARCH_PATHS = (
454 | "$(inherited)",
455 | "@executable_path/Frameworks",
456 | );
457 | SDKROOT = iphoneos;
458 | TARGETED_DEVICE_FAMILY = "1,2";
459 | };
460 | name = Debug;
461 | };
462 | A96D4527F178BD8C0DEB7EE72B9AAE09 /* Release */ = {
463 | isa = XCBuildConfiguration;
464 | baseConfigurationReference = 35548E3BD8DA30925E8FE97E67B84868 /* shared.release.xcconfig */;
465 | buildSettings = {
466 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
467 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
468 | CLANG_ENABLE_OBJC_WEAK = NO;
469 | IPHONEOS_DEPLOYMENT_TARGET = 14.1;
470 | LD_RUNPATH_SEARCH_PATHS = (
471 | "$(inherited)",
472 | "@executable_path/Frameworks",
473 | );
474 | SDKROOT = iphoneos;
475 | TARGETED_DEVICE_FAMILY = "1,2";
476 | VALIDATE_PRODUCT = YES;
477 | };
478 | name = Release;
479 | };
480 | AF088B6CD92A52AC4DCB62DEEC871231 /* Debug */ = {
481 | isa = XCBuildConfiguration;
482 | baseConfigurationReference = 3F64BADB16C311E9D09DAD0116F684F4 /* Pods-iosApp.debug.xcconfig */;
483 | buildSettings = {
484 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = NO;
485 | CLANG_ENABLE_OBJC_WEAK = NO;
486 | "CODE_SIGN_IDENTITY[sdk=appletvos*]" = "";
487 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "";
488 | "CODE_SIGN_IDENTITY[sdk=watchos*]" = "";
489 | CURRENT_PROJECT_VERSION = 1;
490 | DEFINES_MODULE = YES;
491 | DYLIB_COMPATIBILITY_VERSION = 1;
492 | DYLIB_CURRENT_VERSION = 1;
493 | DYLIB_INSTALL_NAME_BASE = "@rpath";
494 | INFOPLIST_FILE = "Target Support Files/Pods-iosApp/Pods-iosApp-Info.plist";
495 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
496 | IPHONEOS_DEPLOYMENT_TARGET = 14.1;
497 | LD_RUNPATH_SEARCH_PATHS = (
498 | "$(inherited)",
499 | "@executable_path/Frameworks",
500 | "@loader_path/Frameworks",
501 | );
502 | MACH_O_TYPE = staticlib;
503 | MODULEMAP_FILE = "Target Support Files/Pods-iosApp/Pods-iosApp.modulemap";
504 | OTHER_LDFLAGS = "";
505 | OTHER_LIBTOOLFLAGS = "";
506 | PODS_ROOT = "$(SRCROOT)";
507 | PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.${PRODUCT_NAME:rfc1034identifier}";
508 | PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
509 | SDKROOT = iphoneos;
510 | SKIP_INSTALL = YES;
511 | TARGETED_DEVICE_FAMILY = "1,2";
512 | VERSIONING_SYSTEM = "apple-generic";
513 | VERSION_INFO_PREFIX = "";
514 | };
515 | name = Debug;
516 | };
517 | /* End XCBuildConfiguration section */
518 |
519 | /* Begin XCConfigurationList section */
520 | 4821239608C13582E20E6DA73FD5F1F9 /* Build configuration list for PBXProject "Pods" */ = {
521 | isa = XCConfigurationList;
522 | buildConfigurations = (
523 | A0374B8CF9A7D6A45F6D116D698D1C19 /* Debug */,
524 | 593F10BFFA94DAC7D6E17FB8A7F32D72 /* Release */,
525 | );
526 | defaultConfigurationIsVisible = 0;
527 | defaultConfigurationName = Release;
528 | };
529 | 8349D8E2EC974421A14EF8ABFF6AD6DC /* Build configuration list for PBXAggregateTarget "shared" */ = {
530 | isa = XCConfigurationList;
531 | buildConfigurations = (
532 | A7B4967B71249851CABD6EC29251E481 /* Debug */,
533 | A96D4527F178BD8C0DEB7EE72B9AAE09 /* Release */,
534 | );
535 | defaultConfigurationIsVisible = 0;
536 | defaultConfigurationName = Release;
537 | };
538 | 9F1E85ECB672A0CC96333A6C6DF60EE6 /* Build configuration list for PBXNativeTarget "Pods-iosApp" */ = {
539 | isa = XCConfigurationList;
540 | buildConfigurations = (
541 | AF088B6CD92A52AC4DCB62DEEC871231 /* Debug */,
542 | 02DDCCED053337F381DEBAFDEC6F354F /* Release */,
543 | );
544 | defaultConfigurationIsVisible = 0;
545 | defaultConfigurationName = Release;
546 | };
547 | /* End XCConfigurationList section */
548 | };
549 | rootObject = BFDFE7DC352907FC980B868725387E98 /* Project object */;
550 | }
551 |
--------------------------------------------------------------------------------