├── samples ├── .gitignore ├── app │ ├── .gitignore │ ├── src │ │ ├── main │ │ │ ├── ic_launcher-playstore.png │ │ │ └── res │ │ │ │ ├── drawable-hdpi │ │ │ │ └── app_logo.png │ │ │ │ ├── drawable-mdpi │ │ │ │ └── app_logo.png │ │ │ │ ├── drawable-xhdpi │ │ │ │ └── app_logo.png │ │ │ │ ├── drawable-xxhdpi │ │ │ │ └── app_logo.png │ │ │ │ ├── drawable-xxxhdpi │ │ │ │ └── app_logo.png │ │ │ │ ├── mipmap-hdpi │ │ │ │ ├── ic_launcher_round.png │ │ │ │ └── ic_launcher_foreground.png │ │ │ │ ├── mipmap-mdpi │ │ │ │ ├── ic_launcher_round.png │ │ │ │ └── ic_launcher_foreground.png │ │ │ │ ├── mipmap-xhdpi │ │ │ │ ├── ic_launcher_round.png │ │ │ │ └── ic_launcher_foreground.png │ │ │ │ ├── mipmap-xxhdpi │ │ │ │ ├── ic_launcher_round.png │ │ │ │ └── ic_launcher_foreground.png │ │ │ │ ├── mipmap-xxxhdpi │ │ │ │ ├── ic_launcher_round.png │ │ │ │ └── ic_launcher_foreground.png │ │ │ │ ├── values │ │ │ │ ├── strings.xml │ │ │ │ ├── ic_launcher_background.xml │ │ │ │ └── colors.xml │ │ │ │ ├── mipmap-anydpi-v26 │ │ │ │ ├── ic_launcher.xml │ │ │ │ └── ic_launcher_round.xml │ │ │ │ └── drawable │ │ │ │ └── bg_splash.xml │ │ ├── remote │ │ │ ├── ic_launcher-playstore.png │ │ │ ├── res │ │ │ │ ├── mipmap-hdpi │ │ │ │ │ ├── ic_launcher.png │ │ │ │ │ ├── ic_launcher_round.png │ │ │ │ │ └── ic_launcher_foreground.png │ │ │ │ ├── mipmap-mdpi │ │ │ │ │ ├── ic_launcher.png │ │ │ │ │ ├── ic_launcher_round.png │ │ │ │ │ └── ic_launcher_foreground.png │ │ │ │ ├── mipmap-xhdpi │ │ │ │ │ ├── ic_launcher.png │ │ │ │ │ ├── ic_launcher_round.png │ │ │ │ │ └── ic_launcher_foreground.png │ │ │ │ ├── mipmap-xxhdpi │ │ │ │ │ ├── ic_launcher.png │ │ │ │ │ ├── ic_launcher_round.png │ │ │ │ │ └── ic_launcher_foreground.png │ │ │ │ ├── mipmap-xxxhdpi │ │ │ │ │ ├── ic_launcher.png │ │ │ │ │ ├── ic_launcher_round.png │ │ │ │ │ └── ic_launcher_foreground.png │ │ │ │ ├── values │ │ │ │ │ └── ic_launcher_background.xml │ │ │ │ └── mipmap-anydpi-v26 │ │ │ │ │ ├── ic_launcher.xml │ │ │ │ │ └── ic_launcher_round.xml │ │ │ └── kotlin │ │ │ │ └── io │ │ │ │ └── github │ │ │ │ └── xlopec │ │ │ │ └── reader │ │ │ │ └── app │ │ │ │ └── AndroidAppComponent.kt │ │ └── default │ │ │ └── kotlin │ │ │ └── io │ │ │ └── github │ │ │ └── xlopec │ │ │ └── reader │ │ │ └── app │ │ │ └── AndroidAppComponent.kt │ └── proguard-rules.pro ├── counter │ ├── .gitignore │ ├── build.gradle.kts │ └── src │ │ └── main │ │ └── java │ │ └── io │ │ └── github │ │ └── xlopec │ │ └── counter │ │ └── Counter.kt ├── iosApp │ ├── iosApp │ │ ├── Assets.xcassets │ │ │ └── Contents.json │ │ ├── Preview Content │ │ │ └── Preview Assets.xcassets │ │ │ │ └── Contents.json │ │ ├── NewsReaderApp.swift │ │ ├── AppView.swift │ │ └── Base.lproj │ │ │ └── LaunchScreen.storyboard │ ├── iosApp.xcodeproj │ │ └── project.xcworkspace │ │ │ ├── contents.xcworkspacedata │ │ │ └── xcshareddata │ │ │ └── IDEWorkspaceChecks.plist │ ├── iosAppTests │ │ ├── Info.plist │ │ └── iosAppTests.swift │ └── iosAppUITests │ │ ├── Info.plist │ │ └── iosAppUITests.swift └── shared-app-lib │ ├── src │ ├── commonMain │ │ ├── composeResources │ │ │ └── font │ │ │ │ ├── roboto_bold.ttf │ │ │ │ ├── roboto_medium.ttf │ │ │ │ └── roboto_regular.ttf │ │ ├── kotlin │ │ │ └── io │ │ │ │ └── github │ │ │ │ └── xlopec │ │ │ │ └── reader │ │ │ │ └── app │ │ │ │ ├── model │ │ │ │ ├── DateTime.kt │ │ │ │ ├── Country.kt │ │ │ │ └── Source.kt │ │ │ │ ├── ui │ │ │ │ ├── screens │ │ │ │ │ ├── BackHandler.kt │ │ │ │ │ └── filters │ │ │ │ │ │ └── FiltersSubtitle.kt │ │ │ │ ├── misc │ │ │ │ │ └── InsetsAwareBottomNavigation.kt │ │ │ │ └── theme │ │ │ │ │ └── Typography.kt │ │ │ │ ├── ResolverDslBuilders.kt │ │ │ │ ├── feature │ │ │ │ ├── article │ │ │ │ │ ├── details │ │ │ │ │ │ ├── ArticleDetailsModule.kt │ │ │ │ │ │ ├── ArticleDetailsResolver.kt │ │ │ │ │ │ ├── DoOpenInBrowser.kt │ │ │ │ │ │ ├── Message.kt │ │ │ │ │ │ └── ArticleDetailsState.kt │ │ │ │ │ └── list │ │ │ │ │ │ ├── ArticlesResolver.kt │ │ │ │ │ │ └── Module.kt │ │ │ │ ├── network │ │ │ │ │ └── EncoderExtensions.kt │ │ │ │ ├── settings │ │ │ │ │ ├── SettingsScreen.kt │ │ │ │ │ └── Message.kt │ │ │ │ └── filter │ │ │ │ │ ├── Module.kt │ │ │ │ │ └── SuggestionsInitializer.kt │ │ │ │ ├── misc │ │ │ │ └── StringExtensions.kt │ │ │ │ ├── Environment.kt │ │ │ │ ├── AppUpdater.kt │ │ │ │ ├── AppResolver.kt │ │ │ │ ├── MessageHandler.kt │ │ │ │ ├── Message.kt │ │ │ │ ├── command │ │ │ │ └── Command.kt │ │ │ │ └── Screens.kt │ │ └── sqldelight │ │ │ └── io │ │ │ └── github │ │ │ └── xlopec │ │ │ └── reader │ │ │ └── app │ │ │ └── storage │ │ │ ├── RecentSearches.sq │ │ │ ├── Filters.sq │ │ │ └── Articles.sq │ ├── iosMain │ │ └── kotlin │ │ │ └── io │ │ │ └── github │ │ │ └── xlopec │ │ │ └── reader │ │ │ └── app │ │ │ ├── ui │ │ │ └── screens │ │ │ │ └── BackHandler.ios.kt │ │ │ ├── model │ │ │ └── DateTime.ios.kt │ │ │ └── feature │ │ │ ├── article │ │ │ ├── details │ │ │ │ ├── ArticleDetailsModule.kt │ │ │ │ └── ArticleDetailsResolver.kt │ │ │ └── list │ │ │ │ └── NewsApi.kt │ │ │ ├── network │ │ │ └── PlatformSerializers.kt │ │ │ └── storage │ │ │ └── LocalStorage.kt │ └── androidMain │ │ ├── kotlin │ │ └── io │ │ │ └── github │ │ │ └── xlopec │ │ │ └── reader │ │ │ └── app │ │ │ ├── ui │ │ │ └── screens │ │ │ │ ├── BackHandler.android.kt │ │ │ │ └── InsetsController.kt │ │ │ ├── model │ │ │ └── DateTime.android.kt │ │ │ ├── feature │ │ │ ├── article │ │ │ │ └── details │ │ │ │ │ └── ArticleDetailsModule.kt │ │ │ ├── network │ │ │ │ └── PlatformSerializers.kt │ │ │ └── storage │ │ │ │ └── LocalStorageImpl.kt │ │ │ └── ContextExtensions.kt │ │ ├── res │ │ ├── values │ │ │ └── preloaded_fonts.xml │ │ └── font │ │ │ ├── roboto.xml │ │ │ ├── roboto_bold.xml │ │ │ └── roboto_medium.xml │ │ └── AndroidManifest.xml │ └── .gitignore ├── tea-data ├── .gitignore └── src │ ├── commonMain │ └── kotlin │ │ └── io │ │ └── github │ │ └── xlopec │ │ └── tea │ │ └── data │ │ ├── Date.kt │ │ ├── UUID.kt │ │ └── Url.kt │ ├── jvmMain │ └── kotlin │ │ └── io │ │ └── github │ │ └── xlopec │ │ └── tea │ │ └── data │ │ ├── Date.jvm.kt │ │ ├── UUID.jvm.kt │ │ └── Url.jvm.kt │ └── iosMain │ └── kotlin │ └── io │ └── github │ └── xlopec │ └── tea │ └── data │ ├── UUID.ios.kt │ ├── Date.ios.kt │ └── Url.ios.kt ├── tea-test └── .gitignore ├── tea-navigation ├── .gitignore └── src │ └── commonMain │ └── kotlin │ └── io │ └── github │ └── xlopec │ └── tea │ └── navigation │ └── NavStackEntry.kt ├── tea-time-travel ├── .gitignore └── src │ ├── jvmTest │ └── kotlin │ │ └── io │ │ └── github │ │ └── xlopec │ │ └── tea │ │ └── time │ │ └── travel │ │ └── component │ │ └── ComponentException.kt │ └── commonMain │ └── kotlin │ └── io │ └── github │ └── xlopec │ └── tea │ └── time │ └── travel │ └── component │ └── internal │ └── FlowExtension.kt ├── tea-time-travel-plugin ├── .gitignore ├── src │ ├── main │ │ └── java │ │ │ └── io │ │ │ └── github │ │ │ └── xlopec │ │ │ └── tea │ │ │ └── time │ │ │ └── travel │ │ │ └── plugin │ │ │ ├── model │ │ │ ├── SnapshotId.kt │ │ │ ├── Input.kt │ │ │ ├── SnapshotMeta.kt │ │ │ ├── Server.kt │ │ │ ├── Snapshot.kt │ │ │ └── PInt.kt │ │ │ ├── util │ │ │ ├── EitherExtensions.kt │ │ │ ├── Action.kt │ │ │ ├── GsonExtensions.kt │ │ │ ├── ChooserUtils.kt │ │ │ └── FlowExtensions.kt │ │ │ ├── feature │ │ │ ├── server │ │ │ │ ├── Message.kt │ │ │ │ ├── RemoteCall.kt │ │ │ │ ├── Command.kt │ │ │ │ └── Updater.kt │ │ │ ├── storage │ │ │ │ ├── Message.kt │ │ │ │ ├── Commands.kt │ │ │ │ └── Updater.kt │ │ │ ├── component │ │ │ │ └── ui │ │ │ │ │ ├── SnapshotActionItemsPreview.kt │ │ │ │ │ ├── ComponentTab.kt │ │ │ │ │ └── TreePreview.kt │ │ │ ├── settings │ │ │ │ └── PluginSettingsNotifier.kt │ │ │ └── notification │ │ │ │ ├── Command.kt │ │ │ │ └── Notifications.kt │ │ │ ├── ui │ │ │ ├── theme │ │ │ │ └── ThemeChangeListener.kt │ │ │ └── NoIndicationClickable.kt │ │ │ └── integration │ │ │ ├── AppUpdater.kt │ │ │ ├── Command.kt │ │ │ ├── Message.kt │ │ │ └── AppResolver.kt │ └── test │ │ ├── integration │ │ └── kotlin │ │ │ └── io │ │ │ └── github │ │ │ └── xlopec │ │ │ └── tea │ │ │ └── time │ │ │ └── travel │ │ │ └── plugin │ │ │ ├── environment │ │ │ ├── SimpleTestNotificationResolver.kt │ │ │ ├── TestPlatform.kt │ │ │ ├── TestServerCommandResolver.kt │ │ │ └── TestEnvironment.kt │ │ │ └── util │ │ │ ├── Finders.kt │ │ │ ├── TestWindow.kt │ │ │ └── ComposeRuleExtensions.kt │ │ ├── unit │ │ └── kotlin │ │ │ └── io │ │ │ └── github │ │ │ └── xlopec │ │ │ └── tea │ │ │ └── time │ │ │ └── travel │ │ │ └── plugin │ │ │ ├── data │ │ │ └── NumberExtensions.kt │ │ │ ├── util │ │ │ └── LoggerStub.kt │ │ │ ├── integration │ │ │ └── PlatformTest.kt │ │ │ └── model │ │ │ └── StateExtensionsTest.kt │ │ └── resources │ │ └── test_state.json └── resources │ ├── images │ ├── execute.svg │ ├── suspend.svg │ ├── expand.svg │ ├── execute_dark.svg │ ├── suspend_dark.svg │ ├── dropdown.svg │ ├── remove.svg │ ├── remove_dark.svg │ ├── dropdown_dark.svg │ ├── snapshotGutter.svg │ ├── snapshotGutter_dark.svg │ ├── inlineCopy.svg │ ├── import_dark.svg │ ├── close.svg │ ├── collapse.svg │ ├── import.svg │ ├── export.svg │ ├── export_dark.svg │ ├── settings.svg │ ├── settings_dark.svg │ ├── class.svg │ ├── property.svg │ ├── updateRunningApplication.svg │ └── updateRunningApplication_dark.svg │ ├── logback.xml │ └── META-INF │ ├── pluginIcon.svg │ └── pluginIcon_dark.svg ├── tea-time-travel-protocol ├── .gitignore ├── build.gradle.kts └── src │ └── commonMain │ └── kotlin │ └── io │ └── github │ └── xlopec │ └── tea │ └── time │ └── travel │ └── protocol │ └── ComponentId.kt ├── tea-time-travel-adapter-gson ├── .gitignore └── build.gradle.kts ├── res ├── demo.gif └── tea-bag-logo.png ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── .gitmodules ├── .idea └── codeStyles │ ├── codeStyleConfig.xml │ └── Project.xml ├── tea-core ├── .gitignore └── src │ ├── commonTest │ └── kotlin │ │ └── io │ │ └── github │ │ └── xlopec │ │ └── tea │ │ └── core │ │ └── misc │ │ ├── Thread.kt │ │ └── ComponentException.kt │ ├── jvmTest │ └── kotlin │ │ └── io │ │ └── github │ │ └── xlopec │ │ └── tea │ │ └── core │ │ └── misc │ │ └── CurrentThreadName.kt │ └── iosTest │ └── kotlin │ └── io │ └── github │ └── xlopec │ └── tea │ └── core │ └── misc │ └── CurrentThreadName.kt ├── .gitignore ├── LICENSE ├── .run └── Tea-bag [samples_app_assembleDefaultDebug samples_app_installDefaultDebug].run.xml └── hooks └── pre-commit.sh /samples/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /tea-data/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /tea-test/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /samples/app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /samples/counter/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /tea-navigation/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /tea-time-travel/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /tea-time-travel-plugin/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /tea-time-travel-protocol/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /tea-time-travel-adapter-gson/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /res/demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Xlopec/Tea-bag/HEAD/res/demo.gif -------------------------------------------------------------------------------- /res/tea-bag-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Xlopec/Tea-bag/HEAD/res/tea-bag-logo.png -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Xlopec/Tea-bag/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /samples/iosApp/iosApp/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /samples/app/src/main/ic_launcher-playstore.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Xlopec/Tea-bag/HEAD/samples/app/src/main/ic_launcher-playstore.png -------------------------------------------------------------------------------- /samples/app/src/remote/ic_launcher-playstore.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Xlopec/Tea-bag/HEAD/samples/app/src/remote/ic_launcher-playstore.png -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "compose-jetbrains-theme"] 2 | path = compose-jetbrains-theme 3 | url = https://github.com/ButterCam/compose-jetbrains-theme 4 | -------------------------------------------------------------------------------- /samples/app/src/main/res/drawable-hdpi/app_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Xlopec/Tea-bag/HEAD/samples/app/src/main/res/drawable-hdpi/app_logo.png -------------------------------------------------------------------------------- /samples/app/src/main/res/drawable-mdpi/app_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Xlopec/Tea-bag/HEAD/samples/app/src/main/res/drawable-mdpi/app_logo.png -------------------------------------------------------------------------------- /samples/app/src/main/res/drawable-xhdpi/app_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Xlopec/Tea-bag/HEAD/samples/app/src/main/res/drawable-xhdpi/app_logo.png -------------------------------------------------------------------------------- /samples/app/src/main/res/drawable-xxhdpi/app_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Xlopec/Tea-bag/HEAD/samples/app/src/main/res/drawable-xxhdpi/app_logo.png -------------------------------------------------------------------------------- /samples/app/src/main/res/drawable-xxxhdpi/app_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Xlopec/Tea-bag/HEAD/samples/app/src/main/res/drawable-xxxhdpi/app_logo.png -------------------------------------------------------------------------------- /samples/app/src/remote/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Xlopec/Tea-bag/HEAD/samples/app/src/remote/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /samples/app/src/remote/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Xlopec/Tea-bag/HEAD/samples/app/src/remote/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /samples/iosApp/iosApp/Preview Content/Preview Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /samples/app/src/remote/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Xlopec/Tea-bag/HEAD/samples/app/src/remote/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /samples/app/src/remote/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Xlopec/Tea-bag/HEAD/samples/app/src/remote/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /samples/app/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Xlopec/Tea-bag/HEAD/samples/app/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /samples/app/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Xlopec/Tea-bag/HEAD/samples/app/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /samples/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Xlopec/Tea-bag/HEAD/samples/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /samples/app/src/remote/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Xlopec/Tea-bag/HEAD/samples/app/src/remote/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /samples/counter/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | id("org.jetbrains.kotlin.jvm") 3 | } 4 | 5 | dependencies { 6 | implementation(project(":tea-core")) 7 | } 8 | -------------------------------------------------------------------------------- /samples/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Xlopec/Tea-bag/HEAD/samples/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /samples/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Xlopec/Tea-bag/HEAD/samples/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /samples/app/src/remote/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Xlopec/Tea-bag/HEAD/samples/app/src/remote/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /samples/app/src/remote/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Xlopec/Tea-bag/HEAD/samples/app/src/remote/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /samples/app/src/remote/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Xlopec/Tea-bag/HEAD/samples/app/src/remote/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /samples/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Xlopec/Tea-bag/HEAD/samples/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /samples/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Xlopec/Tea-bag/HEAD/samples/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /samples/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Xlopec/Tea-bag/HEAD/samples/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /samples/app/src/remote/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Xlopec/Tea-bag/HEAD/samples/app/src/remote/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /samples/app/src/remote/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Xlopec/Tea-bag/HEAD/samples/app/src/remote/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /samples/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Xlopec/Tea-bag/HEAD/samples/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /samples/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Xlopec/Tea-bag/HEAD/samples/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /samples/app/src/remote/res/mipmap-hdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Xlopec/Tea-bag/HEAD/samples/app/src/remote/res/mipmap-hdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /samples/app/src/remote/res/mipmap-mdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Xlopec/Tea-bag/HEAD/samples/app/src/remote/res/mipmap-mdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /samples/app/src/remote/res/mipmap-xhdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Xlopec/Tea-bag/HEAD/samples/app/src/remote/res/mipmap-xhdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /samples/app/src/remote/res/mipmap-xxhdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Xlopec/Tea-bag/HEAD/samples/app/src/remote/res/mipmap-xxhdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /samples/app/src/remote/res/mipmap-xxxhdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Xlopec/Tea-bag/HEAD/samples/app/src/remote/res/mipmap-xxxhdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /.idea/codeStyles/codeStyleConfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | -------------------------------------------------------------------------------- /samples/shared-app-lib/src/commonMain/composeResources/font/roboto_bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Xlopec/Tea-bag/HEAD/samples/shared-app-lib/src/commonMain/composeResources/font/roboto_bold.ttf -------------------------------------------------------------------------------- /samples/shared-app-lib/src/commonMain/composeResources/font/roboto_medium.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Xlopec/Tea-bag/HEAD/samples/shared-app-lib/src/commonMain/composeResources/font/roboto_medium.ttf -------------------------------------------------------------------------------- /samples/shared-app-lib/src/commonMain/composeResources/font/roboto_regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Xlopec/Tea-bag/HEAD/samples/shared-app-lib/src/commonMain/composeResources/font/roboto_regular.ttf -------------------------------------------------------------------------------- /samples/shared-app-lib/src/commonMain/kotlin/io/github/xlopec/reader/app/model/DateTime.kt: -------------------------------------------------------------------------------- 1 | package io.github.xlopec.reader.app.model 2 | 3 | import io.github.xlopec.tea.data.Date 4 | 5 | public expect fun Date.formatted(): String 6 | -------------------------------------------------------------------------------- /samples/iosApp/iosApp.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /tea-time-travel-plugin/src/main/java/io/github/xlopec/tea/time/travel/plugin/model/SnapshotId.kt: -------------------------------------------------------------------------------- 1 | package io.github.xlopec.tea.time.travel.plugin.model 2 | 3 | import java.util.* 4 | 5 | @JvmInline 6 | value class SnapshotId( 7 | val value: UUID 8 | ) 9 | -------------------------------------------------------------------------------- /samples/shared-app-lib/src/commonMain/kotlin/io/github/xlopec/reader/app/model/Country.kt: -------------------------------------------------------------------------------- 1 | package io.github.xlopec.reader.app.model 2 | 3 | import kotlin.jvm.JvmInline 4 | 5 | @JvmInline 6 | public value class Country( 7 | internal val code: String 8 | ) 9 | -------------------------------------------------------------------------------- /tea-time-travel-plugin/src/main/java/io/github/xlopec/tea/time/travel/plugin/util/EitherExtensions.kt: -------------------------------------------------------------------------------- 1 | package io.github.xlopec.tea.time.travel.plugin.util 2 | 3 | import arrow.core.Either 4 | 5 | fun Either.foldSuper(): C where L : C, R : C = fold({ it }, { it }) 6 | -------------------------------------------------------------------------------- /samples/shared-app-lib/src/commonMain/kotlin/io/github/xlopec/reader/app/ui/screens/BackHandler.kt: -------------------------------------------------------------------------------- 1 | package io.github.xlopec.reader.app.ui.screens 2 | 3 | import androidx.compose.runtime.Composable 4 | 5 | @Composable 6 | internal expect fun BackHandler( 7 | onBack: () -> Unit 8 | ) 9 | -------------------------------------------------------------------------------- /tea-time-travel-plugin/src/main/java/io/github/xlopec/tea/time/travel/plugin/model/Input.kt: -------------------------------------------------------------------------------- 1 | package io.github.xlopec.tea.time.travel.plugin.model 2 | 3 | import arrow.core.Validated 4 | 5 | data class Input( 6 | val input: String, 7 | val value: Validated, 8 | ) 9 | -------------------------------------------------------------------------------- /samples/shared-app-lib/src/iosMain/kotlin/io/github/xlopec/reader/app/ui/screens/BackHandler.ios.kt: -------------------------------------------------------------------------------- 1 | package io.github.xlopec.reader.app.ui.screens 2 | 3 | import androidx.compose.runtime.Composable 4 | 5 | @Composable 6 | internal actual fun BackHandler( 7 | onBack: () -> Unit 8 | ) = Unit 9 | -------------------------------------------------------------------------------- /tea-core/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | *.iml 3 | .gradle 4 | /local.properties 5 | /.idea/caches 6 | /.idea/libraries 7 | /.idea/modules.xml 8 | /.idea/workspace.xml 9 | /.idea/navEditor.xml 10 | /.idea/assetWizardSettings.xml 11 | /.idea/dbnavigator.xml 12 | .DS_Store 13 | /captures 14 | .externalNativeBuild 15 | androidx_prebuilts/ -------------------------------------------------------------------------------- /tea-time-travel-plugin/src/main/java/io/github/xlopec/tea/time/travel/plugin/feature/server/Message.kt: -------------------------------------------------------------------------------- 1 | package io.github.xlopec.tea.time.travel.plugin.feature.server 2 | 3 | import io.github.xlopec.tea.time.travel.plugin.integration.ServerMessage 4 | 5 | object StartServer : ServerMessage 6 | 7 | object StopServer : ServerMessage 8 | -------------------------------------------------------------------------------- /samples/shared-app-lib/src/androidMain/kotlin/io/github/xlopec/reader/app/ui/screens/BackHandler.android.kt: -------------------------------------------------------------------------------- 1 | package io.github.xlopec.reader.app.ui.screens 2 | 3 | import androidx.compose.runtime.Composable 4 | 5 | @Composable 6 | internal actual fun BackHandler(onBack: () -> Unit) = androidx.activity.compose.BackHandler(onBack = onBack) 7 | -------------------------------------------------------------------------------- /samples/shared-app-lib/src/androidMain/res/values/preloaded_fonts.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | @font/roboto 5 | @font/roboto_bold 6 | @font/roboto_medium 7 | 8 | 9 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | *.jks 3 | .gradle 4 | /local.properties 5 | # User-specific stuff: 6 | .idea/* 7 | .kotlin/ 8 | 9 | !.idea/codeStyles/ 10 | 11 | # Gradle: 12 | /projectFilesBackup*/ 13 | .DS_Store 14 | /build 15 | /captures 16 | .externalNativeBuild 17 | androidx_prebuilts/ 18 | out/ 19 | 20 | /buildSrc/local.properties 21 | .fleet/ -------------------------------------------------------------------------------- /samples/shared-app-lib/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | *.iml 3 | .gradle 4 | /local.properties 5 | /.idea/caches 6 | /.idea/libraries 7 | /.idea/modules.xml 8 | /.idea/workspace.xml 9 | /.idea/navEditor.xml 10 | /.idea/assetWizardSettings.xml 11 | /.idea/dbnavigator.xml 12 | .DS_Store 13 | /captures 14 | .externalNativeBuild 15 | androidx_prebuilts/ -------------------------------------------------------------------------------- /samples/iosApp/iosApp.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /tea-time-travel-plugin/src/main/java/io/github/xlopec/tea/time/travel/plugin/model/SnapshotMeta.kt: -------------------------------------------------------------------------------- 1 | package io.github.xlopec.tea.time.travel.plugin.model 2 | 3 | import androidx.compose.runtime.Immutable 4 | import java.time.LocalDateTime 5 | 6 | @Immutable 7 | data class SnapshotMeta( 8 | val id: SnapshotId, 9 | val timestamp: LocalDateTime 10 | ) 11 | -------------------------------------------------------------------------------- /tea-time-travel-plugin/resources/images/execute.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /tea-time-travel-plugin/resources/images/suspend.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /tea-time-travel-plugin/resources/images/expand.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /tea-time-travel-plugin/resources/images/execute_dark.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /tea-navigation/src/commonMain/kotlin/io/github/xlopec/tea/navigation/NavStackEntry.kt: -------------------------------------------------------------------------------- 1 | package io.github.xlopec.tea.navigation 2 | 3 | /** 4 | * Represents navigation stack entry, each navigation entry should provide a unique identifier 5 | */ 6 | public interface NavStackEntry { 7 | /** 8 | * Unique stack entry identifier 9 | */ 10 | public val id: T 11 | } 12 | -------------------------------------------------------------------------------- /tea-time-travel-plugin/resources/images/suspend_dark.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /tea-time-travel-plugin/resources/images/dropdown.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /tea-time-travel-plugin/resources/images/remove.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /tea-time-travel-plugin/resources/images/remove_dark.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /tea-time-travel-plugin/resources/images/dropdown_dark.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /samples/shared-app-lib/src/androidMain/res/font/roboto.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | -------------------------------------------------------------------------------- /samples/shared-app-lib/src/iosMain/kotlin/io/github/xlopec/reader/app/model/DateTime.ios.kt: -------------------------------------------------------------------------------- 1 | package io.github.xlopec.reader.app.model 2 | 3 | import io.github.xlopec.tea.data.Date 4 | import platform.Foundation.NSDateFormatter 5 | 6 | private val DateFormatter = NSDateFormatter().apply { 7 | dateFormat = "dd MMM' at 'hh:mm" 8 | } 9 | 10 | public actual fun Date.formatted(): String = DateFormatter.stringFromDate(this) 11 | -------------------------------------------------------------------------------- /.idea/codeStyles/Project.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 9 | 10 | -------------------------------------------------------------------------------- /samples/shared-app-lib/src/androidMain/res/font/roboto_bold.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | -------------------------------------------------------------------------------- /samples/shared-app-lib/src/androidMain/res/font/roboto_medium.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | -------------------------------------------------------------------------------- /samples/shared-app-lib/src/androidMain/kotlin/io/github/xlopec/reader/app/model/DateTime.android.kt: -------------------------------------------------------------------------------- 1 | package io.github.xlopec.reader.app.model 2 | 3 | import io.github.xlopec.tea.data.Date 4 | import java.text.SimpleDateFormat 5 | import java.util.* 6 | 7 | private val DateFormatter: SimpleDateFormat by lazy { 8 | SimpleDateFormat("dd MMM' at 'hh:mm", Locale.getDefault()) 9 | } 10 | 11 | public actual fun Date.formatted(): String = DateFormatter.format(this) 12 | -------------------------------------------------------------------------------- /tea-time-travel-plugin/src/main/java/io/github/xlopec/tea/time/travel/plugin/feature/server/RemoteCall.kt: -------------------------------------------------------------------------------- 1 | package io.github.xlopec.tea.time.travel.plugin.feature.server 2 | 3 | import io.github.xlopec.tea.time.travel.gson.GsonClientMessage 4 | import io.github.xlopec.tea.time.travel.protocol.ComponentId 5 | import java.util.UUID 6 | 7 | data class RemoteCall( 8 | val callId: UUID, 9 | val component: ComponentId, 10 | val message: GsonClientMessage 11 | ) 12 | -------------------------------------------------------------------------------- /tea-time-travel-plugin/src/main/java/io/github/xlopec/tea/time/travel/plugin/ui/theme/ThemeChangeListener.kt: -------------------------------------------------------------------------------- 1 | package io.github.xlopec.tea.time.travel.plugin.ui.theme 2 | 3 | import com.intellij.ide.ui.LafManager 4 | import com.intellij.ide.ui.LafManagerListener 5 | 6 | internal class ThemeChangeListener( 7 | val updateColors: () -> Unit 8 | ) : LafManagerListener { 9 | override fun lookAndFeelChanged(source: LafManager) { 10 | updateColors() 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /tea-time-travel-plugin/resources/images/snapshotGutter.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /tea-time-travel-plugin/src/test/integration/kotlin/io/github/xlopec/tea/time/travel/plugin/environment/SimpleTestNotificationResolver.kt: -------------------------------------------------------------------------------- 1 | package io.github.xlopec.tea.time.travel.plugin.environment 2 | 3 | import io.github.xlopec.tea.time.travel.plugin.feature.notification.NotificationResolver 4 | import io.github.xlopec.tea.time.travel.plugin.integration.NotifyCommand 5 | 6 | class SimpleTestNotificationResolver : NotificationResolver { 7 | override fun resolve(command: NotifyCommand) = Unit 8 | } 9 | -------------------------------------------------------------------------------- /tea-time-travel-plugin/resources/images/snapshotGutter_dark.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /tea-time-travel-plugin/src/main/java/io/github/xlopec/tea/time/travel/plugin/util/Action.kt: -------------------------------------------------------------------------------- 1 | @file:Suppress("FunctionName") 2 | 3 | package io.github.xlopec.tea.time.travel.plugin.util 4 | 5 | import com.intellij.openapi.actionSystem.AnAction 6 | import com.intellij.openapi.actionSystem.AnActionEvent 7 | 8 | fun Action( 9 | text: String, 10 | onAction: (AnActionEvent) -> Unit 11 | ): AnAction = object : AnAction(text) { 12 | override fun actionPerformed(p0: AnActionEvent) = onAction(p0) 13 | } 14 | -------------------------------------------------------------------------------- /tea-time-travel-plugin/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | %d{YYYY-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /samples/app/src/default/kotlin/io/github/xlopec/reader/app/AndroidAppComponent.kt: -------------------------------------------------------------------------------- 1 | @file:Suppress("FunctionName") 2 | 3 | package io.github.xlopec.reader.app 4 | 5 | import android.app.Application 6 | import io.github.xlopec.reader.BuildConfig 7 | import kotlinx.coroutines.CoroutineScope 8 | 9 | fun AppComponent( 10 | application: Application, 11 | scope: CoroutineScope, 12 | ) = Environment(BuildConfig.DEBUG, application, scope) 13 | .let { env -> AppComponent(env, AppInitializer(application.systemDarkModeEnabled, env)) } 14 | -------------------------------------------------------------------------------- /tea-time-travel-plugin/src/main/java/io/github/xlopec/tea/time/travel/plugin/feature/storage/Message.kt: -------------------------------------------------------------------------------- 1 | package io.github.xlopec.tea.time.travel.plugin.feature.storage 2 | 3 | import io.github.xlopec.tea.time.travel.plugin.integration.StoreMessage 4 | import io.github.xlopec.tea.time.travel.protocol.ComponentId 5 | import java.io.File 6 | 7 | data class ExportSessions( 8 | val ids: Collection, 9 | val dir: File 10 | ) : StoreMessage 11 | 12 | @JvmInline 13 | value class ImportSession( 14 | val file: File 15 | ) : StoreMessage 16 | -------------------------------------------------------------------------------- /tea-time-travel-plugin/resources/images/inlineCopy.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /tea-time-travel-plugin/resources/images/import_dark.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /tea-time-travel-plugin/resources/images/close.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | -------------------------------------------------------------------------------- /tea-time-travel-plugin/resources/images/collapse.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /tea-time-travel-plugin/resources/images/import.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /tea-time-travel-plugin/resources/images/export.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /tea-time-travel-plugin/resources/images/export_dark.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /tea-time-travel-plugin/resources/images/settings.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /tea-time-travel-plugin/resources/images/settings_dark.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /tea-time-travel-plugin/src/test/integration/kotlin/io/github/xlopec/tea/time/travel/plugin/util/Finders.kt: -------------------------------------------------------------------------------- 1 | package io.github.xlopec.tea.time.travel.plugin.util 2 | 3 | import androidx.compose.ui.test.SemanticsNodeInteraction 4 | import androidx.compose.ui.test.SemanticsNodeInteractionsProvider 5 | import androidx.compose.ui.test.onChildAt 6 | import androidx.compose.ui.test.onNodeWithTag 7 | import io.github.xlopec.tea.time.travel.plugin.feature.component.ui.ComponentTabTag 8 | import io.github.xlopec.tea.time.travel.protocol.ComponentId 9 | 10 | internal fun SemanticsNodeInteractionsProvider.onCloseTabActionNode(id: ComponentId): SemanticsNodeInteraction = 11 | onNodeWithTag(ComponentTabTag(id), true).onChildAt(1) 12 | -------------------------------------------------------------------------------- /tea-time-travel-plugin/src/main/java/io/github/xlopec/tea/time/travel/plugin/feature/storage/Commands.kt: -------------------------------------------------------------------------------- 1 | package io.github.xlopec.tea.time.travel.plugin.feature.storage 2 | 3 | import io.github.xlopec.tea.time.travel.plugin.feature.settings.Settings 4 | import io.github.xlopec.tea.time.travel.plugin.integration.StoreCommand 5 | import io.github.xlopec.tea.time.travel.plugin.model.DebuggableComponent 6 | import java.io.File 7 | 8 | data class DoExportSessions( 9 | val dir: File, 10 | val sessions: Collection 11 | ) : StoreCommand 12 | 13 | @JvmInline 14 | value class DoImportSession( 15 | val file: File 16 | ) : StoreCommand 17 | 18 | @JvmInline 19 | value class DoStoreSettings( 20 | val settings: Settings 21 | ) : StoreCommand 22 | -------------------------------------------------------------------------------- /samples/shared-app-lib/src/commonMain/sqldelight/io/github/xlopec/reader/app/storage/RecentSearches.sq: -------------------------------------------------------------------------------- 1 | CREATE TABLE RecentSearches( 2 | value TEXT NOT NULL, 3 | type INTEGER NOT NULL, -- tab type 4 | saved_on INTEGER NOT NULL, 5 | PRIMARY KEY (value, type) 6 | ); 7 | 8 | insert: 9 | INSERT OR REPLACE INTO RecentSearches(value, type, saved_on) 10 | VALUES (?, ?, ?); 11 | 12 | delete: 13 | DELETE FROM RecentSearches 14 | WHERE type = ? AND value = ?; 15 | 16 | deleteOutdated: 17 | DELETE FROM RecentSearches 18 | WHERE type = ? AND value NOT IN ( 19 | SELECT value 20 | FROM RecentSearches 21 | WHERE type = ? 22 | ORDER BY saved_on DESC LIMIT ? 23 | ); 24 | 25 | findAllByType: 26 | SELECT * FROM RecentSearches 27 | WHERE type = ? 28 | ORDER BY saved_on DESC; 29 | -------------------------------------------------------------------------------- /tea-time-travel-plugin/src/test/integration/kotlin/io/github/xlopec/tea/time/travel/plugin/util/TestWindow.kt: -------------------------------------------------------------------------------- 1 | package io.github.xlopec.tea.time.travel.plugin.util 2 | 3 | import androidx.compose.foundation.layout.fillMaxSize 4 | import androidx.compose.runtime.Composable 5 | import androidx.compose.ui.Modifier 6 | import androidx.compose.ui.window.FrameWindowScope 7 | import androidx.compose.ui.window.Window 8 | import io.kanro.compose.jetbrains.JBTheme 9 | import io.kanro.compose.jetbrains.control.JPanel 10 | 11 | @Composable 12 | fun TestWindow( 13 | content: @Composable FrameWindowScope.() -> Unit 14 | ) { 15 | Window(visible = true, onCloseRequest = {}) { 16 | JBTheme { 17 | JPanel(modifier = Modifier.fillMaxSize()) { 18 | content() 19 | } 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /samples/iosApp/iosAppTests/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 | 22 | 23 | -------------------------------------------------------------------------------- /samples/iosApp/iosAppUITests/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 | 22 | 23 | -------------------------------------------------------------------------------- /samples/shared-app-lib/src/commonMain/sqldelight/io/github/xlopec/reader/app/storage/Filters.sq: -------------------------------------------------------------------------------- 1 | CREATE TABLE Filter( 2 | type INTEGER NOT NULL PRIMARY KEY, -- tab type 3 | input TEXT DEFAULT NULL 4 | ); 5 | 6 | CREATE TABLE Source( 7 | source TEXT NOT NULL PRIMARY KEY, -- source id 8 | type INTEGER NOT NULL, 9 | FOREIGN KEY (type) REFERENCES Filter ON DELETE CASCADE 10 | ); 11 | 12 | insertFilter: 13 | INSERT OR REPLACE INTO Filter(type, input) 14 | VALUES (?, ?); 15 | 16 | insertSource: 17 | INSERT OR REPLACE INTO Source(source, type) 18 | VALUES (?, ?); 19 | 20 | -- API doesn't allow more than 20 sources per request 21 | deleteSources: 22 | DELETE FROM Source 23 | WHERE type = ?; 24 | 25 | findAllSourcesByType: 26 | SELECT * FROM Source 27 | WHERE type = ?; 28 | 29 | findFilterByType: 30 | SELECT * FROM Filter 31 | WHERE type = ?; 32 | -------------------------------------------------------------------------------- /samples/iosApp/iosAppTests/iosAppTests.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | @testable import iosApp 3 | 4 | class iosAppTests: XCTestCase { 5 | 6 | override func setUp() { 7 | // Put setup code here. This method is called before the invocation of each test method in the class. 8 | } 9 | 10 | override func tearDown() { 11 | // Put teardown code here. This method is called after the invocation of each test method in the class. 12 | } 13 | 14 | func testExample() { 15 | // This is an example of a functional test case. 16 | // Use XCTAssert and related functions to verify your tests produce the correct results. 17 | } 18 | 19 | func testPerformanceExample() { 20 | // This is an example of a performance test case. 21 | self.measure { 22 | // Put the code you want to measure the time of here. 23 | } 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /tea-time-travel-plugin/src/main/java/io/github/xlopec/tea/time/travel/plugin/util/GsonExtensions.kt: -------------------------------------------------------------------------------- 1 | package io.github.xlopec.tea.time.travel.plugin.util 2 | 3 | import com.google.gson.Gson 4 | import com.google.gson.JsonElement 5 | import java.io.BufferedWriter 6 | import java.io.File 7 | import java.io.FileWriter 8 | import java.lang.reflect.Type 9 | import kotlinx.coroutines.Dispatchers 10 | import kotlinx.coroutines.withContext 11 | 12 | internal suspend fun Gson.toJson( 13 | any: Any, 14 | file: File, 15 | typeOfSrc: Type = any::class.java, 16 | ) = withContext(Dispatchers.IO) { 17 | BufferedWriter(FileWriter(file)).use { bw -> toJson(any, typeOfSrc, bw) } 18 | } 19 | 20 | internal suspend fun Gson.toJson( 21 | jsonElement: JsonElement, 22 | file: File, 23 | ) = withContext(Dispatchers.IO) { 24 | BufferedWriter(FileWriter(file)).use { bw -> toJson(jsonElement, bw) } 25 | } 26 | -------------------------------------------------------------------------------- /tea-time-travel-plugin/src/test/unit/kotlin/io/github/xlopec/tea/time/travel/plugin/data/NumberExtensions.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021. Maksym Oliinyk. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.github.xlopec.tea.time.travel.plugin.data 18 | 19 | inline fun Int.times( 20 | block: () -> T 21 | ): List = (0 until this).map { block() } 22 | -------------------------------------------------------------------------------- /tea-time-travel-plugin/src/test/resources/test_state.json: -------------------------------------------------------------------------------- 1 | { 2 | "@type": "com.max.weatherviewer.app.State", 3 | "@value": { 4 | "screens": { 5 | "@type": "kotlinx.collections.immutable.implementations.immutableList.SmallPersistentVector", 6 | "@value": [ 7 | { 8 | "@type": "com.max.weatherviewer.screens.feed.FeedLoading", 9 | "@value": { 10 | "criteria": { 11 | "@type": "com.max.weatherviewer.screens.feed.LoadCriteria$Query", 12 | "@value": { 13 | "query": { 14 | "@type": "java.lang.String", 15 | "@value": "android" 16 | } 17 | } 18 | }, 19 | "id": { 20 | "@type": "java.util.UUID", 21 | "@value": "6b1ece05-eefb-44fe-9313-892eb000f0ee" 22 | } 23 | } 24 | } 25 | ] 26 | } 27 | } 28 | } -------------------------------------------------------------------------------- /samples/shared-app-lib/src/commonMain/sqldelight/io/github/xlopec/reader/app/storage/Articles.sq: -------------------------------------------------------------------------------- 1 | CREATE TABLE Articles( 2 | url TEXT NOT NULL,-- url TEXT PRIMARY KEY NOT NULL definition doesn't work for IOS 3 | title TEXT NOT NULL, 4 | author TEXT, 5 | description TEXT, 6 | url_to_image TEXT, 7 | published INTEGER NOT NULL, 8 | saved_on INTEGER NOT NULL, 9 | is_favorite INTEGER AS Boolean NOT NULL DEFAULT 0, 10 | source TEXT DEFAULT NULL, 11 | FOREIGN KEY (source) REFERENCES Source ON DELETE SET DEFAULT 12 | ); 13 | 14 | insertArticle: 15 | INSERT OR REPLACE INTO Articles(url, title, author, description, url_to_image, published, saved_on, is_favorite, source) 16 | VALUES (?, ?, ?, ?, ?, ?, ?,?, ?); 17 | 18 | deleteArticle: 19 | DELETE FROM Articles WHERE url = ?; 20 | 21 | findAllArticles: 22 | SELECT * FROM Articles 23 | ORDER BY saved_on DESC; 24 | 25 | isFavoriteArticle: 26 | SELECT * FROM Articles WHERE url = ?; 27 | -------------------------------------------------------------------------------- /tea-time-travel-plugin/resources/images/class.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /tea-time-travel-plugin/src/main/java/io/github/xlopec/tea/time/travel/plugin/feature/server/Command.kt: -------------------------------------------------------------------------------- 1 | package io.github.xlopec.tea.time.travel.plugin.feature.server 2 | 3 | import io.github.xlopec.tea.time.travel.plugin.feature.settings.ServerAddress 4 | import io.github.xlopec.tea.time.travel.plugin.integration.ServerCommand 5 | import io.github.xlopec.tea.time.travel.plugin.model.Server 6 | import io.github.xlopec.tea.time.travel.plugin.model.Value 7 | import io.github.xlopec.tea.time.travel.protocol.ComponentId 8 | 9 | @JvmInline 10 | value class DoStartServer( 11 | val address: ServerAddress 12 | ) : ServerCommand 13 | 14 | @JvmInline 15 | value class DoStopServer( 16 | val server: Server 17 | ) : ServerCommand 18 | 19 | data class DoApplyMessage( 20 | val id: ComponentId, 21 | val command: Value, 22 | val server: Server 23 | ) : ServerCommand 24 | 25 | data class DoApplyState( 26 | val id: ComponentId, 27 | val state: Value, 28 | val server: Server 29 | ) : ServerCommand 30 | -------------------------------------------------------------------------------- /tea-time-travel-plugin/src/main/java/io/github/xlopec/tea/time/travel/plugin/feature/component/ui/SnapshotActionItemsPreview.kt: -------------------------------------------------------------------------------- 1 | package io.github.xlopec.tea.time.travel.plugin.feature.component.ui 2 | 3 | import androidx.compose.desktop.ui.tooling.preview.Preview 4 | import androidx.compose.runtime.Composable 5 | import io.github.xlopec.tea.time.travel.plugin.model.SnapshotId 6 | import io.github.xlopec.tea.time.travel.plugin.ui.theme.PluginPreviewTheme 7 | import io.github.xlopec.tea.time.travel.protocol.ComponentId 8 | import io.kanro.compose.jetbrains.control.DropdownMenu 9 | import java.util.* 10 | 11 | @Preview 12 | @Composable 13 | private fun SnapshotActionItemsPreview() { 14 | PluginPreviewTheme { 15 | DropdownMenu(expanded = true, onDismissRequest = {}) { 16 | SnapshotActionItems( 17 | componentId = ComponentId("test component"), 18 | snapshotId = SnapshotId(UUID.randomUUID()), 19 | serverStarted = false, 20 | handler = {} 21 | ) 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /tea-time-travel-plugin/resources/images/property.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /tea-time-travel-plugin/resources/images/updateRunningApplication.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /tea-time-travel-plugin/resources/images/updateRunningApplication_dark.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /tea-time-travel-plugin/src/main/java/io/github/xlopec/tea/time/travel/plugin/integration/AppUpdater.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021. Maksym Oliinyk. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.github.xlopec.tea.time.travel.plugin.integration 18 | 19 | import io.github.xlopec.tea.core.Update 20 | import io.github.xlopec.tea.time.travel.plugin.model.State 21 | 22 | fun interface AppUpdater { 23 | 24 | fun update( 25 | message: Message, 26 | state: State 27 | ): Update 28 | } 29 | -------------------------------------------------------------------------------- /tea-time-travel-plugin/src/main/java/io/github/xlopec/tea/time/travel/plugin/integration/Command.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021. Maksym Oliinyk. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.github.xlopec.tea.time.travel.plugin.integration 18 | 19 | import androidx.compose.runtime.Immutable 20 | 21 | @Immutable 22 | sealed interface Command 23 | 24 | /*sealed*/ 25 | interface StoreCommand : Command 26 | 27 | /*sealed*/ 28 | interface NotifyCommand : Command 29 | 30 | /*sealed*/ 31 | interface ServerCommand : Command 32 | -------------------------------------------------------------------------------- /samples/iosApp/iosApp/NewsReaderApp.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | import SwiftUI 3 | import SharedAppLib 4 | 5 | @main 6 | struct NewsReaderApp: App { 7 | 8 | @UIApplicationDelegateAdaptor(NewsReaderAppDelegate.self) private var appDelegate: NewsReaderAppDelegate 9 | 10 | init() { 11 | UITabBar.appearance().isTranslucent = false 12 | } 13 | 14 | var body: some Scene { 15 | WindowGroup { 16 | AppView(component: appDelegate.component) 17 | } 18 | } 19 | } 20 | 21 | class NewsReaderAppDelegate: NSObject, UIApplicationDelegate { 22 | 23 | let component: IosComponent 24 | 25 | override init() { 26 | component = IosComponent(systemDarkModeEnabled: UIViewController().isDarkMode) 27 | } 28 | 29 | deinit { 30 | component.destroy() 31 | } 32 | } 33 | 34 | private extension UIViewController { 35 | var isDarkMode: Bool { 36 | if #available(iOS 13.0, *) { 37 | return self.traitCollection.userInterfaceStyle == .dark 38 | } 39 | else { 40 | return false 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /samples/shared-app-lib/src/commonMain/kotlin/io/github/xlopec/reader/app/ResolverDslBuilders.kt: -------------------------------------------------------------------------------- 1 | package io.github.xlopec.reader.app 2 | 3 | import kotlin.contracts.InvocationKind 4 | import kotlin.contracts.contract 5 | 6 | /** 7 | * Wrapper to perform side effect computations and possibly return a new message to be consumed by [Updater] 8 | * 9 | * @receiver command to be used to execute effect 10 | * @param C command 11 | * @param M message 12 | * @param action action to perform that might produce message to be consumed by a component 13 | * @return set of messages to be consumed a component 14 | */ 15 | public suspend inline infix fun C.effect( 16 | crossinline action: suspend C.() -> M?, 17 | ): Set { 18 | contract { 19 | callsInPlace(action, InvocationKind.EXACTLY_ONCE) 20 | } 21 | return setOfNotNull(action(this)) 22 | } 23 | 24 | public suspend inline infix fun C.sideEffect( 25 | crossinline action: suspend C.() -> Unit, 26 | ): Set { 27 | contract { 28 | callsInPlace(action, InvocationKind.EXACTLY_ONCE) 29 | } 30 | action(this) 31 | return setOf() 32 | } 33 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022. Maksym Oliinyk. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /tea-time-travel-plugin/src/main/java/io/github/xlopec/tea/time/travel/plugin/integration/Message.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021. Maksym Oliinyk. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.github.xlopec.tea.time.travel.plugin.integration 18 | 19 | import androidx.compose.runtime.Immutable 20 | 21 | @Immutable 22 | sealed interface Message 23 | 24 | /*sealed*/ 25 | interface ServerMessage : Message 26 | 27 | /*sealed*/ 28 | interface NotificationMessage : Message 29 | 30 | /*sealed*/ 31 | interface ComponentMessage : Message 32 | 33 | /*sealed*/ 34 | interface StoreMessage : Message 35 | -------------------------------------------------------------------------------- /tea-time-travel-plugin/src/main/java/io/github/xlopec/tea/time/travel/plugin/integration/AppResolver.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021. Maksym Oliinyk. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.github.xlopec.tea.time.travel.plugin.integration 18 | 19 | import io.github.xlopec.tea.core.ResolveCtx 20 | import io.github.xlopec.tea.core.Snapshot 21 | import io.github.xlopec.tea.time.travel.plugin.model.State 22 | 23 | fun interface AppResolver { 24 | 25 | fun Env.resolve( 26 | snapshot: Snapshot, 27 | ctx: ResolveCtx 28 | ) 29 | } 30 | -------------------------------------------------------------------------------- /tea-time-travel-plugin/src/main/java/io/github/xlopec/tea/time/travel/plugin/ui/NoIndicationClickable.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021. Maksym Oliinyk. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.github.xlopec.tea.time.travel.plugin.ui 18 | 19 | import androidx.compose.foundation.clickable 20 | import androidx.compose.foundation.interaction.MutableInteractionSource 21 | import androidx.compose.ui.Modifier 22 | 23 | fun Modifier.noIndicationClickable( 24 | onClick: () -> Unit, 25 | ) = clickable( 26 | interactionSource = MutableInteractionSource(), 27 | indication = null, 28 | onClick = onClick 29 | ) 30 | -------------------------------------------------------------------------------- /samples/iosApp/iosApp/AppView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppView.swift 3 | // iosApp 4 | // 5 | // Created by Maksym Oliinyk2 on 11.10.2021. 6 | // Copyright © 2021 orgName. All rights reserved. 7 | // 8 | 9 | import SwiftUI 10 | import SharedAppLib 11 | 12 | struct AppView: View { 13 | 14 | @SwiftUI.Environment(\.colorScheme) private var colorScheme: ColorScheme 15 | 16 | let component: IosComponent 17 | 18 | var body: some View { 19 | ComposeViewController(component: component) 20 | .frame(maxWidth: .infinity, maxHeight: .infinity) 21 | .ignoresSafeArea() 22 | } 23 | 24 | private func updateDarkMode(darkModeEnabled: Bool) { 25 | let window = UIApplication.shared.windows.first 26 | 27 | window?.overrideUserInterfaceStyle = darkModeEnabled ? .dark : .light 28 | } 29 | 30 | } 31 | 32 | struct ComposeViewController: UIViewControllerRepresentable { 33 | 34 | let component: IosComponent 35 | 36 | func makeUIViewController(context: Context) -> UIViewController { 37 | App_iosKt.appController(component: component) 38 | } 39 | 40 | func updateUIViewController(_ uiViewController: UIViewController, context: Context) { 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /tea-time-travel-plugin/src/test/integration/kotlin/io/github/xlopec/tea/time/travel/plugin/environment/TestPlatform.kt: -------------------------------------------------------------------------------- 1 | package io.github.xlopec.tea.time.travel.plugin.environment 2 | 3 | import com.intellij.psi.PsiClass 4 | import io.github.xlopec.tea.time.travel.plugin.feature.storage.ExportSessions 5 | import io.github.xlopec.tea.time.travel.plugin.integration.Platform 6 | import io.github.xlopec.tea.time.travel.plugin.model.Type 7 | import io.github.xlopec.tea.time.travel.protocol.ComponentId 8 | import java.io.File 9 | import kotlinx.collections.immutable.ImmutableSet 10 | 11 | class TestPlatform : Platform { 12 | 13 | override suspend fun chooseSessionFile(): File { 14 | TODO("Not yet implemented") 15 | } 16 | 17 | override suspend fun chooseExportSessionDirectory(ids: ImmutableSet): ExportSessions? { 18 | TODO("Not yet implemented") 19 | } 20 | 21 | override fun psiClassFor(type: Type): PsiClass? { 22 | TODO("Not yet implemented") 23 | } 24 | 25 | override fun navigateToSources(psiClass: PsiClass) { 26 | TODO("Not yet implemented") 27 | } 28 | 29 | override fun navigateToSettings() { 30 | TODO("Not yet implemented") 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /tea-time-travel-plugin/src/main/java/io/github/xlopec/tea/time/travel/plugin/feature/component/ui/ComponentTab.kt: -------------------------------------------------------------------------------- 1 | @file:Suppress("FunctionName") 2 | 3 | package io.github.xlopec.tea.time.travel.plugin.feature.component.ui 4 | 5 | import androidx.compose.runtime.Composable 6 | import androidx.compose.ui.Modifier 7 | import androidx.compose.ui.platform.testTag 8 | import io.github.xlopec.tea.time.travel.plugin.feature.component.integration.RemoveComponent 9 | import io.github.xlopec.tea.time.travel.plugin.feature.component.integration.SelectComponent 10 | import io.github.xlopec.tea.time.travel.plugin.ui.control.CloseableTab 11 | import io.github.xlopec.tea.time.travel.protocol.ComponentId 12 | 13 | internal fun ComponentTabTag( 14 | id: ComponentId, 15 | ) = "component tab '${id.value}'" 16 | 17 | @Composable 18 | internal fun ComponentTab( 19 | id: ComponentId, 20 | currentSelection: ComponentId, 21 | handler: MessageHandler, 22 | ) { 23 | CloseableTab( 24 | modifier = Modifier.testTag(ComponentTabTag(id)), 25 | text = id.value, 26 | selected = id == currentSelection, 27 | onSelect = { handler(SelectComponent(id)) }, 28 | onClose = { handler(RemoveComponent(id)) } 29 | ) 30 | } 31 | -------------------------------------------------------------------------------- /.run/Tea-bag [samples_app_assembleDefaultDebug samples_app_installDefaultDebug].run.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 17 | 19 | true 20 | true 21 | false 22 | 23 | 24 | -------------------------------------------------------------------------------- /samples/counter/src/main/java/io/github/xlopec/counter/Counter.kt: -------------------------------------------------------------------------------- 1 | @file:OptIn(ExperimentalTeaApi::class) 2 | 3 | package io.github.xlopec.counter 4 | 5 | import io.github.xlopec.tea.core.* 6 | import kotlinx.coroutines.runBlocking 7 | 8 | /**Async initializer, provides initial state*/ 9 | suspend fun initializer(): Initial = Initial(0) 10 | 11 | /**Some tracker*/ 12 | fun track( 13 | event: Snapshot, 14 | ctx: ResolveCtx, 15 | ) { 16 | ctx sideEffect { println("Track: \"$event\"") } 17 | } 18 | 19 | /**App logic, for now it just adds delta to count and returns this as result*/ 20 | fun add( 21 | delta: Int, 22 | counter: Int, 23 | ): Update = (counter + delta) command delta 24 | 25 | /**Some UI, e.g. console*/ 26 | suspend fun display( 27 | snapshot: Snapshot<*, *, *>, 28 | ) { 29 | println("Display: $snapshot") 30 | } 31 | 32 | fun main() = runBlocking { 33 | // Somewhere at the application level 34 | val component = Component( 35 | initializer = ::initializer, 36 | resolver = ::track, 37 | updater = ::add, 38 | scope = this, 39 | ) 40 | // UI = component([message1, message2, ..., message N]) 41 | component(+1, +2, -3).collect(::display) 42 | } 43 | -------------------------------------------------------------------------------- /tea-time-travel-plugin/src/test/integration/kotlin/io/github/xlopec/tea/time/travel/plugin/util/ComposeRuleExtensions.kt: -------------------------------------------------------------------------------- 1 | package io.github.xlopec.tea.time.travel.plugin.util 2 | 3 | import androidx.compose.runtime.Composable 4 | import androidx.compose.runtime.DisposableEffect 5 | import androidx.compose.ui.test.junit4.ComposeContentTestRule 6 | import io.github.xlopec.tea.time.travel.plugin.environment.TestEnvironment 7 | import kotlinx.coroutines.runBlocking 8 | 9 | inline operator fun ComposeContentTestRule.invoke( 10 | crossinline body: suspend ComposeContentTestRule.() -> Unit 11 | ) { 12 | runBlocking { 13 | body() 14 | } 15 | } 16 | 17 | fun ComposeContentTestRule.setTestContent( 18 | content: @Composable () -> Unit 19 | ) { 20 | setContent { 21 | TestTheme { 22 | content() 23 | } 24 | } 25 | } 26 | 27 | fun ComposeContentTestRule.setContentWithEnv( 28 | environment: TestEnvironment, 29 | content: @Composable () -> Unit 30 | ) { 31 | setTestContent { 32 | DisposableEffect(Unit) { 33 | registerIdlingResource(environment) 34 | onDispose { 35 | unregisterIdlingResource(environment) 36 | } 37 | } 38 | 39 | content() 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /samples/shared-app-lib/src/androidMain/kotlin/io/github/xlopec/reader/app/ui/screens/InsetsController.kt: -------------------------------------------------------------------------------- 1 | package io.github.xlopec.reader.app.ui.screens 2 | 3 | import android.app.Activity 4 | import android.content.Context 5 | import android.content.ContextWrapper 6 | import android.view.View 7 | import android.view.Window 8 | import androidx.compose.runtime.Composable 9 | import androidx.compose.runtime.remember 10 | import androidx.compose.ui.platform.LocalView 11 | import androidx.compose.ui.window.DialogWindowProvider 12 | import androidx.core.view.WindowCompat 13 | import androidx.core.view.WindowInsetsControllerCompat 14 | 15 | @Composable 16 | internal fun rememberWindowInsetsController(): WindowInsetsControllerCompat { 17 | val view = LocalView.current 18 | 19 | return remember(view) { 20 | val window = view.findWindow() 21 | WindowCompat.getInsetsController(window, window.decorView) 22 | } 23 | } 24 | 25 | private fun View.findWindow(): Window = 26 | (parent as? DialogWindowProvider)?.window ?: context.findWindow() 27 | 28 | private tailrec fun Context.findWindow(): Window = 29 | when (this) { 30 | is Activity -> window 31 | is ContextWrapper -> baseContext.findWindow() 32 | else -> error("No window found") 33 | } 34 | -------------------------------------------------------------------------------- /tea-time-travel-plugin/src/main/java/io/github/xlopec/tea/time/travel/plugin/model/Server.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021. Maksym Oliinyk. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | @file:Suppress("FunctionName") 18 | 19 | package io.github.xlopec.tea.time.travel.plugin.model 20 | 21 | import io.github.xlopec.tea.time.travel.gson.GsonClientMessage 22 | import io.github.xlopec.tea.time.travel.plugin.feature.settings.ServerAddress 23 | import io.github.xlopec.tea.time.travel.protocol.ComponentId 24 | 25 | interface Server { 26 | 27 | val address: ServerAddress 28 | suspend operator fun invoke( 29 | component: ComponentId, 30 | message: GsonClientMessage, 31 | ) 32 | 33 | suspend fun stop() 34 | } 35 | -------------------------------------------------------------------------------- /tea-time-travel-plugin/src/main/java/io/github/xlopec/tea/time/travel/plugin/feature/storage/Updater.kt: -------------------------------------------------------------------------------- 1 | package io.github.xlopec.tea.time.travel.plugin.feature.storage 2 | 3 | import io.github.xlopec.tea.core.Update 4 | import io.github.xlopec.tea.core.command 5 | import io.github.xlopec.tea.time.travel.plugin.integration.Command 6 | import io.github.xlopec.tea.time.travel.plugin.integration.StoreMessage 7 | import io.github.xlopec.tea.time.travel.plugin.integration.onUnhandledMessage 8 | import io.github.xlopec.tea.time.travel.plugin.model.State 9 | import io.github.xlopec.tea.time.travel.plugin.model.componentOrThrow 10 | 11 | internal fun State.onUpdateForStoreMessage( 12 | message: StoreMessage, 13 | ): Update = when { 14 | message is ExportSessions && debugger.components.isNotEmpty() -> onExportSessions(message) 15 | message is ImportSession -> onImportSession(message) 16 | else -> onUnhandledMessage(message) 17 | } 18 | 19 | internal fun State.onImportSession( 20 | message: ImportSession 21 | ): Update = 22 | this command DoImportSession(message.file) 23 | 24 | internal fun State.onExportSessions( 25 | message: ExportSessions 26 | ): Update = 27 | this command DoExportSessions(message.dir, message.ids.map(debugger::componentOrThrow)) 28 | -------------------------------------------------------------------------------- /samples/app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | -keepattributes SourceFile,LineNumberTable 18 | -dontobfuscate 19 | 20 | #-printconfiguration ~/tea-core-full-r8-config.txt 21 | 22 | # If you keep the line number information, uncomment this to 23 | # hide the original source file name. 24 | #-renamesourcefileattribute SourceFile 25 | 26 | -keepattributes Signature 27 | # see https://r8.googlesource.com/r8/+/refs/heads/main/compatibility-faq.md#kotlin-suspend-functions-and-generic-signatures 28 | # for R8 full mode 29 | 30 | -assumenosideeffects public class androidx.compose.runtime.ComposerKt { 31 | boolean isTraceInProgress(); 32 | void traceEventStart(int,java.lang.String); 33 | void traceEventEnd(); 34 | } -------------------------------------------------------------------------------- /tea-time-travel-plugin/src/main/java/io/github/xlopec/tea/time/travel/plugin/feature/settings/PluginSettingsNotifier.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021. Maksym Oliinyk. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.github.xlopec.tea.time.travel.plugin.feature.settings 18 | 19 | import com.intellij.util.messages.Topic 20 | import io.github.xlopec.tea.time.travel.plugin.model.PInt 21 | 22 | fun interface PluginSettingsNotifier { 23 | 24 | companion object { 25 | val TOPIC = Topic.create("Plugin Settings Notifier", PluginSettingsNotifier::class.java) 26 | } 27 | 28 | fun onSettingsUpdated( 29 | isDetailedToStringEnabled: Boolean, 30 | clearSnapshotsOnComponentAttach: Boolean, 31 | maxSnapshots: PInt, 32 | ) 33 | } 34 | -------------------------------------------------------------------------------- /tea-time-travel-plugin/src/test/unit/kotlin/io/github/xlopec/tea/time/travel/plugin/util/LoggerStub.kt: -------------------------------------------------------------------------------- 1 | package io.github.xlopec.tea.time.travel.plugin.util 2 | 3 | import com.intellij.openapi.diagnostic.Logger 4 | import org.apache.log4j.Level 5 | 6 | open class LoggerStub : Logger() { 7 | override fun isDebugEnabled(): Boolean { 8 | TODO("Not yet implemented") 9 | } 10 | 11 | override fun debug(p0: String?) { 12 | TODO("Not yet implemented") 13 | } 14 | 15 | override fun debug(p0: Throwable?) { 16 | TODO("Not yet implemented") 17 | } 18 | 19 | override fun debug(p0: String?, p1: Throwable?) { 20 | TODO("Not yet implemented") 21 | } 22 | 23 | override fun info(p0: String?) { 24 | TODO("Not yet implemented") 25 | } 26 | 27 | override fun info(p0: String?, p1: Throwable?) { 28 | TODO("Not yet implemented") 29 | } 30 | 31 | override fun warn(p0: String?, p1: Throwable?) { 32 | TODO("Not yet implemented") 33 | } 34 | 35 | override fun error(p0: String?, p1: Throwable?, vararg p2: String?) { 36 | TODO("Not yet implemented") 37 | } 38 | 39 | @Deprecated("Deprecated in Java") 40 | override fun setLevel(@Suppress("UnstableApiUsage") p0: Level) { 41 | TODO("Not yet implemented") 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /samples/app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 24 | 25 | 26 | News Reader 27 | 28 | -------------------------------------------------------------------------------- /tea-time-travel-plugin/src/main/java/io/github/xlopec/tea/time/travel/plugin/util/ChooserUtils.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021. Maksym Oliinyk. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.github.xlopec.tea.time.travel.plugin.util 18 | 19 | import com.intellij.openapi.fileChooser.FileChooser 20 | import com.intellij.openapi.fileChooser.FileChooserDescriptor 21 | import com.intellij.openapi.project.Project 22 | import java.io.File 23 | import kotlin.coroutines.resume 24 | import kotlin.coroutines.suspendCoroutine 25 | 26 | suspend fun Project.chooseFile( 27 | descriptor: FileChooserDescriptor 28 | ) = suspendCoroutine { continuation -> 29 | FileChooser.chooseFile(descriptor, this, null, null) { virtualFile -> 30 | continuation.resume(File(virtualFile.path)) 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /samples/shared-app-lib/src/commonMain/kotlin/io/github/xlopec/reader/app/ui/misc/InsetsAwareBottomNavigation.kt: -------------------------------------------------------------------------------- 1 | package io.github.xlopec.reader.app.ui.misc 2 | 3 | import androidx.compose.foundation.layout.RowScope 4 | import androidx.compose.foundation.layout.navigationBarsPadding 5 | import androidx.compose.material.BottomNavigation 6 | import androidx.compose.material.MaterialTheme 7 | import androidx.compose.material.Surface 8 | import androidx.compose.material.contentColorFor 9 | import androidx.compose.runtime.Composable 10 | import androidx.compose.ui.Modifier 11 | import androidx.compose.ui.graphics.Color 12 | import androidx.compose.ui.unit.Dp 13 | import androidx.compose.ui.unit.dp 14 | 15 | @Composable 16 | internal fun InsetsAwareBottomNavigation( 17 | modifier: Modifier = Modifier, 18 | elevation: Dp = 1.dp, 19 | background: Color = MaterialTheme.colors.surface, 20 | content: @Composable RowScope.() -> Unit, 21 | ) { 22 | Surface( 23 | modifier = modifier, 24 | elevation = elevation, 25 | color = background, 26 | ) { 27 | BottomNavigation( 28 | modifier = Modifier.navigationBarsPadding(), 29 | elevation = 0.dp, 30 | backgroundColor = Color.Unspecified, 31 | contentColor = contentColorFor(background), 32 | content = content 33 | ) 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /tea-core/src/commonTest/kotlin/io/github/xlopec/tea/core/misc/Thread.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License 3 | * 4 | * Copyright (c) 2022. Maksym Oliinyk. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | package io.github.xlopec.tea.core.misc 26 | 27 | expect fun currentThreadName(): String 28 | -------------------------------------------------------------------------------- /tea-time-travel-plugin/src/main/java/io/github/xlopec/tea/time/travel/plugin/feature/notification/Command.kt: -------------------------------------------------------------------------------- 1 | package io.github.xlopec.tea.time.travel.plugin.feature.notification 2 | 3 | import io.github.xlopec.tea.time.travel.plugin.integration.Command 4 | import io.github.xlopec.tea.time.travel.plugin.integration.Message 5 | import io.github.xlopec.tea.time.travel.plugin.integration.NotifyCommand 6 | import io.github.xlopec.tea.time.travel.plugin.integration.PluginException 7 | import io.github.xlopec.tea.time.travel.plugin.model.State 8 | import io.github.xlopec.tea.time.travel.protocol.ComponentId 9 | import java.io.File 10 | 11 | data class DoNotifyOperationException( 12 | val exception: PluginException, 13 | val operation: Command?, 14 | val description: String? 15 | ) : NotifyCommand 16 | 17 | data class DoWarnUnacceptableMessage( 18 | val message: Message, 19 | val state: State 20 | ) : NotifyCommand 21 | 22 | data class DoNotifyComponentAttached( 23 | val id: ComponentId, 24 | val isComponentReattached: Boolean, 25 | ) : NotifyCommand 26 | 27 | data class DoNotifyFileOperationSuccess( 28 | val title: String, 29 | val description: String, 30 | val forFile: File? = null, 31 | ) : NotifyCommand 32 | 33 | data class DoNotifyFileOperationFailure( 34 | val title: String, 35 | val description: String, 36 | val forFile: File? = null, 37 | ) : NotifyCommand 38 | -------------------------------------------------------------------------------- /tea-core/src/jvmTest/kotlin/io/github/xlopec/tea/core/misc/CurrentThreadName.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License 3 | * 4 | * Copyright (c) 2022. Maksym Oliinyk. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | package io.github.xlopec.tea.core.misc 26 | 27 | actual fun currentThreadName(): String = Thread.currentThread().name 28 | -------------------------------------------------------------------------------- /samples/app/src/main/res/values/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 25 | 26 | 27 | #F6F6F6 28 | -------------------------------------------------------------------------------- /samples/app/src/remote/res/values/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 25 | 26 | 27 | #FFFFFF 28 | -------------------------------------------------------------------------------- /tea-time-travel-plugin/src/main/java/io/github/xlopec/tea/time/travel/plugin/util/FlowExtensions.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021. Maksym Oliinyk. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.github.xlopec.tea.time.travel.plugin.util 18 | 19 | import kotlinx.coroutines.coroutineScope 20 | import kotlinx.coroutines.flow.Flow 21 | import kotlinx.coroutines.flow.channelFlow 22 | import kotlinx.coroutines.flow.collect 23 | import kotlinx.coroutines.launch 24 | 25 | fun Flow.mergeWith(other: Flow): Flow = 26 | channelFlow { 27 | coroutineScope { 28 | launch { 29 | other.collect { 30 | send(it) 31 | } 32 | } 33 | 34 | launch { 35 | collect { 36 | send(it) 37 | } 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | # 2 | # MIT License 3 | # 4 | # Copyright (c) 2022. Maksym Oliinyk. 5 | # 6 | # Permission is hereby granted, free of charge, to any person obtaining a copy 7 | # of this software and associated documentation files (the "Software"), to deal 8 | # in the Software without restriction, including without limitation the rights 9 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | # copies of the Software, and to permit persons to whom the Software is 11 | # furnished to do so, subject to the following conditions: 12 | # 13 | # The above copyright notice and this permission notice shall be included in all 14 | # copies or substantial portions of the Software. 15 | # 16 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | # SOFTWARE. 23 | # 24 | 25 | distributionBase=GRADLE_USER_HOME 26 | distributionPath=wrapper/dists 27 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-all.zip 28 | zipStoreBase=GRADLE_USER_HOME 29 | zipStorePath=wrapper/dists 30 | -------------------------------------------------------------------------------- /samples/iosApp/iosAppUITests/iosAppUITests.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | 3 | class appNameUITests: XCTestCase { 4 | 5 | override func setUp() { 6 | // Put setup code here. This method is called before the invocation of each test method in the class. 7 | 8 | // In UI tests it is usually best to stop immediately when a failure occurs. 9 | continueAfterFailure = false 10 | 11 | // In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this. 12 | } 13 | 14 | override func tearDown() { 15 | // Put teardown code here. This method is called after the invocation of each test method in the class. 16 | } 17 | 18 | func testExample() { 19 | // UI tests must launch the application that they test. 20 | let app = XCUIApplication() 21 | app.launch() 22 | 23 | // Use recording to get started writing UI tests. 24 | // Use XCTAssert and related functions to verify your tests produce the correct results. 25 | } 26 | 27 | func testLaunchPerformance() { 28 | if #available(macOS 10.15, iOS 13.0, tvOS 13.0, *) { 29 | // This measures how long it takes to launch your application. 30 | measure(metrics: [XCTOSSignpostMetric.applicationLaunch]) { 31 | XCUIApplication().launch() 32 | } 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /tea-core/src/iosTest/kotlin/io/github/xlopec/tea/core/misc/CurrentThreadName.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License 3 | * 4 | * Copyright (c) 2022. Maksym Oliinyk. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | package io.github.xlopec.tea.core.misc 26 | 27 | import platform.Foundation.NSThread 28 | 29 | actual fun currentThreadName(): String = NSThread.currentThread.toString() 30 | -------------------------------------------------------------------------------- /tea-time-travel-plugin/src/test/unit/kotlin/io/github/xlopec/tea/time/travel/plugin/integration/PlatformTest.kt: -------------------------------------------------------------------------------- 1 | package io.github.xlopec.tea.time.travel.plugin.integration 2 | 3 | import com.intellij.openapi.project.IndexNotReadyException 4 | import io.github.xlopec.tea.time.travel.plugin.model.Type 5 | import io.github.xlopec.tea.time.travel.plugin.util.LoggerStub 6 | import io.github.xlopec.tea.time.travel.plugin.util.ProjectStub 7 | import kotlinx.coroutines.test.runTest 8 | import org.junit.Test 9 | import kotlin.test.assertIs 10 | import kotlin.test.assertNull 11 | 12 | class PlatformTest { 13 | 14 | @Test 15 | fun `test psiClassFor returns null and logs exception when exception occurs internally`() = runTest { 16 | val project = object : ProjectStub() { 17 | override fun getService(p0: Class): T = throw IndexNotReadyException.create() 18 | } 19 | val logger = object : LoggerStub() { 20 | var th: Throwable? = null 21 | 22 | override fun warn(p0: String?, p1: Throwable?) { 23 | require(th == null) { "Test shouldn't produce more then 1 exception, was $p1, recorded $th" } 24 | th = p1 25 | } 26 | } 27 | 28 | val platform = Platform(project, logger) 29 | val psiClass = platform.psiClassFor(Type.of("java.util.StringJoiner")) 30 | 31 | assertNull(psiClass) 32 | assertIs(logger.th) 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /tea-core/src/commonTest/kotlin/io/github/xlopec/tea/core/misc/ComponentException.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License 3 | * 4 | * Copyright (c) 2022. Maksym Oliinyk. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | package io.github.xlopec.tea.core.misc 26 | 27 | class ComponentException(message: String? = null, cause: Throwable? = null) : 28 | IllegalStateException(message, cause) 29 | -------------------------------------------------------------------------------- /tea-time-travel/src/jvmTest/kotlin/io/github/xlopec/tea/time/travel/component/ComponentException.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License 3 | * 4 | * Copyright (c) 2022. Maksym Oliinyk. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | package io.github.xlopec.tea.time.travel.component 26 | 27 | class ComponentException(message: String? = null, cause: Throwable? = null) : 28 | IllegalStateException(message, cause) 29 | -------------------------------------------------------------------------------- /samples/shared-app-lib/src/commonMain/kotlin/io/github/xlopec/reader/app/feature/article/details/ArticleDetailsModule.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License 3 | * 4 | * Copyright (c) 2022. Maksym Oliinyk. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | @file:Suppress("FunctionName") 26 | 27 | package io.github.xlopec.reader.app.feature.article.details 28 | 29 | public typealias ArticleDetailsModule = ArticleDetailsResolver 30 | -------------------------------------------------------------------------------- /samples/shared-app-lib/src/commonMain/kotlin/io/github/xlopec/reader/app/misc/StringExtensions.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License 3 | * 4 | * Copyright (c) 2022. Maksym Oliinyk. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | package io.github.xlopec.reader.app.misc 26 | 27 | internal fun String.coerceIn( 28 | min: UInt, 29 | max: UInt 30 | ): String? = take(max.toInt()).takeIf { it.length.toUInt() in min..max } 31 | -------------------------------------------------------------------------------- /tea-data/src/commonMain/kotlin/io/github/xlopec/tea/data/Date.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License 3 | * 4 | * Copyright (c) 2022. Maksym Oliinyk. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | package io.github.xlopec.tea.data 26 | 27 | public expect class Date 28 | 29 | public expect fun now(): Date 30 | 31 | public expect fun fromMillis( 32 | millis: Long 33 | ): Date 34 | 35 | public expect fun Date.toMillis(): Long 36 | -------------------------------------------------------------------------------- /samples/shared-app-lib/src/commonMain/kotlin/io/github/xlopec/reader/app/ui/theme/Typography.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License 3 | * 4 | * Copyright (c) 2022. Maksym Oliinyk. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | package io.github.xlopec.reader.app.ui.theme 26 | 27 | import androidx.compose.material.Typography 28 | import androidx.compose.runtime.Composable 29 | 30 | @Composable 31 | internal expect fun typography(): Typography 32 | -------------------------------------------------------------------------------- /samples/shared-app-lib/src/iosMain/kotlin/io/github/xlopec/reader/app/feature/article/details/ArticleDetailsModule.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License 3 | * 4 | * Copyright (c) 2022. Maksym Oliinyk. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | @file:Suppress("FunctionName") 26 | 27 | package io.github.xlopec.reader.app.feature.article.details 28 | 29 | public fun ArticleDetailsModule(): ArticleDetailsModule = ArticleDetailsResolver() 30 | -------------------------------------------------------------------------------- /samples/shared-app-lib/src/commonMain/kotlin/io/github/xlopec/reader/app/feature/article/details/ArticleDetailsResolver.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License 3 | * 4 | * Copyright (c) 2022. Maksym Oliinyk. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | package io.github.xlopec.reader.app.feature.article.details 26 | 27 | public interface ArticleDetailsResolver { 28 | 29 | public suspend fun resolve( 30 | command: DoOpenInBrowser 31 | ) 32 | } 33 | -------------------------------------------------------------------------------- /samples/shared-app-lib/src/commonMain/kotlin/io/github/xlopec/reader/app/feature/network/EncoderExtensions.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License 3 | * 4 | * Copyright (c) 2022. Maksym Oliinyk. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | package io.github.xlopec.reader.app.feature.network 26 | 27 | import kotlinx.serialization.encoding.Encoder 28 | 29 | internal fun Encoder.encodeNullableString( 30 | s: String? 31 | ) = s?.let(::encodeString) ?: encodeNull() 32 | -------------------------------------------------------------------------------- /samples/shared-app-lib/src/commonMain/kotlin/io/github/xlopec/reader/app/Environment.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License 3 | * 4 | * Copyright (c) 2022. Maksym Oliinyk. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | package io.github.xlopec.reader.app 26 | 27 | import io.github.xlopec.reader.app.feature.storage.LocalStorage 28 | import kotlinx.coroutines.CoroutineScope 29 | 30 | public expect interface Environment : AppModule, CoroutineScope, LocalStorage 31 | -------------------------------------------------------------------------------- /tea-data/src/commonMain/kotlin/io/github/xlopec/tea/data/UUID.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License 3 | * 4 | * Copyright (c) 2022. Maksym Oliinyk. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | @file:Suppress("FunctionName") 26 | 27 | package io.github.xlopec.tea.data 28 | 29 | public expect class UUID 30 | 31 | public expect fun RandomUUID(): UUID 32 | 33 | public expect fun UUIDFrom( 34 | value: String 35 | ): UUID 36 | 37 | public expect fun UUID.toHumanReadable(): String 38 | -------------------------------------------------------------------------------- /samples/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /samples/app/src/remote/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /samples/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /samples/app/src/remote/res/mipmap-anydpi-v26/ic_launcher_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /tea-time-travel-plugin/src/main/java/io/github/xlopec/tea/time/travel/plugin/feature/server/Updater.kt: -------------------------------------------------------------------------------- 1 | package io.github.xlopec.tea.time.travel.plugin.feature.server 2 | 3 | import arrow.core.zip 4 | import arrow.typeclasses.Semigroup 5 | import io.github.xlopec.tea.core.Update 6 | import io.github.xlopec.tea.core.command 7 | import io.github.xlopec.tea.core.noCommand 8 | import io.github.xlopec.tea.time.travel.plugin.feature.settings.ServerAddress 9 | import io.github.xlopec.tea.time.travel.plugin.integration.Command 10 | import io.github.xlopec.tea.time.travel.plugin.integration.ServerMessage 11 | import io.github.xlopec.tea.time.travel.plugin.integration.onUnhandledMessage 12 | import io.github.xlopec.tea.time.travel.plugin.model.Server 13 | import io.github.xlopec.tea.time.travel.plugin.model.State 14 | 15 | internal fun State.onUpdateForServerMessage( 16 | message: ServerMessage 17 | ): Update = 18 | when { 19 | message === StartServer && server !is Server -> onStartServer() 20 | message === StopServer && server is Server -> onStopServer(server) 21 | else -> onUnhandledMessage(message) 22 | } 23 | 24 | private fun State.onStopServer(server: Server) = 25 | this command DoStopServer(server) 26 | 27 | private fun State.onStartServer(): Update { 28 | val command = debugger.settings.host.value.zip(Semigroup.string(), debugger.settings.port.value) { host, port -> 29 | DoStartServer(ServerAddress(host, port)) 30 | }.fold({ null }, { it }) ?: return noCommand() 31 | 32 | return command(command) 33 | } 34 | -------------------------------------------------------------------------------- /tea-data/src/jvmMain/kotlin/io/github/xlopec/tea/data/Date.jvm.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License 3 | * 4 | * Copyright (c) 2022. Maksym Oliinyk. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | package io.github.xlopec.tea.data 26 | 27 | public actual typealias Date = java.util.Date 28 | 29 | public actual fun now(): Date = java.util.Date() 30 | 31 | public actual fun fromMillis( 32 | millis: Long 33 | ): Date = java.util.Date(millis) 34 | 35 | public actual fun Date.toMillis(): Long = time 36 | -------------------------------------------------------------------------------- /samples/app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 25 | 26 | 27 | #232324 28 | #232324 29 | @android:color/white 30 | @android:color/black 31 | 32 | -------------------------------------------------------------------------------- /tea-time-travel-protocol/build.gradle.kts: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License 3 | * 4 | * Copyright (c) 2022. Maksym Oliinyk. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | plugins { 26 | `published-multiplatform-library-convention` 27 | } 28 | 29 | kotlin { 30 | 31 | sourceSets { 32 | val commonMain by getting { 33 | dependencies { 34 | implementation(project(":tea-data")) 35 | implementation(libs.stdlib) 36 | } 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /samples/shared-app-lib/src/commonMain/kotlin/io/github/xlopec/reader/app/feature/article/list/ArticlesResolver.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License 3 | * 4 | * Copyright (c) 2022. Maksym Oliinyk. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | package io.github.xlopec.reader.app.feature.article.list 26 | 27 | import io.github.xlopec.reader.app.Message 28 | 29 | public interface ArticlesResolver { 30 | 31 | public suspend fun Env.resolve( 32 | command: ArticlesCommand 33 | ): Set 34 | } 35 | -------------------------------------------------------------------------------- /tea-time-travel-plugin/src/main/java/io/github/xlopec/tea/time/travel/plugin/model/Snapshot.kt: -------------------------------------------------------------------------------- 1 | package io.github.xlopec.tea.time.travel.plugin.model 2 | 3 | import androidx.compose.runtime.Immutable 4 | import io.github.xlopec.tea.time.travel.plugin.util.mapNotNull 5 | import kotlinx.collections.immutable.PersistentList 6 | 7 | @Immutable 8 | data class OriginalSnapshot( 9 | val meta: SnapshotMeta, 10 | val message: Value?, 11 | val state: Value, 12 | val commands: CollectionWrapper, 13 | ) 14 | 15 | @Immutable 16 | data class FilteredSnapshot( 17 | val meta: SnapshotMeta, 18 | val message: Value? = null, 19 | val state: Value? = null, 20 | val commands: CollectionWrapper? = null, 21 | ) { 22 | init { 23 | require(message != null || state != null || commands != null) { "failed requirement $this" } 24 | } 25 | } 26 | 27 | fun OriginalSnapshot.toFiltered() = 28 | FilteredSnapshot( 29 | meta, 30 | message, 31 | state, 32 | commands 33 | ) 34 | 35 | fun OriginalSnapshot.filteredBy( 36 | predicate: Predicate, 37 | ): FilteredSnapshot? { 38 | 39 | val m = message?.let { predicate.applyTo(it) } 40 | val s = predicate.applyTo(state) 41 | val c = predicate.applyToWrapper(commands) 42 | 43 | return if (m != null || s != null || c != null) { 44 | FilteredSnapshot(meta, m, s, c) 45 | } else { 46 | null 47 | } 48 | } 49 | 50 | fun PersistentList.filteredBy( 51 | predicate: Predicate, 52 | ): PersistentList = 53 | mapNotNull { it.filteredBy(predicate) } 54 | -------------------------------------------------------------------------------- /samples/shared-app-lib/src/commonMain/kotlin/io/github/xlopec/reader/app/feature/article/details/DoOpenInBrowser.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License 3 | * 4 | * Copyright (c) 2022. Maksym Oliinyk. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | package io.github.xlopec.reader.app.feature.article.details 26 | 27 | import io.github.xlopec.reader.app.command.Command 28 | import io.github.xlopec.reader.app.model.Article 29 | 30 | public data class DoOpenInBrowser internal constructor( 31 | val article: Article, 32 | ) : Command 33 | -------------------------------------------------------------------------------- /samples/app/src/main/res/drawable/bg_splash.xml: -------------------------------------------------------------------------------- 1 | 2 | 25 | 26 | 27 | 28 | 29 | 32 | 33 | -------------------------------------------------------------------------------- /samples/shared-app-lib/src/commonMain/kotlin/io/github/xlopec/reader/app/AppUpdater.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License 3 | * 4 | * Copyright (c) 2022. Maksym Oliinyk. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | package io.github.xlopec.reader.app 26 | 27 | import io.github.xlopec.reader.app.command.Command 28 | import io.github.xlopec.tea.core.Update 29 | 30 | public fun interface AppUpdater { 31 | 32 | public fun Env.update( 33 | message: Message, 34 | state: AppState 35 | ): Update 36 | } 37 | -------------------------------------------------------------------------------- /tea-time-travel-plugin/src/test/integration/kotlin/io/github/xlopec/tea/time/travel/plugin/environment/TestServerCommandResolver.kt: -------------------------------------------------------------------------------- 1 | package io.github.xlopec.tea.time.travel.plugin.environment 2 | 3 | import androidx.compose.ui.test.IdlingResource 4 | import io.github.xlopec.tea.core.ResolveCtx 5 | import io.github.xlopec.tea.core.effect 6 | import io.github.xlopec.tea.time.travel.plugin.data.StartedTestServerStub 7 | import io.github.xlopec.tea.time.travel.plugin.feature.notification.ServerStarted 8 | import io.github.xlopec.tea.time.travel.plugin.feature.notification.ServerStopped 9 | import io.github.xlopec.tea.time.travel.plugin.feature.notification.StateDeployed 10 | import io.github.xlopec.tea.time.travel.plugin.feature.server.* 11 | import io.github.xlopec.tea.time.travel.plugin.integration.Message 12 | import io.github.xlopec.tea.time.travel.plugin.integration.ServerCommand 13 | 14 | interface TestServerCommandResolver : ServerCommandResolver, IdlingResource 15 | class SimpleTestServerCommandResolver : TestServerCommandResolver { 16 | override fun resolveServerCommand( 17 | command: ServerCommand, 18 | ctx: ResolveCtx, 19 | ) { 20 | ctx.effect { 21 | when (command) { 22 | is DoStartServer -> ServerStarted(StartedTestServerStub) 23 | is DoStopServer -> ServerStopped 24 | is DoApplyMessage -> null 25 | is DoApplyState -> StateDeployed(command.id, command.state) 26 | else -> error("shouldn't get here") 27 | } 28 | } 29 | } 30 | 31 | override val isIdleNow: Boolean = true 32 | } 33 | -------------------------------------------------------------------------------- /samples/shared-app-lib/src/androidMain/kotlin/io/github/xlopec/reader/app/feature/article/details/ArticleDetailsModule.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License 3 | * 4 | * Copyright (c) 2022. Maksym Oliinyk. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | @file:JvmName("AndroidArticleDetailsModule") 26 | @file:Suppress("FunctionName") 27 | 28 | package io.github.xlopec.reader.app.feature.article.details 29 | 30 | import android.app.Application 31 | 32 | public fun ArticleDetailsModule( 33 | application: Application 34 | ): ArticleDetailsModule = ArticleDetailsResolver(application) 35 | -------------------------------------------------------------------------------- /tea-data/src/iosMain/kotlin/io/github/xlopec/tea/data/UUID.ios.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License 3 | * 4 | * Copyright (c) 2022. Maksym Oliinyk. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | @file:Suppress("FunctionName") 26 | 27 | package io.github.xlopec.tea.data 28 | 29 | import platform.Foundation.NSUUID 30 | 31 | public actual typealias UUID = NSUUID 32 | 33 | public actual fun RandomUUID(): UUID = NSUUID() 34 | 35 | public actual fun UUIDFrom( 36 | value: String, 37 | ): UUID = NSUUID(value) 38 | 39 | public actual fun UUID.toHumanReadable(): String = UUIDString 40 | -------------------------------------------------------------------------------- /samples/shared-app-lib/src/commonMain/kotlin/io/github/xlopec/reader/app/AppResolver.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License 3 | * 4 | * Copyright (c) 2022. Maksym Oliinyk. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | package io.github.xlopec.reader.app 26 | 27 | import io.github.xlopec.reader.app.command.Command 28 | import io.github.xlopec.tea.core.ResolveCtx 29 | import io.github.xlopec.tea.core.Snapshot 30 | 31 | public fun interface AppResolver { 32 | 33 | public fun Env.resolve( 34 | snapshot: Snapshot, 35 | context: ResolveCtx 36 | ) 37 | } 38 | -------------------------------------------------------------------------------- /tea-data/src/commonMain/kotlin/io/github/xlopec/tea/data/Url.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License 3 | * 4 | * Copyright (c) 2022. Maksym Oliinyk. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | @file:Suppress("FunctionName") 26 | 27 | package io.github.xlopec.tea.data 28 | 29 | public expect class Url 30 | 31 | public expect val Url.domain: String 32 | 33 | public expect val Url.protocol: String? 34 | 35 | public val Url.isSecureProtocol: Boolean 36 | get() = protocol == "https" 37 | 38 | public expect fun UrlFor( 39 | s: String 40 | ): Url 41 | 42 | public expect fun Url.toExternalValue(): String 43 | -------------------------------------------------------------------------------- /samples/shared-app-lib/src/commonMain/kotlin/io/github/xlopec/reader/app/feature/settings/SettingsScreen.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License 3 | * 4 | * Copyright (c) 2022. Maksym Oliinyk. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | package io.github.xlopec.reader.app.feature.settings 26 | 27 | import io.github.xlopec.reader.app.ScreenId 28 | import io.github.xlopec.reader.app.TabScreen 29 | import io.github.xlopec.reader.app.feature.navigation.Tab 30 | 31 | public data object SettingsScreen : TabScreen { 32 | override val tab: Tab = Tab.Settings 33 | override val id: ScreenId = Tab.Settings.id 34 | } 35 | -------------------------------------------------------------------------------- /tea-data/src/jvmMain/kotlin/io/github/xlopec/tea/data/UUID.jvm.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License 3 | * 4 | * Copyright (c) 2022. Maksym Oliinyk. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | @file:Suppress("FunctionName") 26 | 27 | package io.github.xlopec.tea.data 28 | 29 | import java.util.UUID as JavaUUID 30 | 31 | public actual typealias UUID = java.util.UUID 32 | 33 | public actual fun RandomUUID(): UUID = 34 | JavaUUID.randomUUID() 35 | 36 | public actual fun UUIDFrom( 37 | value: String 38 | ): UUID = JavaUUID.fromString(value) 39 | 40 | public actual fun UUID.toHumanReadable(): String = toString() 41 | -------------------------------------------------------------------------------- /tea-data/src/jvmMain/kotlin/io/github/xlopec/tea/data/Url.jvm.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License 3 | * 4 | * Copyright (c) 2022. Maksym Oliinyk. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | @file:Suppress("FunctionName") 26 | 27 | package io.github.xlopec.tea.data 28 | 29 | public actual typealias Url = java.net.URI 30 | 31 | public actual fun UrlFor( 32 | s: String 33 | ): Url = java.net.URI(s) 34 | 35 | public actual fun Url.toExternalValue(): String = toASCIIString() 36 | 37 | public actual val Url.domain: String 38 | get() = host 39 | 40 | public actual val Url.protocol: String? 41 | get() = scheme 42 | -------------------------------------------------------------------------------- /samples/shared-app-lib/src/androidMain/kotlin/io/github/xlopec/reader/app/ContextExtensions.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License 3 | * 4 | * Copyright (c) 2022. Maksym Oliinyk. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | package io.github.xlopec.reader.app 26 | 27 | import android.content.Context 28 | import android.content.res.Configuration 29 | 30 | public val Context.systemDarkModeEnabled: Boolean 31 | get() = resources.configuration.systemDarkModeEnabled 32 | 33 | public val Configuration.systemDarkModeEnabled: Boolean 34 | get() = Configuration.UI_MODE_NIGHT_YES == uiMode and Configuration.UI_MODE_NIGHT_MASK 35 | -------------------------------------------------------------------------------- /samples/shared-app-lib/src/commonMain/kotlin/io/github/xlopec/reader/app/MessageHandler.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License 3 | * 4 | * Copyright (c) 2022. Maksym Oliinyk. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | package io.github.xlopec.reader.app 26 | 27 | import kotlinx.coroutines.CoroutineScope 28 | import kotlinx.coroutines.flow.FlowCollector 29 | import kotlinx.coroutines.launch 30 | 31 | public typealias MessageHandler = (Message) -> Unit 32 | 33 | public fun CoroutineScope.messageHandler( 34 | messages: FlowCollector, 35 | ): MessageHandler = 36 | { message -> launch { messages.emit(message) } } 37 | -------------------------------------------------------------------------------- /samples/shared-app-lib/src/androidMain/kotlin/io/github/xlopec/reader/app/feature/network/PlatformSerializers.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License 3 | * 4 | * Copyright (c) 2022. Maksym Oliinyk. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | package io.github.xlopec.reader.app.feature.network 26 | 27 | import java.text.SimpleDateFormat 28 | import java.util.* 29 | 30 | private val DateParser = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.ENGLISH) 31 | 32 | public actual fun Date.toJson(): String = DateParser.format(this) 33 | 34 | public actual fun String.toDate(): Date = DateParser.parse(this) ?: error("Invalid date $this") 35 | -------------------------------------------------------------------------------- /tea-time-travel-plugin/src/test/integration/kotlin/io/github/xlopec/tea/time/travel/plugin/environment/TestEnvironment.kt: -------------------------------------------------------------------------------- 1 | @file:Suppress("TestFunctionName") 2 | 3 | package io.github.xlopec.tea.time.travel.plugin.environment 4 | 5 | import androidx.compose.ui.test.IdlingResource 6 | import io.github.xlopec.tea.time.travel.plugin.feature.notification.NotificationResolver 7 | import io.github.xlopec.tea.time.travel.plugin.feature.server.ServerCommandResolver 8 | import io.github.xlopec.tea.time.travel.plugin.feature.storage.StorageResolver 9 | import io.github.xlopec.tea.time.travel.plugin.integration.AppResolver 10 | import io.github.xlopec.tea.time.travel.plugin.integration.AppUpdater 11 | import io.github.xlopec.tea.time.travel.plugin.integration.Environment 12 | import kotlinx.coroutines.CoroutineScope 13 | import kotlinx.coroutines.test.StandardTestDispatcher 14 | 15 | interface TestEnvironment : Environment, IdlingResource 16 | 17 | fun TestEnvironment( 18 | serverCommandResolver: TestServerCommandResolver = SimpleTestServerCommandResolver(), 19 | storageResolver: TestStorageResolver = SimpleTestStorageResolver(), 20 | notificationResolver: NotificationResolver = SimpleTestNotificationResolver(), 21 | scope: CoroutineScope = CoroutineScope(StandardTestDispatcher()), 22 | ): TestEnvironment = object : TestEnvironment, 23 | AppUpdater by AppUpdater(), 24 | StorageResolver by storageResolver, 25 | ServerCommandResolver by serverCommandResolver, 26 | NotificationResolver by notificationResolver, 27 | AppResolver by AppResolver(), 28 | CoroutineScope by scope { 29 | 30 | override val isIdleNow: Boolean 31 | get() = serverCommandResolver.isIdleNow && storageResolver.isIdleNow 32 | } 33 | -------------------------------------------------------------------------------- /samples/shared-app-lib/src/commonMain/kotlin/io/github/xlopec/reader/app/feature/filter/Module.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License 3 | * 4 | * Copyright (c) 2022. Maksym Oliinyk. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | @file:Suppress("FunctionName") 26 | 27 | package io.github.xlopec.reader.app.feature.filter 28 | 29 | import io.github.xlopec.reader.app.feature.article.list.NewsApi 30 | import io.github.xlopec.reader.app.feature.storage.LocalStorage 31 | 32 | public typealias FiltersModule = FiltersResolver 33 | 34 | public fun FiltersModule(): FiltersModule where Env : LocalStorage, Env : NewsApi = 35 | FiltersResolver() 36 | -------------------------------------------------------------------------------- /tea-time-travel-protocol/src/commonMain/kotlin/io/github/xlopec/tea/time/travel/protocol/ComponentId.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License 3 | * 4 | * Copyright (c) 2022. Maksym Oliinyk. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | package io.github.xlopec.tea.time.travel.protocol 26 | 27 | import kotlin.jvm.JvmInline 28 | 29 | /** 30 | * Component identifier, it can be any non blank and non-empty string 31 | * 32 | * @param value raw identifier value 33 | */ 34 | @JvmInline 35 | public value class ComponentId( 36 | public val value: String, 37 | ) { 38 | init { 39 | require(value.isNotBlank() && value.isNotEmpty()) 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /tea-time-travel-plugin/src/test/unit/kotlin/io/github/xlopec/tea/time/travel/plugin/model/StateExtensionsTest.kt: -------------------------------------------------------------------------------- 1 | package io.github.xlopec.tea.time.travel.plugin.model 2 | 3 | import io.github.xlopec.tea.time.travel.plugin.data.ComponentDebugStates 4 | import io.github.xlopec.tea.time.travel.plugin.data.StartedTestServerStub 5 | import io.github.xlopec.tea.time.travel.plugin.data.ValidTestSettings 6 | import kotlinx.collections.immutable.toPersistentMap 7 | import org.junit.Test 8 | import kotlin.test.assertTrue 9 | 10 | class StateExtensionsTest { 11 | 12 | @Test 13 | fun `test canExport returns true given state is started and has data for export`() { 14 | assertTrue( 15 | State( 16 | debugger = Debugger( 17 | settings = ValidTestSettings, 18 | components = ComponentDebugStates().toMap().toPersistentMap() 19 | ), 20 | server = StartedTestServerStub 21 | ).canExport 22 | ) 23 | 24 | assertTrue( 25 | State( 26 | debugger = Debugger( 27 | settings = ValidTestSettings, 28 | components = ComponentDebugStates().toMap().toPersistentMap() 29 | ), 30 | server = null 31 | ).canExport 32 | ) 33 | } 34 | 35 | @Test 36 | fun `test isStarted returns true given state is started`() { 37 | assertTrue(State(debugger = Debugger(ValidTestSettings), server = StartedTestServerStub).isStarted) 38 | } 39 | 40 | @Test 41 | fun `test canStart returns true given state is stopped and contain valid settings`() { 42 | assertTrue(State(settings = ValidTestSettings).canStart) 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /tea-time-travel-plugin/src/main/java/io/github/xlopec/tea/time/travel/plugin/feature/notification/Notifications.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021. Maksym Oliinyk. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package io.github.xlopec.tea.time.travel.plugin.feature.notification 18 | 19 | import com.intellij.notification.NotificationGroupManager 20 | import com.intellij.notification.NotificationType 21 | import com.intellij.openapi.actionSystem.AnAction 22 | import com.intellij.openapi.project.Project 23 | 24 | fun Project.showNotification( 25 | title: String, 26 | message: String, 27 | type: NotificationType, 28 | vararg actions: AnAction 29 | ) = showNotification(title, message, type, listOf(*actions)) 30 | 31 | fun Project.showNotification( 32 | title: String, 33 | message: String, 34 | type: NotificationType, 35 | actions: Iterable 36 | ) { 37 | NotificationGroupManager.getInstance() 38 | .getNotificationGroup("Tea Time Traveller") 39 | .createNotification(title, message, type) 40 | .addActions(actions as? MutableCollection ?: actions.toMutableList() as MutableCollection) 41 | .notify(this) 42 | } 43 | -------------------------------------------------------------------------------- /hooks/pre-commit.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | # MIT License 4 | # 5 | # Copyright (c) 2022. Maksym Oliinyk. 6 | # 7 | # Permission is hereby granted, free of charge, to any person obtaining a copy 8 | # of this software and associated documentation files (the "Software"), to deal 9 | # in the Software without restriction, including without limitation the rights 10 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | # copies of the Software, and to permit persons to whom the Software is 12 | # furnished to do so, subject to the following conditions: 13 | # 14 | # The above copyright notice and this permission notice shall be included in all 15 | # copies or substantial portions of the Software. 16 | # 17 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | # SOFTWARE. 24 | # 25 | 26 | # checks code style and performs code base analysis 27 | # should reside in Git's hook directory 28 | 29 | branch=$(git rev-parse --abbrev-ref HEAD) 30 | 31 | die () { 32 | echo 33 | echo "$*" 34 | echo 35 | exit 1 36 | } 37 | 38 | if [[ ${branch} =~ master|^dev.*|^release.* ]]; then 39 | 40 | chmod +x ./gradlew 41 | 42 | echo "performing code style checking and analysis" 43 | 44 | ./gradlew detekt -q || die "code analysis has failed!" 45 | 46 | echo "done performing code analysis" 47 | 48 | fi -------------------------------------------------------------------------------- /samples/shared-app-lib/src/commonMain/kotlin/io/github/xlopec/reader/app/feature/settings/Message.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License 3 | * 4 | * Copyright (c) 2022. Maksym Oliinyk. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | package io.github.xlopec.reader.app.feature.settings 26 | 27 | import io.github.xlopec.reader.app.ScreenMessage 28 | 29 | public sealed interface SettingsMessage : ScreenMessage 30 | 31 | public data class ToggleDarkMode( 32 | val userDarkModeEnabled: Boolean, 33 | val syncWithSystemDarkModeEnabled: Boolean, 34 | ) : SettingsMessage 35 | 36 | public data class SystemDarkModeChanged( 37 | val enabled: Boolean 38 | ) : SettingsMessage 39 | -------------------------------------------------------------------------------- /samples/app/src/remote/kotlin/io/github/xlopec/reader/app/AndroidAppComponent.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License 3 | * 4 | * Copyright (c) 2022. Maksym Oliinyk. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | @file:Suppress("FunctionName") 26 | 27 | package io.github.xlopec.reader.app 28 | 29 | import android.app.Application 30 | import io.github.xlopec.reader.BuildConfig 31 | import kotlinx.coroutines.CoroutineScope 32 | 33 | fun AppComponent( 34 | application: Application, 35 | scope: CoroutineScope, 36 | ) = Environment(BuildConfig.DEBUG, application, scope) 37 | .let { env -> DebuggableAppComponent(env, AppInitializer(application.systemDarkModeEnabled, env)) } 38 | -------------------------------------------------------------------------------- /samples/shared-app-lib/src/commonMain/kotlin/io/github/xlopec/reader/app/feature/article/list/Module.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License 3 | * 4 | * Copyright (c) 2022. Maksym Oliinyk. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | @file:Suppress("FunctionName") 26 | 27 | package io.github.xlopec.reader.app.feature.article.list 28 | 29 | import io.github.xlopec.reader.app.feature.storage.LocalStorage 30 | 31 | public typealias ArticlesModule = ArticlesResolver 32 | 33 | public fun ArticlesModule( 34 | shareArticle: ShareArticle 35 | ): ArticlesModule where Env : NewsApi, 36 | Env : LocalStorage = ArticlesResolver(shareArticle) 37 | -------------------------------------------------------------------------------- /samples/shared-app-lib/src/commonMain/kotlin/io/github/xlopec/reader/app/Message.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License 3 | * 4 | * Copyright (c) 2022. Maksym Oliinyk. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | package io.github.xlopec.reader.app 26 | 27 | import io.github.xlopec.reader.app.command.Command 28 | import io.github.xlopec.reader.app.model.Filter 29 | 30 | public interface Message 31 | 32 | public interface ScreenMessage : Message 33 | 34 | public data class Log( 35 | val throwable: Throwable, 36 | val causedBy: Command, 37 | val id: ScreenId? = null, 38 | ) : ScreenMessage 39 | 40 | public data class FilterUpdated( 41 | val filter: Filter, 42 | ) : ScreenMessage 43 | -------------------------------------------------------------------------------- /samples/shared-app-lib/src/iosMain/kotlin/io/github/xlopec/reader/app/feature/article/list/NewsApi.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License 3 | * 4 | * Copyright (c) 2022. Maksym Oliinyk. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | package io.github.xlopec.reader.app.feature.article.list 26 | 27 | import io.github.xlopec.reader.app.feature.network.NewsApiImpl 28 | import io.github.xlopec.reader.app.model.Country 29 | import io.ktor.client.engine.darwin.* 30 | import platform.Foundation.NSLocale 31 | import platform.Foundation.countryCode 32 | import platform.Foundation.currentLocale 33 | 34 | public fun NewsApi(): NewsApi = NewsApiImpl(Darwin, Country(NSLocale.currentLocale.countryCode ?: "en")) 35 | -------------------------------------------------------------------------------- /samples/iosApp/iosApp/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /tea-data/src/iosMain/kotlin/io/github/xlopec/tea/data/Date.ios.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License 3 | * 4 | * Copyright (c) 2022. Maksym Oliinyk. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | package io.github.xlopec.tea.data 26 | 27 | import platform.Foundation.NSDate 28 | import platform.Foundation.dateWithTimeIntervalSince1970 29 | import platform.Foundation.timeIntervalSince1970 30 | 31 | public actual typealias Date = NSDate 32 | 33 | public actual fun now(): Date = NSDate() 34 | 35 | public actual fun fromMillis( 36 | millis: Long 37 | ): Date = NSDate.dateWithTimeIntervalSince1970(millis / 1000.0) 38 | 39 | public actual fun Date.toMillis(): Long = (timeIntervalSince1970() * 1000.0).toLong() 40 | -------------------------------------------------------------------------------- /samples/shared-app-lib/src/iosMain/kotlin/io/github/xlopec/reader/app/feature/network/PlatformSerializers.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License 3 | * 4 | * Copyright (c) 2022. Maksym Oliinyk. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | package io.github.xlopec.reader.app.feature.network 26 | 27 | import io.github.xlopec.tea.data.Date 28 | import platform.Foundation.NSDateFormatter 29 | 30 | private val DateParser = NSDateFormatter().apply { 31 | dateFormat = "yyyy-MM-dd'T'HH:mm:ss'Z'" 32 | } 33 | 34 | public actual fun Date.toJson(): String = DateParser.stringFromDate(this) 35 | 36 | public actual fun String.toDate(): Date = DateParser.dateFromString(this) 37 | ?: error("couldn't parse $this as date") 38 | -------------------------------------------------------------------------------- /tea-time-travel-plugin/resources/META-INF/pluginIcon.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | 8 | 10 | 25 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /tea-time-travel-plugin/src/main/java/io/github/xlopec/tea/time/travel/plugin/model/PInt.kt: -------------------------------------------------------------------------------- 1 | package io.github.xlopec.tea.time.travel.plugin.model 2 | 3 | /** 4 | * Denotes positive integer - x > 0 5 | */ 6 | @JvmInline 7 | value class PInt private constructor( 8 | val value: UInt 9 | ) : Comparable { 10 | 11 | companion object { 12 | val MIN_VALUE = PInt(1U) 13 | val MAX_VALUE = PInt(UInt.MAX_VALUE) 14 | 15 | fun of( 16 | value: Int 17 | ) = of(value.toUInt()) 18 | 19 | fun of( 20 | value: UInt 21 | ) = PInt(value.coerceAtLeast(MIN_VALUE.value)) 22 | } 23 | 24 | override fun compareTo( 25 | other: PInt 26 | ): Int = value.compareTo(other.value) 27 | } 28 | 29 | fun Int.toPInt(): PInt = PInt.of(this) 30 | 31 | fun UInt.toPInt(): PInt = PInt.of(this) 32 | 33 | fun PInt.toInt(): Int = value.toInt() 34 | 35 | fun PInt.toUInt(): UInt = value 36 | 37 | @Suppress("NOTHING_TO_INLINE") 38 | inline operator fun PInt.plus( 39 | other: PInt 40 | ) = (value + other.value).toPInt() 41 | 42 | @Suppress("NOTHING_TO_INLINE") 43 | inline operator fun PInt.minus( 44 | other: PInt 45 | ) = (value - other.value).toPInt() 46 | 47 | @Suppress("NOTHING_TO_INLINE") 48 | inline operator fun PInt.times( 49 | other: PInt 50 | ) = (value * other.value).toPInt() 51 | 52 | @Suppress("NOTHING_TO_INLINE") 53 | inline operator fun PInt.div( 54 | other: PInt 55 | ) = (value / other.value).toPInt() 56 | 57 | @Suppress("NOTHING_TO_INLINE") 58 | inline operator fun PInt.rem( 59 | other: PInt 60 | ) = (value % other.value).toPInt() 61 | 62 | @Suppress("NOTHING_TO_INLINE") 63 | inline operator fun PInt.inc() = value.inc().toPInt() 64 | 65 | @Suppress("NOTHING_TO_INLINE") 66 | inline operator fun PInt.dec() = value.dec().toPInt() 67 | -------------------------------------------------------------------------------- /tea-data/src/iosMain/kotlin/io/github/xlopec/tea/data/Url.ios.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License 3 | * 4 | * Copyright (c) 2022. Maksym Oliinyk. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | @file:Suppress("FunctionName") 26 | 27 | package io.github.xlopec.tea.data 28 | 29 | import platform.Foundation.NSURL 30 | 31 | @Suppress("CONFLICTING_OVERLOADS") 32 | public actual typealias Url = NSURL 33 | 34 | public actual fun UrlFor( 35 | s: String 36 | ): Url = NSURL(string = s) 37 | 38 | public actual fun Url.toExternalValue(): String = toString() 39 | 40 | public actual val Url.domain: String 41 | get() = host ?: error("No domain: ${toExternalValue()}") 42 | 43 | public actual val Url.protocol: String? 44 | get() = scheme 45 | -------------------------------------------------------------------------------- /samples/shared-app-lib/src/androidMain/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 38 | 39 | -------------------------------------------------------------------------------- /samples/shared-app-lib/src/commonMain/kotlin/io/github/xlopec/reader/app/feature/article/details/Message.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License 3 | * 4 | * Copyright (c) 2022. Maksym Oliinyk. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | package io.github.xlopec.reader.app.feature.article.details 26 | 27 | import io.github.xlopec.reader.app.ScreenId 28 | import io.github.xlopec.reader.app.ScreenMessage 29 | 30 | public sealed interface ArticleDetailsMessage : ScreenMessage { 31 | public val id: ScreenId 32 | } 33 | 34 | public data class ToggleArticleIsFavorite( 35 | override val id: ScreenId, 36 | ) : ArticleDetailsMessage 37 | 38 | public data class OpenInBrowser( 39 | override val id: ScreenId 40 | ) : ArticleDetailsMessage 41 | -------------------------------------------------------------------------------- /samples/shared-app-lib/src/commonMain/kotlin/io/github/xlopec/reader/app/feature/article/details/ArticleDetailsState.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License 3 | * 4 | * Copyright (c) 2022. Maksym Oliinyk. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | package io.github.xlopec.reader.app.feature.article.details 26 | 27 | import io.github.xlopec.reader.app.FullScreen 28 | import io.github.xlopec.reader.app.ScreenId 29 | import io.github.xlopec.reader.app.model.Article 30 | 31 | public data class ArticleDetailsState internal constructor( 32 | override val id: ScreenId, 33 | val article: Article, 34 | ) : FullScreen 35 | 36 | internal fun ArticleDetailsState.article( 37 | toggled: Article 38 | ): ArticleDetailsState = copy(article = toggled) 39 | -------------------------------------------------------------------------------- /samples/shared-app-lib/src/iosMain/kotlin/io/github/xlopec/reader/app/feature/storage/LocalStorage.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License 3 | * 4 | * Copyright (c) 2022. Maksym Oliinyk. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | @file:Suppress("FunctionName") 26 | 27 | package io.github.xlopec.reader.app.feature.storage 28 | 29 | import com.squareup.sqldelight.db.SqlDriver 30 | import com.squareup.sqldelight.drivers.native.NativeSqliteDriver 31 | import io.github.xlopec.reader.app.storage.AppDatabase 32 | 33 | private const val DBfileName = "app.db" 34 | 35 | internal fun LocalStorage( 36 | schema: SqlDriver.Schema = AppDatabase.Schema, 37 | dbName: String = DBfileName, 38 | ): LocalStorage = 39 | LocalStorage(NativeSqliteDriver(schema, dbName)) 40 | -------------------------------------------------------------------------------- /samples/shared-app-lib/src/androidMain/kotlin/io/github/xlopec/reader/app/feature/storage/LocalStorageImpl.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License 3 | * 4 | * Copyright (c) 2022. Maksym Oliinyk. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | @file:Suppress("FunctionName") 26 | 27 | @file:JvmName("AndroidLocalStorageImpl") 28 | 29 | package io.github.xlopec.reader.app.feature.storage 30 | 31 | import android.app.Application 32 | import com.squareup.sqldelight.android.AndroidSqliteDriver 33 | import io.github.xlopec.reader.app.storage.AppDatabase 34 | 35 | private const val DBfileName = "app.db" 36 | 37 | internal fun LocalStorage( 38 | application: Application 39 | ): LocalStorage = 40 | LocalStorage(AndroidSqliteDriver(AppDatabase.Schema, application, DBfileName)) 41 | -------------------------------------------------------------------------------- /samples/shared-app-lib/src/commonMain/kotlin/io/github/xlopec/reader/app/command/Command.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License 3 | * 4 | * Copyright (c) 2022. Maksym Oliinyk. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | package io.github.xlopec.reader.app.command 26 | 27 | import io.github.xlopec.reader.app.AppState 28 | import io.github.xlopec.reader.app.ScreenId 29 | 30 | /*sealed*/ 31 | public interface Command 32 | 33 | // App wide commands 34 | 35 | public data class DoLog( 36 | val state: AppState, 37 | val throwable: Throwable, 38 | val id: ScreenId?, 39 | val causedBy: Command, 40 | ) : Command 41 | 42 | public data class DoStoreDarkMode( 43 | val userDarkModeEnabled: Boolean, 44 | val syncWithSystemDarkModeEnabled: Boolean 45 | ) : Command 46 | -------------------------------------------------------------------------------- /tea-time-travel-plugin/resources/META-INF/pluginIcon_dark.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | 8 | 10 | 25 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /samples/shared-app-lib/src/commonMain/kotlin/io/github/xlopec/reader/app/Screens.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License 3 | * 4 | * Copyright (c) 2022. Maksym Oliinyk. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | package io.github.xlopec.reader.app 26 | 27 | import androidx.compose.runtime.Immutable 28 | import io.github.xlopec.reader.app.feature.navigation.Tab 29 | import io.github.xlopec.tea.navigation.NavStackEntry 30 | 31 | @Immutable 32 | public sealed interface Screen : NavStackEntry 33 | 34 | /** 35 | * Intermediate screen that should be rendered without 36 | * tab frame 37 | */ 38 | public interface FullScreen : Screen 39 | 40 | /** 41 | * Root screen in the navigation hierarchy 42 | */ 43 | public interface TabScreen : Screen { 44 | public val tab: Tab 45 | } 46 | -------------------------------------------------------------------------------- /tea-time-travel-plugin/src/main/java/io/github/xlopec/tea/time/travel/plugin/feature/component/ui/TreePreview.kt: -------------------------------------------------------------------------------- 1 | package io.github.xlopec.tea.time.travel.plugin.feature.component.ui 2 | 3 | import androidx.compose.desktop.ui.tooling.preview.Preview 4 | import androidx.compose.runtime.Composable 5 | import androidx.compose.runtime.CompositionLocalProvider 6 | import io.github.xlopec.tea.time.travel.plugin.model.* 7 | import io.github.xlopec.tea.time.travel.plugin.ui.theme.PluginPreviewTheme 8 | 9 | private val PreviewTreeRoot = Ref( 10 | Type.of("io.github.xlopec.Developer"), 11 | Property("name", StringWrapper("Max")), 12 | Property("surname", StringWrapper("Oliynick")), 13 | Property( 14 | "interests", 15 | CollectionWrapper( 16 | listOf( 17 | StringWrapper("Jetpack Compose"), 18 | StringWrapper("Programming"), 19 | StringWrapper("FP") 20 | ) 21 | ) 22 | ), 23 | Property("emptyCollection", CollectionWrapper()) 24 | ) 25 | 26 | @Preview 27 | @Composable 28 | private fun ValueTreePreviewExpandedShort() { 29 | PluginPreviewTheme { 30 | CompositionLocalProvider( 31 | LocalInitialExpandState provides true 32 | ) { 33 | Tree( 34 | root = PreviewTreeRoot, 35 | formatter = ::toReadableStringShort, 36 | valuePopupContent = {} 37 | ) 38 | } 39 | } 40 | } 41 | 42 | @Preview 43 | @Composable 44 | private fun ValueTreePreviewExpandedLong() { 45 | PluginPreviewTheme { 46 | CompositionLocalProvider( 47 | LocalInitialExpandState provides true 48 | ) { 49 | Tree( 50 | root = PreviewTreeRoot, 51 | formatter = ::toReadableStringLong, 52 | valuePopupContent = {} 53 | ) 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /samples/shared-app-lib/src/commonMain/kotlin/io/github/xlopec/reader/app/model/Source.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License 3 | * 4 | * Copyright (c) 2022. Maksym Oliinyk. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | package io.github.xlopec.reader.app.model 26 | 27 | import io.github.xlopec.tea.data.Url 28 | import kotlin.jvm.JvmInline 29 | 30 | public data class Source( 31 | val id: SourceId, 32 | val name: SourceName, 33 | val description: SourceDescription?, 34 | val url: Url, 35 | val logo: Url, 36 | ) 37 | 38 | @JvmInline 39 | public value class SourceName( 40 | public val value: String, 41 | ) 42 | 43 | @JvmInline 44 | public value class SourceDescription( 45 | public val value: String, 46 | ) 47 | 48 | @JvmInline 49 | public value class SourceId( 50 | public val value: String, 51 | ) 52 | -------------------------------------------------------------------------------- /samples/shared-app-lib/src/iosMain/kotlin/io/github/xlopec/reader/app/feature/article/details/ArticleDetailsResolver.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License 3 | * 4 | * Copyright (c) 2022. Maksym Oliinyk. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | @file:Suppress("FunctionName") 26 | 27 | package io.github.xlopec.reader.app.feature.article.details 28 | 29 | import kotlinx.coroutines.Dispatchers 30 | import kotlinx.coroutines.withContext 31 | import platform.UIKit.UIApplication 32 | 33 | public fun ArticleDetailsResolver(): ArticleDetailsResolver = 34 | object : ArticleDetailsResolver { 35 | override suspend fun resolve(command: DoOpenInBrowser) { 36 | withContext(Dispatchers.Main) { 37 | UIApplication.sharedApplication.openURL(command.article.url) 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /tea-time-travel-adapter-gson/build.gradle.kts: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License 3 | * 4 | * Copyright (c) 2022. Maksym Oliinyk. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | plugins { 26 | `published-jvm-library-convention` 27 | } 28 | 29 | tasks.test { 30 | useJUnit() 31 | } 32 | 33 | val allTests by tasks.creating(Task::class) { 34 | dependsOn("test") 35 | } 36 | 37 | dependencies { 38 | 39 | api(project(":tea-time-travel-protocol")) 40 | api(libs.gson) 41 | implementation(project(":tea-data")) 42 | implementation(libs.stdlib.reflect) 43 | 44 | implementation(libs.stdlib) 45 | 46 | testImplementation(project(":tea-test")) 47 | testImplementation(project(":tea-time-travel-protocol")) 48 | testImplementation(libs.collections.immutable) 49 | testImplementation(libs.junit) 50 | } 51 | -------------------------------------------------------------------------------- /samples/shared-app-lib/src/commonMain/kotlin/io/github/xlopec/reader/app/feature/filter/SuggestionsInitializer.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License 3 | * 4 | * Copyright (c) 2022. Maksym Oliinyk. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | @file:Suppress("FunctionName") 26 | 27 | package io.github.xlopec.reader.app.feature.filter 28 | 29 | import io.github.xlopec.reader.app.ScreenId 30 | import io.github.xlopec.reader.app.misc.Loadable 31 | import io.github.xlopec.reader.app.model.Filter 32 | import io.github.xlopec.tea.core.Update 33 | import io.github.xlopec.tea.core.command 34 | 35 | public fun FiltersInitialUpdate( 36 | id: ScreenId, 37 | filter: Filter, 38 | ): Update = FiltersState(id, filter, Loadable.newLoading()) 39 | .command(DoLoadRecentSearches(id, filter.type), DoLoadSources(id)) 40 | -------------------------------------------------------------------------------- /samples/shared-app-lib/src/commonMain/kotlin/io/github/xlopec/reader/app/ui/screens/filters/FiltersSubtitle.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License 3 | * 4 | * Copyright (c) 2022. Maksym Oliinyk. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | package io.github.xlopec.reader.app.ui.screens.filters 26 | 27 | import androidx.compose.material.MaterialTheme 28 | import androidx.compose.material.Text 29 | import androidx.compose.runtime.Composable 30 | import androidx.compose.ui.Modifier 31 | import androidx.compose.ui.text.style.TextAlign 32 | 33 | @Composable 34 | internal fun FiltersSubtitle( 35 | modifier: Modifier, 36 | text: String, 37 | ) { 38 | Text( 39 | text = text, 40 | modifier = modifier, 41 | textAlign = TextAlign.Start, 42 | style = MaterialTheme.typography.subtitle1 43 | ) 44 | } 45 | -------------------------------------------------------------------------------- /tea-time-travel/src/commonMain/kotlin/io/github/xlopec/tea/time/travel/component/internal/FlowExtension.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License 3 | * 4 | * Copyright (c) 2022. Maksym Oliinyk. 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | package io.github.xlopec.tea.time.travel.component.internal 26 | 27 | import kotlinx.coroutines.coroutineScope 28 | import kotlinx.coroutines.flow.Flow 29 | import kotlinx.coroutines.flow.channelFlow 30 | import kotlinx.coroutines.launch 31 | 32 | internal fun Flow.mergeWith( 33 | another: Flow 34 | ): Flow = channelFlow { 35 | coroutineScope { 36 | launch { 37 | another.collect { 38 | send(it) 39 | } 40 | } 41 | 42 | launch { 43 | collect { 44 | send(it) 45 | } 46 | } 47 | } 48 | } 49 | --------------------------------------------------------------------------------