diff --git a/android/shared/src/main/res/values-en/generated_strings.xml b/android/shared/src/main/res/values-en/generated_strings.xml index 38f9dbad..40ce8753 100644 --- a/android/shared/src/main/res/values-en/generated_strings.xml +++ b/android/shared/src/main/res/values-en/generated_strings.xml @@ -1,6 +1,6 @@ - + @@ -249,9 +249,7 @@ This tip is floating, you can define arrow anchors This message is optional This tip has rule that appears the tip after 3 taps on button - If you close the tip you will have to restart the app for appear tip - again - + If you close the tip you will have to restart the app for appear tip again Example of TipKit Inline tip Rule tip diff --git a/android/shared/src/main/res/values-sk/generated_strings.xml b/android/shared/src/main/res/values-sk/generated_strings.xml index 73461718..ba5880f9 100644 --- a/android/shared/src/main/res/values-sk/generated_strings.xml +++ b/android/shared/src/main/res/values-sk/generated_strings.xml @@ -1,6 +1,6 @@ - + @@ -248,11 +248,8 @@ Táto správa je nepovinná Tento tip je plávajúci, môžete definovať kotvy šípok Táto správa je nepovinná - Tento tip má pravidlo, že sa tip zobrazí po 3 ťuknutiach na tlačidlo - - Ak tip zatvoríte, budete musieť reštartovať aplikáciu, aby sa tip opäť - zobrazil - + Tento tip má pravidlo, že sa tip zobrazí po 3 ťuknutiach na tlačidlo + Ak tip zatvoríte, budete musieť reštartovať aplikáciu, aby sa tip opäť zobrazil Príklady TipKita Inline tip Rule tip diff --git a/android/shared/src/main/res/values/generated_strings.xml b/android/shared/src/main/res/values/generated_strings.xml index 02d9bd52..7b6afaef 100644 --- a/android/shared/src/main/res/values/generated_strings.xml +++ b/android/shared/src/main/res/values/generated_strings.xml @@ -1,6 +1,6 @@ - + @@ -248,11 +248,8 @@ Tahle zpráva je nepovinná Tento tip je plovoucí, můžete definovat kotvy šipek Tahle zpráva je nepovinná - Tento tip má pravidlo, že se tip objeví po 3 klepnutích na tlačítko - - Pokud tip zavřete, budete muset aplikaci restartovat, aby se tip znovu - objevil. - + Tento tip má pravidlo, že se tip objeví po 3 klepnutích na tlačítko + Pokud tip zavřete, budete muset aplikaci restartovat, aby se tip znovu objevil. Příklady TipKitu Inline tip Rule tip diff --git a/ios/PresentationLayer/Onboarding/Sources/Onboarding/Errors/ValidationError.swift b/ios/PresentationLayer/Onboarding/Sources/Onboarding/Errors/ValidationError.swift index add3e094..b79bb8be 100644 --- a/ios/PresentationLayer/Onboarding/Sources/Onboarding/Errors/ValidationError.swift +++ b/ios/PresentationLayer/Onboarding/Sources/Onboarding/Errors/ValidationError.swift @@ -13,13 +13,11 @@ extension ValidationError: LocalizedError { switch self { case .email(let reason): switch reason { - #warning("TODO: Use MR strings when issue [https://github.com/icerockdev/moko-resources/issues/714] is resolved") - case .isEmpty: "Invalid email format" // MR.strings().invalid_email.desc().localized() + case .isEmpty: return MR.strings().invalid_email.desc().localized() } case .password(let reason): switch reason { - #warning("TODO: Use MR strings when issue [https://github.com/icerockdev/moko-resources/issues/714] is resolved") - case .isEmpty: "Invalid password" // MR.strings().invalid_password.desc().localized() + case .isEmpty: return MR.strings().invalid_password.desc().localized() } } } diff --git a/ios/PresentationLayer/Onboarding/Tests/OnboardingTests/LoginViewModelTests.swift b/ios/PresentationLayer/Onboarding/Tests/OnboardingTests/LoginViewModelTests.swift index 9655114b..8416c0ab 100644 --- a/ios/PresentationLayer/Onboarding/Tests/OnboardingTests/LoginViewModelTests.swift +++ b/ios/PresentationLayer/Onboarding/Tests/OnboardingTests/LoginViewModelTests.swift @@ -102,10 +102,10 @@ final class LoginViewModelTests: XCTestCase { func testLoginInvalidPassword() async { let vm = createViewModel() let errorResult = AuthError.InvalidLoginCredentials(throwable: nil) - #warning("TODO: Use localizedMessage when issue [https://github.com/icerockdev/moko-resources/issues/714] is resolved") + fixMokoResourcesForTests() loginUseCase.executeThrowableError = KmmLocalizedError( errorResult: errorResult, - localizedMessage: "" // errorResult.localizedMessage(nil) + localizedMessage: errorResult.localizedMessage(nil) ) vm.onIntent(.changeEmail(LoginData.stubValid.email)) diff --git a/ios/PresentationLayer/Onboarding/Tests/OnboardingTests/RegistrationViewModelTests.swift b/ios/PresentationLayer/Onboarding/Tests/OnboardingTests/RegistrationViewModelTests.swift index 2d03d61d..d564ccdb 100644 --- a/ios/PresentationLayer/Onboarding/Tests/OnboardingTests/RegistrationViewModelTests.swift +++ b/ios/PresentationLayer/Onboarding/Tests/OnboardingTests/RegistrationViewModelTests.swift @@ -30,6 +30,7 @@ final class RegistrationViewModelTests: XCTestCase { // MARK: Tests func testRegisterEmptyEmail() async { + fixMokoResourcesForTests() let vm = createViewModel() registrationUseCase.executeThrowableError = ValidationError.email(.isEmpty) @@ -39,14 +40,13 @@ final class RegistrationViewModelTests: XCTestCase { await vm.awaitAllTasks() XCTAssert(!vm.state.isLoading) - #warning("TODO: Use MR strings when issue [https://github.com/icerockdev/moko-resources/issues/714] is resolved") - // XCTAssertEqual(vm.state.alert, AlertData(title: MR.strings().invalid_email.desc().localized())) - XCTAssertEqual(vm.state.alert, AlertData(title: "Invalid email format")) + XCTAssertEqual(vm.state.alert, AlertData(title: MR.strings().invalid_email.desc().localized())) XCTAssertEqual(fc.handleFlowValue, nil) XCTAssert(registrationUseCase.executeReceivedInvocations == [.stubEmptyEmail]) } func testRegisterEmptyPassword() async { + fixMokoResourcesForTests() let vm = createViewModel() registrationUseCase.executeThrowableError = ValidationError.password(.isEmpty) @@ -56,9 +56,7 @@ final class RegistrationViewModelTests: XCTestCase { await vm.awaitAllTasks() XCTAssert(!vm.state.isLoading) - #warning("TODO: Use MR strings when issue [https://github.com/icerockdev/moko-resources/issues/714] is resolved") - // XCTAssertEqual(vm.state.alert, AlertData(title: MR.strings().invalid_password.desc().localized())) - XCTAssertEqual(vm.state.alert, AlertData(title: "Invalid password")) + XCTAssertEqual(vm.state.alert, AlertData(title: MR.strings().invalid_password.desc().localized())) XCTAssertEqual(fc.handleFlowValue, nil) XCTAssert(registrationUseCase.executeReceivedInvocations == [.stubEmptyPassword]) } diff --git a/ios/PresentationLayer/Recipes/Sources/Recipes/TipKit/ExampleTipKitViewModel.swift b/ios/PresentationLayer/Recipes/Sources/Recipes/TipKit/ExampleTipKitViewModel.swift index aed24097..644fae94 100644 --- a/ios/PresentationLayer/Recipes/Sources/Recipes/TipKit/ExampleTipKitViewModel.swift +++ b/ios/PresentationLayer/Recipes/Sources/Recipes/TipKit/ExampleTipKitViewModel.swift @@ -17,7 +17,7 @@ class ExampleTipKitViewModel: BaseViewModel, ObservableObject, ViewModel { super.init() if #available(iOS 17, *) { - state.remainigTapsToShowTip = 3 - RuleTip.remainToShow.donations.count + state.remainingTapsToShowTip = 3 - RuleTip.remainToShow.donations.count } } diff --git a/ios/PresentationLayer/UIToolkit/Sources/UIToolkit/Extensions/Bundle+Extensions.swift b/ios/PresentationLayer/UIToolkit/Sources/UIToolkit/Extensions/Bundle+Extensions.swift deleted file mode 100644 index 99e29813..00000000 --- a/ios/PresentationLayer/UIToolkit/Sources/UIToolkit/Extensions/Bundle+Extensions.swift +++ /dev/null @@ -1,40 +0,0 @@ -// -// Created by Petr Chmelar on 30.05.2022 -// Copyright © 2022 Matee. All rights reserved. -// - -import Foundation - -extension Bundle { - /// Workaround for crashing SwiftUI Previews when any of underlying modules uses .module - /// Taken from: https://developer.apple.com/forums/thread/664295 - static var myModule: Bundle = { - /* The name of your local package, prepended by "LocalPackages_" for iOS and "PackageName_" for macOS. You may have same PackageName and TargetName*/ - let bundleNameIOS = "LocalPackages_UIToolkit" - let bundleNameMacOs = "UIToolkit_UIToolkit" - let candidates = [ - /* Bundle should be present here when the package is linked into an App. */ - Bundle.main.resourceURL, - /* Bundle should be present here when the package is linked into a framework. */ - Bundle(for: BundleToken.self).resourceURL, - /* For command-line tools. */ - Bundle.main.bundleURL, - /* Bundle should be present here when running previews from a different package (this is the path to "…/Debug-iphonesimulator/"). */ - Bundle(for: BundleToken.self).resourceURL?.deletingLastPathComponent().deletingLastPathComponent().deletingLastPathComponent(), - Bundle(for: BundleToken.self).resourceURL?.deletingLastPathComponent().deletingLastPathComponent() - ] - - for candidate in candidates { - let bundlePathiOS = candidate?.appendingPathComponent(bundleNameIOS + ".bundle") - let bundlePathMacOS = candidate?.appendingPathComponent(bundleNameMacOs + ".bundle") - if let bundle = bundlePathiOS.flatMap(Bundle.init(url:)) { - return bundle - } else if let bundle = bundlePathMacOS.flatMap(Bundle.init(url:)) { - return bundle - } - } - fatalError("unable to find bundle") - }() -} - -private final class BundleToken {} diff --git a/ios/PresentationLayer/UIToolkit/Sources/UIToolkit/Extensions/BundleToken.swift b/ios/PresentationLayer/UIToolkit/Sources/UIToolkit/Extensions/BundleToken.swift new file mode 100644 index 00000000..2c25da40 --- /dev/null +++ b/ios/PresentationLayer/UIToolkit/Sources/UIToolkit/Extensions/BundleToken.swift @@ -0,0 +1,8 @@ +// +// Created by Petr Chmelar on 30.05.2022 +// Copyright © 2022 Matee. All rights reserved. +// + +import Foundation + +private final class BundleToken {} diff --git a/ios/PresentationLayer/UIToolkit/Sources/UIToolkit/Utilities/MokoFix.swift b/ios/PresentationLayer/UIToolkit/Sources/UIToolkit/Utilities/MokoFix.swift new file mode 100644 index 00000000..5937199f --- /dev/null +++ b/ios/PresentationLayer/UIToolkit/Sources/UIToolkit/Utilities/MokoFix.swift @@ -0,0 +1,20 @@ +// +// Created by Julia Jakubcova on 23/09/2024 +// Copyright © 2024 Matee. All rights reserved. +// + +import DevstackKmpShared + +#warning("TODO: Remove this workaround when issue [https://github.com/icerockdev/moko-resources/issues/714] is resolved") +public func fixMokoResourcesForTests() { + if ProcessInfo.processInfo.processName == "xctest" { + MokoResourcesPreviewWorkaroundKt.nsBundle = Bundle.init(for: KotlinBase.self) + } +} + +#warning("TODO: Remove this workaround when issue [https://github.com/icerockdev/moko-resources/issues/714] is resolved") +public func fixMokoResourcesForPreviews() { + if ProcessInfo.processInfo.processName == "XCPreviewAgent" { + MokoResourcesPreviewWorkaroundKt.nsBundle = Bundle.init(for: KotlinBase.self) + } +} diff --git a/ios/PresentationLayer/UIToolkit/Sources/UIToolkit/Utilities/Plurals.swift b/ios/PresentationLayer/UIToolkit/Sources/UIToolkit/Utilities/Plurals.swift index 52eeaedb..28e83260 100644 --- a/ios/PresentationLayer/UIToolkit/Sources/UIToolkit/Utilities/Plurals.swift +++ b/ios/PresentationLayer/UIToolkit/Sources/UIToolkit/Utilities/Plurals.swift @@ -22,15 +22,15 @@ public enum Plurals: String { func stringForCount(_ count: Int) -> String { if count == 0 { // swiftlint:disable:this empty_count - return String(format: NSLocalizedString("zero_\(rawValue)", bundle: .myModule, comment: ""), count) + return String(format: NSLocalizedString("zero_\(rawValue)", bundle: .module, comment: ""), count) } else if abs(count) == 1 { - return String(format: NSLocalizedString("one_\(rawValue)", bundle: .myModule, comment: ""), count) + return String(format: NSLocalizedString("one_\(rawValue)", bundle: .module, comment: ""), count) } else if abs(count) > 1 && abs(count) < 5 { - return String(format: NSLocalizedString("few_\(rawValue)", bundle: .myModule, comment: ""), count) + return String(format: NSLocalizedString("few_\(rawValue)", bundle: .module, comment: ""), count) } else if abs(count) >= 5 { - return String(format: NSLocalizedString("many_\(rawValue)", bundle: .myModule, comment: ""), count) + return String(format: NSLocalizedString("many_\(rawValue)", bundle: .module, comment: ""), count) } else { - return String(format: NSLocalizedString("other_\(rawValue)", bundle: .myModule, comment: ""), count) + return String(format: NSLocalizedString("other_\(rawValue)", bundle: .module, comment: ""), count) } } } diff --git a/ios/PresentationLayer/UIToolkit/Sources/UIToolkit/swiftgen-strings.stencil b/ios/PresentationLayer/UIToolkit/Sources/UIToolkit/swiftgen-strings.stencil index 3fb3ceae..06956484 100644 --- a/ios/PresentationLayer/UIToolkit/Sources/UIToolkit/swiftgen-strings.stencil +++ b/ios/PresentationLayer/UIToolkit/Sources/UIToolkit/swiftgen-strings.stencil @@ -3,7 +3,6 @@ // Revision: 7e13d641745b56775d9a7f983a5468d2d9952ada // Modifications: -// - Use `.myModule` [workaround](https://developer.apple.com/forums/thread/664295) to address SwiftUI Previews crashes // - Use snake_case instead of camelCase, this is done by changing `swiftIdentifier:"pretty"` to `swiftIdentifier` // - Ability to change localization via Environment.localization @@ -102,7 +101,7 @@ extension {{enumName}} { private final class BundleToken { static let bundle: Bundle = { #if SWIFT_PACKAGE - return Bundle.myModule + return Bundle.module #else return Bundle(for: BundleToken.self) #endif diff --git a/ios/PresentationLayer/UIToolkit/Sources/UIToolkit/swiftgen-xcassets.stencil b/ios/PresentationLayer/UIToolkit/Sources/UIToolkit/swiftgen-xcassets.stencil index cbdc65c9..0797b806 100644 --- a/ios/PresentationLayer/UIToolkit/Sources/UIToolkit/swiftgen-xcassets.stencil +++ b/ios/PresentationLayer/UIToolkit/Sources/UIToolkit/swiftgen-xcassets.stencil @@ -3,7 +3,6 @@ // Revision: 937d05fa32ff389c63f93f0f9e2919d2c461b3c9 // Modifications: -// - Use `.myModule` [workaround](https://developer.apple.com/forums/thread/664295) to address SwiftUI Previews crashes // - Ensure SwiftUI-first behavior for colors by renaming `.color` to `.uiColor` and `.swiftUIColor` to `.color` // - Ensure SwiftUI-first behavior for images by renaming `.image` to `.uiImage` and `.swiftUIImage` to `.image` @@ -433,7 +432,7 @@ private final class BundleToken { static let bundle: Bundle = { #if SWIFT_PACKAGE - return Bundle.myModule + return Bundle.module #else return Bundle(for: BundleToken.self) #endif diff --git a/shared/src/commonMain/resources/MR/base/strings.xml b/shared/src/commonMain/resources/MR/base/strings.xml index 9ff005cd..6123e657 100644 --- a/shared/src/commonMain/resources/MR/base/strings.xml +++ b/shared/src/commonMain/resources/MR/base/strings.xml @@ -1,6 +1,6 @@ - + diff --git a/shared/src/commonMain/resources/MR/cs/strings.xml b/shared/src/commonMain/resources/MR/cs/strings.xml index db17d481..c6046142 100644 --- a/shared/src/commonMain/resources/MR/cs/strings.xml +++ b/shared/src/commonMain/resources/MR/cs/strings.xml @@ -1,6 +1,6 @@ - + diff --git a/shared/src/commonMain/resources/MR/sk/strings.xml b/shared/src/commonMain/resources/MR/sk/strings.xml index fdafdcc1..b44be65e 100644 --- a/shared/src/commonMain/resources/MR/sk/strings.xml +++ b/shared/src/commonMain/resources/MR/sk/strings.xml @@ -1,6 +1,6 @@ - + diff --git a/shared/src/iosMain/kotlin/dev/icerock/moko/resources/utils/MokoResourcesPreviewWorkaround.kt b/shared/src/iosMain/kotlin/dev/icerock/moko/resources/utils/MokoResourcesPreviewWorkaround.kt new file mode 100644 index 00000000..2e3f2518 --- /dev/null +++ b/shared/src/iosMain/kotlin/dev/icerock/moko/resources/utils/MokoResourcesPreviewWorkaround.kt @@ -0,0 +1,38 @@ +package dev.icerock.moko.resources.utils // must be same as in moko-resources to override method + +import platform.Foundation.NSBundle +import platform.Foundation.NSDirectoryEnumerator +import platform.Foundation.NSFileManager +import platform.Foundation.NSURL +import platform.Foundation.pathExtension + +/** + * Workaround by MAX-POLKOVNIK from https://github.com/icerockdev/moko-resources/issues/747#issuecomment-2330854244 + * Remove when https://github.com/icerockdev/moko-resources/issues/747 is resolved + */ + +var nsBundle: NSBundle = NSBundle.mainBundle // <-- this is where we should looking for resources, by default mainBundle + +fun NSBundle.Companion.loadableBundle(identifier: String): NSBundle { + val bundlePath: String = nsBundle.bundlePath // <-- path where we should search for bundle with resources + val enumerator: NSDirectoryEnumerator = requireNotNull(NSFileManager.defaultManager.enumeratorAtPath(bundlePath)) + while (true) { + val relativePath: String = enumerator.nextObject() as? String ?: break + val url = NSURL(fileURLWithPath = relativePath) + if (url.pathExtension == "bundle") { + val fullPath = "$bundlePath/$relativePath" + val foundedBundle: NSBundle? = NSBundle.bundleWithPath(fullPath) + val loadedIdentifier: String? = foundedBundle?.bundleIdentifier + + if (isBundleSearchLogEnabled) { + println("moko-resources auto-load bundle with identifier $loadedIdentifier at path $fullPath") + } + + if (foundedBundle?.bundleIdentifier == identifier) return foundedBundle + } + } + + throw IllegalArgumentException("bundle with identifier $identifier not found") +} + +var isBundleSearchLogEnabled = false