Eureka icon indicating copy to clipboard operation
Eureka copied to clipboard

Footer and header duplication

Open amadeu01 opened this issue 5 years ago • 15 comments

IMG_4E59B0DD8762-1

After hidden/unhidden a section by doing

section.hidden = .function(["care"]) { form -> Bool in
            guard let row = form.rowBy(tag: "care") as? MultipleSelectorRow<Care>,
                let care = row.value else {
                    return true
            }

            return !careTypes.contains(where: { $0.shouldCare == true })
        }

amadeu01 avatar Apr 11 '19 21:04 amadeu01

Hi @amadeu01 can you share a entire form definition so I can see what's going on..

mtnbarreto avatar Apr 12 '19 15:04 mtnbarreto

@mtnbarreto

private func initForm(with data: RequisitionFormData) {
        healthPlanFilesSection(with: data)
        personalFilesSection(with: data)
        appointmentTypeSection(with: data)
        addressSection(with: data)
        requisitionSection(with: data)
        scheduleSection(with: data)
        contactSection(with: data)
        extraSection(with: data)
    }

    private func healthPlanFilesSection(with data: RequisitionFormData) {
        form
            +++ Section()

            <<< SwitchRow {
                $0.title = L10n.CreateRequisition.Row.Title.healthPlan
                $0.tag = "healthPlan"
                }.onChange { [weak self] row in
                    guard let isHealthPlan = row.value else { return }
                    self?.vm.requisition.update(\.isPrivate, to: !isHealthPlan)
            }

            +++ Section(L10n.CreateRequisition.Section.Header.healthPlanFiles) {
                $0.hidden = .function(["healthPlan"], { form -> Bool in
                    guard let row = form.rowBy(tag: "healthPlan") as? RowOf<Bool> else {
                        return false
                    }
                    return row.value ?? false == false
                })
        }

        addImageRow(for: .healthPlan, with: data)
    }

    private func personalFilesSection(with data: RequisitionFormData) {
        form +++ Section(L10n.CreateRequisition.Section.Header.personalFiles)
        addImageRow(for: .personal, with: data)
    }

    private func addImageRow(for group: RDFileType.Group, with data: RequisitionFormData) {
        guard let lastSection = form.allSections.last else { return }
        for fileType in data.images.filter({ $0.group == group }) {
            let uuid = UUID()
            lastSection <<< ImageRow {
                $0.title = fileType.name
                $0.tag = uuid.uuidString
                }.onChange { [weak self] row in
                    guard let image = row.value,
                        let data = image.jpegData(compressionQuality: 0.5) else { return }
                    self?.vm.addFile(data, for: uuid, with: fileType)
                }.onRemove { [weak self] _ in
                    self?.vm.removeFile(uuid)
            }
        }
    }

    private func appointmentTypeSection(with data: RequisitionFormData) {
        form
            +++ Section(L10n.CreateRequisition.Section.Header.careType)

            <<< MultipleSelectorRow<RDCareType> {
                $0.title = L10n.CreateRequisition.Row.Title.careType
                $0.options = data.careTypes
                $0.selectorTitle = L10n.CreateRequisition.Row.SelectorTitle.careType
                $0.tag = "careType"
                }
                .onPresent { [weak self] from, to in
                    to.navigationItem.rightBarButtonItem = self?.multipleSelectorDoneButton(from)
                }.onChange { [weak self] in
                    self?.vm.requisition.update(\.careTypes, to: Array($0.value ?? []))
            }

            <<< PushRow<RDUnity> {
                $0.title = L10n.CreateRequisition.Row.Title.unity
                $0.options = data.unities
                $0.selectorTitle = L10n.CreateRequisition.Row.SelectorTitle.unity
                }.onChange { [weak self] in
                    self?.vm.requisition.update(\.unity, to: $0.value)
        }
    }

    private func multipleSelectorDoneButton(_ from: UIViewController) -> UIBarButtonItem {
        return UIBarButtonItem(
            barButtonSystemItem: .done,
            target: from,
            action: #selector(CreateRequisitionViewController.multipleSelectorDone(_:))
        )
    }

    private func addressSection(with data: RequisitionFormData) {
        let section: Section

        if data.addresses.isEmpty {
            section = addressFormSection()
        } else {
            section = addressPushRowSection(with: data)
        }

        section.hidden = .function(["careType"]) { form -> Bool in
            guard let row = form.rowBy(tag: "careType") as? MultipleSelectorRow<RDCareType>,
                let careTypes = row.value else {
                    return true
            }

            return !careTypes.contains(where: { $0.shouldInformAddress == true })
        }

        form +++ section
    }

    private func addressPushRowSection(with data: RequisitionFormData) -> Section {
        return Section(L10n.CreateRequisition.Section.Header.address)
            <<< PushRow<RDAddress> {
                $0.title = L10n.CreateRequisition.Row.Title.address
                $0.options = data.addresses
                $0.selectorTitle = L10n.CreateRequisition.Row.SelectorTitle.address
                $0.displayValueFor = { address in return address?.name }
                }.onPresent { [weak self] from, to in
                    to.dismissOnSelection = false
                    to.dismissOnChange = false
                    to.row.displayValueFor = { address in return address?.name }
                    to.navigationItem.rightBarButtonItem = self?.multipleSelectorDoneButton(from)
                }
                .onChange { [weak self] in
                    guard let addressId = $0.value?.id else { return }
                    self?.vm.requisition.update(\.addressId, to: addressId)
        }
    }

    private func addressFormSection() -> Section {
        return sectionAddress { [weak self] keyPath, newValue in
            self?.vm.addressDidChange(keyPath, to: newValue)
        }
    }

    private func requisitionSection(with data: RequisitionFormData) {
        form
            +++ Section(L10n.CreateRequisition.Section.Header.medialRequisition) {
                $0.tag = "requisitionSection"
            }

            <<< ImageRow {
                $0.title = L10n.CreateRequisition.Row.Title.medicalRequisition
        }
    }

    private func scheduleSection(with data: RequisitionFormData) {
        form
            +++ Section(
                header: L10n.CreateRequisition.Section.Header.schedule,
                footer: L10n.CreateRequisition.Section.Footer.schedule
            ) {
                $0.tag = "scheduleSection"
            }

            <<< DateTimeRow {
                $0.title = L10n.CreateRequisition.Row.Title.schedule
                $0.value = Date()
                $0.minimumDate = Date()
        }
    }

    private func contactSection(with data: RequisitionFormData) {
        form
            +++ Section(L10n.CreateRequisition.Section.Header.contact) {
                $0.tag = "contactSection"
            }
            <<< phoneRow(with: data)
    }

    private func phoneRow(with data: RequisitionFormData) -> BaseRow {
        if data.phoneTypes.isEmpty {
            return emptyPhoneRow(with: data)
        } else {
            return pushPhoneRow(with: data)
        }
    }

    private func emptyPhoneRow(with data: RequisitionFormData) -> BaseRow {
        return SplitRow<PushRow<RDPhoneType>, PhoneRow> {
            $0.rowLeftPercentage = 0.45
            $0.rowLeft = PushRow<RDPhoneType> {
                $0.selectorTitle = L10n.CreateRequisition.Row.SelectorTitle.telephone
                $0.options = data.phoneTypes
                $0.value = data.phoneTypes.first
                }.onChange { [weak self] in
                    guard let typeId = $0.value?.id else { return }
                    self?.vm.phoneDidChange(\.typeId, to: typeId)
            }

            $0.rowRight = PhoneRow {
                $0.placeholder = ""
                $0.formatter = PhoneFormatter()
                }.onChange { [weak self] in self?.vm.phoneDidChange(\.number, to: ($0.value ?? ""))  }
        }
    }

    private func pushPhoneRow(with data: RequisitionFormData) -> BaseRow {
        return PushRow<RDPhone> {
            $0.title = L10n.CreateRequisition.Row.Title.phone
            $0.options = data.phoneNumbers
            $0.selectorTitle = L10n.CreateRequisition.Row.SelectorTitle.telephone
            $0.displayValueFor = { phone in return phone?.number }
            }.onPresent { [weak self] from, to in
                to.dismissOnSelection = false
                to.dismissOnChange = false
                to.row.displayValueFor = { phone in return phone?.number }
                to.row.cellStyle = .value2
                to.navigationItem.rightBarButtonItem = self?.multipleSelectorDoneButton(from)
            }
            .onChange { [weak self] in
                guard let phoneId = $0.value?.id else { return }
                self?.vm.requisition.update(\.phoneId, to: phoneId)
        }
    }

    private func extraSection(with data: RequisitionFormData) {
        form
            +++ Section()

            <<< TextAreaRow {
                $0.placeholder = L10n.CreateRequisition.Row.Placeholder.medicationInUse
                $0.textAreaHeight = .dynamic(initialTextViewHeight: 50)
                }.onChange { [weak self] in
                    self?.vm.requisition.update(\.medicinesInUse, to: $0.value)
            }

            <<< TextAreaRow {
                $0.placeholder = L10n.CreateRequisition.Row.Placeholder.observation
                $0.textAreaHeight = .dynamic(initialTextViewHeight: 50)
                }.onChange { [weak self] in
                    self?.vm.requisition.update(\.observation, to: $0.value)
        }
    }

    @objc func multipleSelectorDone(_ item: UIBarButtonItem) {
        _ = navigationController?.popViewController(animated: true)
    }

amadeu01 avatar Apr 12 '19 15:04 amadeu01

@amadeu01 Are you sure you have only one table view in the view's hierarchy?

mtnbarreto avatar Apr 12 '19 15:04 mtnbarreto

I was able to reproduce it.
Do you have the same footer in more than one section?

mtnbarreto avatar Apr 12 '19 16:04 mtnbarreto

@mtnbarreto replying both of your questions

I was able to reproduce it. Do you have the same footer in more than one section?

I do not.

The cell bellow the footer has other header.

image

@amadeu01 Are you sure you have only one table view in the view's hierarchy?

I do not have any-other table view. I only add sections and rows. All of them from eureka lib. I have this ImageRow, however I borrowed the code from the eureka demo. So, I do not seen another tableview.

amadeu01 avatar Apr 12 '19 16:04 amadeu01

@mtnbarreto I did a workaround of removing and adding the section with the duplicated footer. It worked, however I didn't like it.

ezgif com-optimize

I guess the solution would to remove and add all sections below the unhidden section.

amadeu01 avatar Apr 12 '19 16:04 amadeu01

great! I was trying to reproduce it in the example app but I couldn't. I willing to help but i need a complete form to reproduce it (your posted code is incomplete), so i suggest you change HiddenRowsExample.swift in the example app so i can take a look and we found the solution or what is causing the issue.

I don't like the workaround too.

mtnbarreto avatar Apr 12 '19 17:04 mtnbarreto

@mtnbarreto I couldn't reproduce the error with the example project. Still trying :(

amadeu01 avatar Apr 12 '19 19:04 amadeu01

@mtnbarreto I was able to reproduce the error!!!!!!

amadeu01 avatar Apr 12 '19 20:04 amadeu01

@mtnbarreto

Example/Example/Controllers/HiddenRowsExample.swift

AppDelegate

I notice that the error only occur when I use view code.

I did the changes in this branch

https://github.com/amadeu01/Eureka/tree/error

amadeu01 avatar Apr 12 '19 20:04 amadeu01

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {

        let window = UIWindow(frame: UIScreen.main.bounds)
        window.makeKeyAndVisible()
        let nav = UINavigationController()
        let example = HiddenRowsExample()
        nav.viewControllers = [example]
        window.rootViewController = nav

        self.window = window
        return true
    }

The problem might be in this init

class HiddenRowsExample : FormViewController {

    init() {
        super.init(style: UITableView.Style.grouped)
    }

@mtnbarreto is there any more desirable way of making a custom init for the FormController ?

amadeu01 avatar Apr 12 '19 20:04 amadeu01

@mtnbarreto have you had the chance of checking anything? I couldn't find the origin of the issue :(

amadeu01 avatar Apr 16 '19 20:04 amadeu01

Hi @amadeu01 , I will take a look shortly!

mtnbarreto avatar Apr 17 '19 14:04 mtnbarreto

hi @mtnbarreto !

Have you had the chance of looking at this issue? I haven't 😢

I'll try to look at it next week, if you get some time we could pair programming to try to find out the issue 😄

amadeu01 avatar Apr 28 '19 15:04 amadeu01

Hi, I have the same issue and I notice it only on iOS 12. When I try to reproduce it on iOS 14 — nothing happens and header seems to be fine. Just in case it helps anyone.

Is there any plan to fix it in the nearest future?

t4ec avatar Dec 21 '20 18:12 t4ec