btw <@U79JY5TL3> and I sorted out the KMMBridge ba...
# confetti
j
btw @mbonnin and I sorted out the KMMBridge based publication of Confetti Swift Package....you should be able to search for Confetti now when adding package in XCode (assuming you've added your github account) and add to project. We've updated to publish to https://repsy.io/ maven repo now (thanks to suggestion from @bod). In a fresh XCode project, along with Confetti , you'll also need to add Firebase swift pacakge as well....at least Auth part anyway.....and also add libsqllite3 lib. I haven't gone beyond this yet as need to figure out minimum Decompose plumbing I need to pull in to get say basic list of sessions showing)
@Arkadii Ivanov I'd be curious to see if there's perhaps more minimal example we can create than maybe what we have in main repo right now......we'll probably also need to update talk we've been giving to use Decompose instead of KMMViewModel so would be useful for that too πŸ™‚
a
Sorry, but I don't understand what you are talking about πŸ˜€ What's the Confetti swift package? How can it be used? What is the context?
j
Sorry, yeah, didn't really provide any context πŸ˜ƒ . So, for KMP, it's becoming more and more common to build shared code as a Swift Package which you can then easily add in XCode. This package is, as we've done, usually published to some public repo.
So, given that, I was looking at what minimum app we could create that consumed that package and maybe showed list of sessions.
right now for example, in main repo, we've pulled in these....wasn't sure if these are all always needed
anyway, nothing urgent of course.....as mentioned, also have this in mind for next talk we have to give where we're also trying to create something quite minimal in short period of time
I'll play around with things anyway and see what I can pare it down to
For example if we want to show single view in an app (e.g. list of sessions) then maybe all the nav related stuff isn't needed
a
How did you add ObservableValue as a Swift package?
j
I didn't....the above was from main confetti project. Assume I'd have to add those manually here as well
a
Are there any links? For some reason it's difficult for me to understand what's going on. What's the main Confetti project? Isn't it the one where we added Decompose recently?
in main repo, we've pulled in these
I understand this as we added those things on the screenshot as swift packages. But it looks like I'm wrong.
j
I could be misunderstanding things as well....I'll try a few a thing here
Ok, so say I'm creating new iOS app that's consuming shared Confetti code......it has single screen.....is it possible for that to use
SessionsComponent
directly?
actually, that's in interface of course.....might be able to instantiate
DefaultSessionsComponent
from swift code
a
Don't forget to satisfy any Koin dependencies, they are implicit
j
DefaultSessionsComponent
is a
KoinComponent
and I've called
KoinKt.doInitKoin()
...are there other changes you think are needed?
I've got to point that I'm getting back and reflecting loading state .....but not success yet for some. reason
this is what I have here now (along with other "plumbing" files)
Copy code
struct SessionsView: View {
    private let component: SessionsComponent
    private let lifecycle: LifecycleRegistry

    @StateValue
    private var uiState: SessionsUiState
    
    init() {
        lifecycle = LifecycleRegistryKt.LifecycleRegistry()
        
        self.component = DefaultSessionsComponent(
            componentContext: DefaultComponentContext(lifecycle: lifecycle),
            conference: "droidconsf2023", user: nil, onSessionSelected: {_ in }, onSignIn: {})
        
            
        _uiState = StateValue(component.uiState)
    }
    
    var body: some View {
        switch uiState {
        case is SessionsUiStateLoading: ProgressView()
        case is SessionsUiStateError: ErrorView()
        case let state as SessionsUiStateSuccess: SessionsContentView(component: component, sessionUiState: state)
        default: EmptyView()
        }
    }
}
I might also need to do something with lifeycle ...
a
are there other changes you think are needed?
That should be enough.
First thing, you are embedding the component incorrectly. This way it will be instantiated every time the view is re-rendered. I would derive the approach from that link I provided above. If you are doing this in a new empty iOS app, then you could just use that approach as it is.
And you would also need to drive the lifecycle, as it is done in Confetti.
j
do you have to use
UIApplicationDelegate
?
or could that be done in
App
class?
a
I would copy the whole initial plumbing from Confetti. In particular:
AppDelegate.swift
and
iOSApp.swift
j
ok....also re. "This way it will be instantiated every time the view is re-rendered.", would it be sufficient I wonder to use @State for it
Part of what I'm looking at here is what the absolute minimum code needed would be πŸ™‚
a
would it be sufficient I wonder to use @State for it
I never tried it, sorry.
Part of what I'm looking at here is what the absolute minimum code needed would be
In this case, I would try extracting the whole plumbing into a separate Holder class, call
LifecycleRegistryExtKt.resume(lifecycle)
in
init
, and
destroy
in
deinit
. Then embed the Holder as
StateObject
.
j
thanks, will try that
that worked! So, this is pretty much all the code (other than actual session info rendering)
Copy code
@main
struct Test2App: App {
    @State private var component: SessionsComponent
    private let lifecycle: LifecycleRegistry

    
    init() {
        KoinKt.doInitKoin()
        
        lifecycle = LifecycleRegistryKt.LifecycleRegistry()
        LifecycleRegistryExtKt.resume(lifecycle)
        
        self.component = DefaultSessionsComponent(
            componentContext: DefaultComponentContext(lifecycle: lifecycle),
            conference: "droidconsf2023", user: nil, onSessionSelected: {_ in }, onSignIn: {})
    }
    
    var body: some Scene {
        WindowGroup {
            SessionsView(component)
        }
    }
}
Copy code
struct SessionsView: View {
    let component: SessionsComponent
    
    @StateValue
    private var uiState: SessionsUiState
    
    init(_ component: SessionsComponent) {
        self.component = component
        _uiState = StateValue(component.uiState)
    }
    
    var body: some View {
        switch uiState {
        case is SessionsUiStateLoading: ProgressView()
        case is SessionsUiStateError: ErrorView()
        case let state as SessionsUiStateSuccess: SessionsContentView(component: component, sessionUiState: state)
        default: EmptyView()
        }
    }
}
guess I need to also add something to call lifecycle destory
a
Well, that would be more than "minimum". But exactly because of this I suggested extracting to class, where
deinit
is available.
j
Well, that would be more than "minimum".
Sorry, didn't fully understand....what could be simplified above? You mean by creating that wrapper classs?
(I'm hoping to put this in to separate repo btw once it's at good stage)
I copied over most of SwiftUI to show list of sessions as well now
a
I meant that destroying the lifecycle is not strictly required, the app should be working fine without it, assuming this is the only screen in the app.
Could you also explain, what's the end goal of this?
j
ah, ok
So, the idea is that having shared code as Swift Package makes it very easy for someone for example, with very little setup, to create an iOS etc app that consumes that code.....and wanted then to show minimum code needed to get that up and running
I was also looking separately to trying out some of the updates announced at WWDC 23 e.g. creating macOS widget that used that same Swift Package....and again what minimum would be needed to set that up
Also hoping to try out visionOS once that SDK becomes available in a few weeks time πŸ˜ƒ
a
Got it, thanks!
j
ok, pushed changes so far to https://github.com/joreilly/ConfettiSwiftUI
it's an iOS and macOS app but will only work for iOS right now until I add mac target support to shared code
a
The repository's name is a bit confusing. E.g. both Confetti and ConfettiSwiftUI use SwiftUI. Maybe something like
ConfettiSPM
?
j
yeah, agreed.....original one was ConfgettiUsingSwfitPackage πŸ™‚
naming is hard πŸ™‚
a
That's true πŸ™‚
j
@mbonnin you're usually good with names....any thoughts πŸ™‚
m
@bod is the one who ends up with the good names, I'm just good at discussing the names πŸ˜‚
j
btw be good if folks could try to pull down that repo and see if it works for them......it works for me on one laptop but on another I'm seeing XCode issues with swfit package related to fact that confetti repo using git-lfs (main confetti repo is where
Package.swift
etc is hosted)
m
In that specific case, I'll have to dive in a bit. How many Swift Packages do we publish? If it's only one, might as well call it just
Confetti
?
j
no rush though of course
m
Oh wait, I see there's a new GitHub repo now
j
yeah, just to post this again "So, the idea is that having shared code as Swift Package makes it very easy for someone for example, with very little setup, to create an iOS etc app that consumes that code.....and wanted then to show minimum code needed to get that up and running"
m
Sorry, can't stay much right now but will read the thread this we and bikeshed the naming accordingly
j
in meantime, as mentioned, I'm going to try and add macOS target to shared code...hoping to try out new macOS Widgets with it!
b
(same but yeah I think
ConfettiSPM
probably makes sense)
j
My only concern with name like that is that it could seem to indicate that it's the repo that contains the actual package
b
oh ok if it's not I definitely need to re-read this thread πŸ˜„ sorry
j
my original name btw was
ConfgettiUsingSwfitPackage
πŸ™‚
b
descriptive πŸ‘
j
I'm also hoping to try and get iOS folks to maybe try this out....so was trying to lure them in a bit by including
SwiftUI
πŸ˜ƒ
and seeing that nice solid bar of red πŸ˜ƒ
It's also not intended to be the full app....more just. minimal sample to show how easy it is to get up and running (when consuming as swift package like this)
and, as is probably implied, showing a non-monorepo setup when using KMM
πŸ™‚
b
Perfect πŸ‘Œ