Sepehrom
Sepehrom

Reputation: 1335

Placing SwiftUI Data Sources Somewhere Else

I'm trying to use SwiftUI in a project but beyond the very basic version of using @States and @Bindings that can be found in every tutorial, so I need some help on what I'm doing wrong here.

Environment Setup: I have following files involved with this problem:

The Problem:

Here are the implementations (Partially) as I have done and have no idea where I have gone wrong:

CustomTextField:

struct CustomTextField: View {
@Binding var config: CustomTextFieldConfiguration

var body: some View {
    ZStack {
        VStack {
            VStack {
                ZStack {
                    HStack {
                        TextField($config.placeHolder,
                                  value: $config.textValue,
                                  formatter: NumberFormatter(),
                                  onEditingChanged: {_ in },
                                  onCommit: {})
                            .frame(height: 52.0)
                            .padding(EdgeInsets(top:    0, leading:  16 + ($config.detailActionImage != nil ? 44 : 0),
                                                bottom: 0, trailing: 16 + ($config.contentAlignment == .center && $config.detailActionImage != nil ? 44 : 0)))
                            .background($config.backgroundColor)
                            .cornerRadius($config.cornerRedius)
                            .font($config.font)
            ...
            ...
            ...
            ...

CustomTextFieldConfiguration:

struct CustomTextFieldConfiguration {
    @Binding var textValue: String
    ...
    ...
    ...
    ...

RootView:

struct RootView: View {
    @State var configuration: CustomTextFieldConfiguration
    var interactor: RootInteractorProtocol!
    @Environment(\.colorScheme) private var colorScheme
    
    var body: some View {
        HStack {
            Spacer(minLength: 40)
            VStack(alignment: .trailing) {
                CustomTextField(config: $configuration)
                Text("\(configuration.textValue)")
            }
            Spacer(minLength: 40)
        }
    }
}

RootPresenter:

class RootPresenter: BasePresenter {

    @ObservedObject var rootPresentationModel: RootPresentationModel

    init(presentationModel: RootPresentationModel) {
        rootPresentationModel = presentationModel
    }
    ...
    ...
    ...

RootPresentationModel:

class RootPresentationModel: ObservableObject {
    var textValue: String = ""  {
        didSet {
            print(textValue)
        }
    }
}

RootBuilder:

class RootBuilder: BaseBuilder {
    class func build() -> (RootView, RootInteractor) {
        let interactor = RootInteractor()
        
        let presenter = RootPresenter(presentationModel: RootPresentationModel())
        let view: RootView = RootView(configuration: CustomTextFieldConfiguration.Presets.priceInput(textValue: presenter.$rootPresentationModel.textValue, placeholder: "", description: ""), interactor: interactor)
        let router = RootRouter()
        
        interactor.presenter = presenter
        interactor.router = router
        
        return (view, interactor)
    }
}

(That Presets method doesn't do anything important, but just to make sure it will not raise an irrelevant question, here's the implementation):

static func priceInput(textValue: Binding<String>, placeholder: String, description: String) -> CustomTextFieldConfiguration {
      return CustomTextFieldConfiguration(textValue: textValue,
                                         placeHolder: placeholder,
                                         description: description,
                                         defaultDescription: description,
                                         textAlignment: .center,
                                         descriptionAlignment: .center,
                                         contentAlignment: .center,
                                         font: CustomFont.headline1))
}

Upvotes: 1

Views: 233

Answers (1)

lorem ipsum
lorem ipsum

Reputation: 29242

import SwiftUI
struct CustomTextField: View {
    @EnvironmentObject var config: CustomTextFieldConfiguration
    @Binding var textValue: Double
    var body: some View {
        ZStack {
            VStack {
                VStack {
                    ZStack {
                        HStack {
                            //Number formatter forces the need for Double
                            TextField(config.placeHolder,
                                      value: $textValue,
                                      formatter: NumberFormatter(),
                                      onEditingChanged: {_ in },
                                      onCommit: {})
                                .frame(height: 52.0)
                                //.padding(EdgeInsets(top:    0, leading:  16 + (Image(systemName: config.detailActionImageName) != nil ? 44 : 0),bottom: 0, trailing: 16 + (config.contentAlignment == .center && Image(systemName: config.detailActionImageName) != nil ? 44 : 0)))
                                .background(config.backgroundColor)
                                .cornerRadius(config.cornerRedius)
                                .font(config.font)
                        }
                    }
                }
            }
        }
    }
}
class CustomTextFieldConfiguration: ObservableObject {
    @Published var placeHolder: String = "place"
    @Published var detailActionImageName: String = "checkmark"
    @Published var contentAlignment: UnitPoint = .center
    @Published var backgroundColor: Color = Color(UIColor.secondarySystemBackground)
    @Published var font: Font = .body
    @Published var cornerRedius: CGFloat = CGFloat(5)
    @Published var description: String = ""
    @Published var defaultDescription: String = ""
    @Published var textAlignment: UnitPoint = .center
    @Published var descriptionAlignment: UnitPoint = .center
    
    init() {
        
    }
    init(placeHolder: String, description: String, defaultDescription: String, textAlignment: UnitPoint,descriptionAlignment: UnitPoint,contentAlignment: UnitPoint, font:Font) {
        self.placeHolder = placeHolder
        self.description = description
        self.defaultDescription = defaultDescription
        self.textAlignment = textAlignment
        self.descriptionAlignment = descriptionAlignment
        self.contentAlignment = contentAlignment
        self.font = font
    }
    struct Presets {
        static func priceInput(placeholder: String, description: String) -> CustomTextFieldConfiguration {
            return CustomTextFieldConfiguration(placeHolder: placeholder, description: description,defaultDescription: description,textAlignment: .center,descriptionAlignment: .center,contentAlignment: .center, font:Font.headline)
        }
    }
}
struct RootView: View {
    @ObservedObject var configuration: CustomTextFieldConfiguration
    //var interactor: RootInteractorProtocol!
    @Environment(\.colorScheme) private var colorScheme
    @Binding var textValue: Double
    
    var body: some View {
        HStack {
            Spacer(minLength: 40)
            VStack(alignment: .trailing) {
                CustomTextField(textValue: $textValue).environmentObject(configuration)
                Text("\(textValue)")
            }
            Spacer(minLength: 40)
        }
    }
}
//RootPresenter is a class @ObservedObject only works properly in SwiftUI Views/struct
class RootPresenter//: BasePresenter
{
    //Won't work can't chain ObservableObjects
//        var rootPresentationModel: RootPresentationModel
//
//        init(presentationModel: RootPresentationModel) {
//            rootPresentationModel = presentationModel
//        }
}
class RootPresentationModel: ObservableObject {
    @Published var textValue: Double = 12  {
        didSet {
            print(textValue)
        }
    }
}

struct NewView: View {
    //Must be observed directly
    @StateObject var vm: RootPresentationModel = RootPresentationModel()
    //This cannot be Observed
    let presenter: RootPresenter = RootPresenter()

    var body: some View {
        RootView(configuration: CustomTextFieldConfiguration.Presets.priceInput(placeholder: "", description: ""), textValue: $vm.textValue//, interactor: interactor
        )
    }
}

struct NewView_Previews: PreviewProvider {
    static var previews: some View {
        NewView()
    }
}

Upvotes: 2

Related Questions