diff --git a/AutoCat.xcodeproj/project.pbxproj b/AutoCat.xcodeproj/project.pbxproj index 134404d..5c80193 100644 --- a/AutoCat.xcodeproj/project.pbxproj +++ b/AutoCat.xcodeproj/project.pbxproj @@ -60,8 +60,6 @@ 7A6DD90C24335A6D009DE740 /* FlagLayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A6DD90B24335A6D009DE740 /* FlagLayer.swift */; }; 7A6DD90E24337930009DE740 /* PlateNumber.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A6DD90D24337930009DE740 /* PlateNumber.swift */; }; 7A6E03282485951700DB22ED /* OwnersController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A6E03272485951700DB22ED /* OwnersController.swift */; }; - 7A7547DD2403180A004E8406 /* SectionHeader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A7547DB2403180A004E8406 /* SectionHeader.swift */; }; - 7A7547DE2403180A004E8406 /* SectionHeader.xib in Resources */ = {isa = PBXBuildFile; fileRef = 7A7547DC2403180A004E8406 /* SectionHeader.xib */; }; 7A7547E024032CB6004E8406 /* VehiclePhotoCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A7547DF24032CB6004E8406 /* VehiclePhotoCell.swift */; }; 7A813DBE2506A57100CC93B9 /* AuthenticationServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7A813DBD2506A57100CC93B9 /* AuthenticationServices.framework */; }; 7A813DC12508C4D900CC93B9 /* ExceptionCatcher in Frameworks */ = {isa = PBXBuildFile; productRef = 7A813DC02508C4D900CC93B9 /* ExceptionCatcher */; }; @@ -96,10 +94,7 @@ 7AEF47A4253DC4D2001D6238 /* Eureka in Frameworks */ = {isa = PBXBuildFile; productRef = 7AEF47A3253DC4D2001D6238 /* Eureka */; }; 7AEFC3BE2529D3CC00BADFB2 /* ConfigurableCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AEFC3BD2529D3CC00BADFB2 /* ConfigurableCell.swift */; }; 7AEFE728240455E200910EB7 /* SettingsController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AEFE727240455E200910EB7 /* SettingsController.swift */; }; - 7AF58D2F24029C5200CE01A0 /* MagazineLayout in Frameworks */ = {isa = PBXBuildFile; productRef = 7AF58D2E24029C5200CE01A0 /* MagazineLayout */; }; - 7AF58D3124029E1000CE01A0 /* VehicleHeaderCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AF58D3024029E1000CE01A0 /* VehicleHeaderCell.swift */; }; 7AF58D342402A91C00CE01A0 /* Kingfisher in Frameworks */ = {isa = PBXBuildFile; productRef = 7AF58D332402A91C00CE01A0 /* Kingfisher */; }; - 7AF58D58240309CA00CE01A0 /* VehicleTextParamCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AF58D57240309CA00CE01A0 /* VehicleTextParamCell.swift */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ @@ -152,8 +147,6 @@ 7A6DD90B24335A6D009DE740 /* FlagLayer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FlagLayer.swift; sourceTree = ""; }; 7A6DD90D24337930009DE740 /* PlateNumber.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlateNumber.swift; sourceTree = ""; }; 7A6E03272485951700DB22ED /* OwnersController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OwnersController.swift; sourceTree = ""; }; - 7A7547DB2403180A004E8406 /* SectionHeader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SectionHeader.swift; sourceTree = ""; }; - 7A7547DC2403180A004E8406 /* SectionHeader.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = SectionHeader.xib; sourceTree = ""; }; 7A7547DF24032CB6004E8406 /* VehiclePhotoCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VehiclePhotoCell.swift; sourceTree = ""; }; 7A813DBD2506A57100CC93B9 /* AuthenticationServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AuthenticationServices.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.15.sdk/System/Library/Frameworks/AuthenticationServices.framework; sourceTree = DEVELOPER_DIR; }; 7A813DC22508EE4F00CC93B9 /* EventCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EventCell.swift; sourceTree = ""; }; @@ -185,8 +178,6 @@ 7AE26A3424F31B0700625033 /* EventsController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EventsController.swift; sourceTree = ""; }; 7AEFC3BD2529D3CC00BADFB2 /* ConfigurableCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConfigurableCell.swift; sourceTree = ""; }; 7AEFE727240455E200910EB7 /* SettingsController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsController.swift; sourceTree = ""; }; - 7AF58D3024029E1000CE01A0 /* VehicleHeaderCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VehicleHeaderCell.swift; sourceTree = ""; }; - 7AF58D57240309CA00CE01A0 /* VehicleTextParamCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VehicleTextParamCell.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -207,7 +198,6 @@ 7AABDE23253327F10041AFC6 /* DifferenceKit in Frameworks */, 7A530B8B240181F500CBFE6E /* RxRealm in Frameworks */, 7A11471F23FEA18700B424AF /* RxRelay in Frameworks */, - 7AF58D2F24029C5200CE01A0 /* MagazineLayout in Frameworks */, 7A11471D23FEA18700B424AF /* RxSwift in Frameworks */, 7A11472623FEA1F400B424AF /* Realm in Frameworks */, ); @@ -351,10 +341,6 @@ isa = PBXGroup; children = ( 7A530B7D24017FEE00CBFE6E /* VehicleCell.swift */, - 7AF58D3024029E1000CE01A0 /* VehicleHeaderCell.swift */, - 7AF58D57240309CA00CE01A0 /* VehicleTextParamCell.swift */, - 7A7547DB2403180A004E8406 /* SectionHeader.swift */, - 7A7547DC2403180A004E8406 /* SectionHeader.xib */, 7A7547DF24032CB6004E8406 /* VehiclePhotoCell.swift */, 7A1090E724A394F100B4F0B2 /* AudioRecordCell.swift */, 7A813DC22508EE4F00CC93B9 /* EventCell.swift */, @@ -434,7 +420,6 @@ 7A11472523FEA1F400B424AF /* Realm */, 7A11472723FEA1F400B424AF /* RealmSwift */, 7A530B8A240181F500CBFE6E /* RxRealm */, - 7AF58D2E24029C5200CE01A0 /* MagazineLayout */, 7AF58D332402A91C00CE01A0 /* Kingfisher */, 7A051610241412CA00FC55AC /* SwiftDate */, 7A813DC02508C4D900CC93B9 /* ExceptionCatcher */, @@ -474,7 +459,6 @@ 7A11471B23FEA18700B424AF /* XCRemoteSwiftPackageReference "RxSwift" */, 7A11472423FEA1F400B424AF /* XCRemoteSwiftPackageReference "realm-cocoa" */, 7A530B89240181F500CBFE6E /* XCRemoteSwiftPackageReference "RxRealm" */, - 7AF58D2D24029C5200CE01A0 /* XCRemoteSwiftPackageReference "MagazineLayout" */, 7AF58D322402A91C00CE01A0 /* XCRemoteSwiftPackageReference "Kingfisher" */, 7A05160F241412CA00FC55AC /* XCRemoteSwiftPackageReference "SwiftDate" */, 7A813DBF2508C4D900CC93B9 /* XCRemoteSwiftPackageReference "ExceptionCatcher" */, @@ -497,7 +481,6 @@ buildActionMask = 2147483647; files = ( 7ADF6C99250F872C00F237B2 /* RoadNumbers.otf in Resources */, - 7A7547DE2403180A004E8406 /* SectionHeader.xib in Resources */, 7A11470D23FDE7E600B424AF /* LaunchScreen.storyboard in Resources */, 7A6DD90A24329541009DE740 /* RoadNumbers2.0.otf in Resources */, 7A11470A23FDE7E600B424AF /* Assets.xcassets in Resources */, @@ -551,14 +534,11 @@ 7A6E03282485951700DB22ED /* OwnersController.swift in Sources */, 7A64AE742469DFB600ABE48E /* MediaContentView.swift in Sources */, 7A1090EC24A4E3E100B4F0B2 /* CellProgressView.swift in Sources */, - 7A7547DD2403180A004E8406 /* SectionHeader.swift in Sources */, - 7AF58D58240309CA00CE01A0 /* VehicleTextParamCell.swift in Sources */, 7A96AE2D246B2B7400297C33 /* GoogleSignInController.swift in Sources */, 7A15051224DB3E3000F39631 /* AnyEncodable.swift in Sources */, 7A1090EA24A3A26300B4F0B2 /* AudioPlayer.swift in Sources */, 7A11474723FF2AA500B424AF /* User.swift in Sources */, 7A11471623FDEB2A00B424AF /* MainSplitController.swift in Sources */, - 7AF58D3124029E1000CE01A0 /* VehicleHeaderCell.swift in Sources */, 7A813DC5250AAF3C00CC93B9 /* LocationEditController.swift in Sources */, 7A43F9F8246C8A6200BA5B49 /* JWT.swift in Sources */, 7A6DD903242BF4A5009DE740 /* PlateView.swift in Sources */, @@ -732,6 +712,7 @@ DEVELOPMENT_TEAM = 46DTTB8X4S; INFOPLIST_FILE = AutoCat/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 13.0; + "IPHONEOS_DEPLOYMENT_TARGET[sdk=macosx*]" = 13.1; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -754,6 +735,7 @@ DEVELOPMENT_TEAM = 46DTTB8X4S; INFOPLIST_FILE = AutoCat/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 13.0; + "IPHONEOS_DEPLOYMENT_TARGET[sdk=macosx*]" = 13.1; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -854,14 +836,6 @@ kind = branch; }; }; - 7AF58D2D24029C5200CE01A0 /* XCRemoteSwiftPackageReference "MagazineLayout" */ = { - isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/airbnb/MagazineLayout"; - requirement = { - kind = upToNextMajorVersion; - minimumVersion = 1.5.5; - }; - }; 7AF58D322402A91C00CE01A0 /* XCRemoteSwiftPackageReference "Kingfisher" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/onevcat/Kingfisher"; @@ -933,11 +907,6 @@ package = 7AEF47A2253DC4D2001D6238 /* XCRemoteSwiftPackageReference "Eureka" */; productName = Eureka; }; - 7AF58D2E24029C5200CE01A0 /* MagazineLayout */ = { - isa = XCSwiftPackageProductDependency; - package = 7AF58D2D24029C5200CE01A0 /* XCRemoteSwiftPackageReference "MagazineLayout" */; - productName = MagazineLayout; - }; 7AF58D332402A91C00CE01A0 /* Kingfisher */ = { isa = XCSwiftPackageProductDependency; package = 7AF58D322402A91C00CE01A0 /* XCRemoteSwiftPackageReference "Kingfisher" */; diff --git a/AutoCat.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/AutoCat.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index ce72e2d..4a8dc44 100644 --- a/AutoCat.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/AutoCat.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -37,15 +37,6 @@ "version": "5.15.5" } }, - { - "package": "MagazineLayout", - "repositoryURL": "https://github.com/airbnb/MagazineLayout", - "state": { - "branch": null, - "revision": "6f88742c282de208e48cb738a7a14b7dc2651701", - "version": "1.6.3" - } - }, { "package": "PKHUD", "repositoryURL": "https://github.com/pkluz/PKHUD.git", diff --git a/AutoCat.xcodeproj/xcuserdata/selim.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist b/AutoCat.xcodeproj/xcuserdata/selim.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist index 9f4253c..618c809 100644 --- a/AutoCat.xcodeproj/xcuserdata/selim.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist +++ b/AutoCat.xcodeproj/xcuserdata/selim.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist @@ -8,7 +8,7 @@ BreakpointExtensionID = "Xcode.Breakpoint.SwiftErrorBreakpoint"> @@ -17,7 +17,7 @@ BreakpointExtensionID = "Xcode.Breakpoint.ExceptionBreakpoint"> - - - - diff --git a/AutoCat.xcodeproj/xcuserdata/selim.xcuserdatad/xcschemes/xcschememanagement.plist b/AutoCat.xcodeproj/xcuserdata/selim.xcuserdatad/xcschemes/xcschememanagement.plist index 5eb0487..3d39954 100644 --- a/AutoCat.xcodeproj/xcuserdata/selim.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/AutoCat.xcodeproj/xcuserdata/selim.xcuserdatad/xcschemes/xcschememanagement.plist @@ -14,35 +14,35 @@ isShown orderHint - 5 + 8 DifferenceKit (Playground) 2.xcscheme isShown orderHint - 6 + 9 DifferenceKit (Playground).xcscheme isShown orderHint - 4 + 7 Eureka (Playground) 1.xcscheme isShown orderHint - 2 + 5 Eureka (Playground) 2.xcscheme isShown orderHint - 3 + 6 Eureka (Playground) 3.xcscheme @@ -70,7 +70,7 @@ isShown orderHint - 1 + 4 GettingStarted (Playground) 1.xcscheme @@ -112,42 +112,42 @@ isShown orderHint - 13 + 12 Rx (Playground) 1.xcscheme isShown orderHint - 8 + 2 Rx (Playground) 2.xcscheme isShown orderHint - 9 + 3 Rx (Playground).xcscheme isShown orderHint - 7 + 1 SwiftDate (Playground) 1.xcscheme isShown orderHint - 10 + 11 SwiftDate (Playground) 2.xcscheme isShown orderHint - 12 + 13 SwiftDate (Playground) 3.xcscheme @@ -175,7 +175,7 @@ isShown orderHint - 11 + 10 SuppressBuildableAutocreation diff --git a/AutoCat/Base.lproj/Main.storyboard b/AutoCat/Base.lproj/Main.storyboard index 1e6dac2..0d81553 100644 --- a/AutoCat/Base.lproj/Main.storyboard +++ b/AutoCat/Base.lproj/Main.storyboard @@ -1,12 +1,11 @@ - + - + - @@ -17,175 +16,8 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -203,7 +35,6 @@ - @@ -335,14 +166,14 @@ - + - + - + @@ -1050,26 +881,14 @@ - - - - - - - - - - - - diff --git a/AutoCat/Cells/SectionHeader.swift b/AutoCat/Cells/SectionHeader.swift deleted file mode 100644 index ce90577..0000000 --- a/AutoCat/Cells/SectionHeader.swift +++ /dev/null @@ -1,18 +0,0 @@ -import UIKit -import MagazineLayout - -class SectionHeader: MagazineLayoutCollectionReusableView { - @IBOutlet weak var title: UILabel! - @IBOutlet weak var divider: UIView! - @IBOutlet weak var dividerHeightConstraint: NSLayoutConstraint! - - override func awakeFromNib() { - super.awakeFromNib() - self.dividerHeightConstraint.constant = 1/UIScreen.main.scale - } - - func configure(with section: ReportSection) { - self.title.text = section.description - self.divider.isHidden = section == .photos - } -} diff --git a/AutoCat/Cells/SectionHeader.xib b/AutoCat/Cells/SectionHeader.xib deleted file mode 100644 index 3ea88fb..0000000 --- a/AutoCat/Cells/SectionHeader.xib +++ /dev/null @@ -1,49 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/AutoCat/Cells/VehicleHeaderCell.swift b/AutoCat/Cells/VehicleHeaderCell.swift deleted file mode 100644 index d3bf2e6..0000000 --- a/AutoCat/Cells/VehicleHeaderCell.swift +++ /dev/null @@ -1,23 +0,0 @@ -import UIKit -import MagazineLayout -import Kingfisher - -class VehicleHeaderCell: MagazineLayoutCollectionViewCell { - @IBOutlet weak var logo: UIImageView! - @IBOutlet weak var name: UILabel! - - private let placeholder = UIImage(named: "SteeringWheel") - - override func prepareForReuse() { - self.logo.kf.cancelDownloadTask() - } - - func configure(with vehicle: Vehicle) { - self.name.text = vehicle.brand?.name?.original - self.logo.image = self.placeholder - - if let url = vehicle.brand?.logo { - self.logo.kf.setImage(with: URL(string: url), placeholder: self.placeholder) - } - } -} diff --git a/AutoCat/Cells/VehiclePhotoCell.swift b/AutoCat/Cells/VehiclePhotoCell.swift index dd65b79..d1e4f07 100644 --- a/AutoCat/Cells/VehiclePhotoCell.swift +++ b/AutoCat/Cells/VehiclePhotoCell.swift @@ -1,8 +1,7 @@ import UIKit -import MagazineLayout import Kingfisher -class VehiclePhotoCell: MagazineLayoutCollectionViewCell { +class VehiclePhotoCell: UICollectionViewCell { @IBOutlet weak var photo: UIImageView! @IBOutlet weak var model: UILabel! @IBOutlet weak var date: UILabel! diff --git a/AutoCat/Cells/VehicleTextParamCell.swift b/AutoCat/Cells/VehicleTextParamCell.swift deleted file mode 100644 index 251314d..0000000 --- a/AutoCat/Cells/VehicleTextParamCell.swift +++ /dev/null @@ -1,18 +0,0 @@ -import UIKit -import MagazineLayout - -class VehicleTextParamCell: MagazineLayoutCollectionViewCell { - @IBOutlet weak var paramName: UILabel! - @IBOutlet weak var paramValue: UITextField! - @IBOutlet weak var dividerHeightConstraint: NSLayoutConstraint! - - override func awakeFromNib() { - super.awakeFromNib() - self.dividerHeightConstraint.constant = 1/UIScreen.main.scale - } - - func configure(param: String, value: String) { - self.paramName.text = param - self.paramValue.text = value - } -} diff --git a/AutoCat/Controllers/ReportController.swift b/AutoCat/Controllers/ReportController.swift index 41af00b..58f0768 100644 --- a/AutoCat/Controllers/ReportController.swift +++ b/AutoCat/Controllers/ReportController.swift @@ -1,96 +1,21 @@ import UIKit -import MagazineLayout import Kingfisher import LinkPresentation import RealmSwift +import Eureka -enum ReportSection: Int, CaseIterable, CustomStringConvertible { - case header = 0 - case general = 1 - case identifiers = 2 - case engine = 3 - case photos = 4 - - var description: String { - switch self { - case .header: return "Header" - case .general: return "General" - case .identifiers: return "Identifiers" - case .engine: return "Engine" - case .photos: return "Photos" - } - } -} +class ReportController: FormViewController, MediaBrowserViewControllerDataSource, MediaBrowserViewControllerDelegate, UIActivityItemSource { -enum ReportGeneralSection: Int, CaseIterable, CustomStringConvertible { - case year = 0 - case color = 1 - case category = 2 - case wheelPosition = 3 - case japanese = 4 - case owners = 5 - case events = 6 - - var description: String { - switch self { - case .year: return "Year" - case .color: return "Color" - case .category: return "Category" - case .wheelPosition: return "Steering wheel position" - case .japanese: return "Japanese" - case .owners: return "Owners (from PTS)" - case .events: return "Events" - } - } -} - -enum ReportIdSection: Int, CaseIterable, CustomStringConvertible { - case number = 0 - case vin = 1 - case sts = 2 - case pts = 3 - - var description: String { - switch self { - case .number: return "Number" - case .vin: return "VIN" - case .pts: return "PTS" - case .sts: return "STS" - } - } -} - -enum ReportEngineSection: Int, CaseIterable, CustomStringConvertible { - case number = 0 - case fuelType = 1 - case volume = 2 - case powerHp = 3 - case powerKw = 4 - - var description: String { - switch self { - case .number: return "Number" - case .fuelType: return "Fuel type" - case .volume: return "Volume (cm³)" - case .powerHp: return "Power (HP)" - case .powerKw: return "Power (kw)" - } - } -} - -class ReportController: UIViewController, UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateMagazineLayout, MediaBrowserViewControllerDataSource, MediaBrowserViewControllerDelegate, UIActivityItemSource { - - @IBOutlet weak var collection: UICollectionView! @IBOutlet weak var actionBarItem: UIBarButtonItem! @IBOutlet weak var copyBarItem: UIBarButtonItem! - private let fullWidth = MagazineLayoutItemSizeMode(widthMode: .fullWidth(respectsHorizontalInsets: true), heightMode: .dynamic) private var reportImageUrl: URL? + private let logoPlaceholder = UIImage(named: "SteeringWheel") var vehicle: Vehicle? { didSet { loadViewIfNeeded() - self.collection.reloadData() + self.form.allSections.forEach { $0.reload() } self.navigationController?.setNavigationBarHidden(self.vehicle == nil, animated: false) } } @@ -112,15 +37,91 @@ class ReportController: UIViewController, UICollectionViewDataSource, UICollecti override func viewDidLoad() { super.viewDidLoad() - self.collection.collectionViewLayout = MagazineLayout() - let nib = UINib(nibName: "SectionHeader", bundle: nil) - self.collection.register(nib, forSupplementaryViewOfKind: MagazineLayout.SupplementaryViewKind.sectionHeader, withReuseIdentifier: "SectionHeader") if let vehicle = self.vehicle { let urls = Array(vehicle.photos.compactMap { URL(string: $0.url) }) let prefetcher = ImagePrefetcher(urls: urls) prefetcher.start() } + + form +++ Section() + <<< LabelRow().cellUpdate { cell, _ in + cell.detailTextLabel?.text = self.vehicle?.brand?.name?.original ?? "" + cell.imageView?.kf.setImage(with: URL(string: self.vehicle?.brand?.logo ?? ""), placeholder: self.logoPlaceholder) + } + + let generalSection = Section("General") + form +++ generalSection + <<< LabelRow() { $0.title = "Year" }.cellUpdate { cell, _ in cell.detailTextLabel?.text = String(self.vehicle?.year ?? 0) } + <<< LabelRow() { $0.title = "Color" }.cellUpdate { cell, _ in cell.detailTextLabel?.text = self.vehicle?.color ?? "" } + <<< LabelRow() { $0.title = "Category" }.cellUpdate { cell, _ in cell.detailTextLabel?.text = self.vehicle?.category ?? "" } + <<< LabelRow() { $0.title = "Steering wheel position" }.cellUpdate { cell, _ in cell.detailTextLabel?.text = self.stringFromBool(self.vehicle?.isRightWheel.value, yes: "Right", no: "Left") } + <<< LabelRow() { $0.title = "Japanese" }.cellUpdate { cell, _ in cell.detailTextLabel?.text = self.stringFromBool(self.vehicle?.isJapanese.value, yes: "Yes", no: "No") } + <<< LabelRow() { $0.title = "Events" }.cellUpdate { cell, _ in + cell.detailTextLabel?.text = String(self.vehicle?.events.count ?? 0) + cell.accessoryType = .disclosureIndicator + } + .onCellSelection { _, _ in + let sb = UIStoryboard(name: "Main", bundle: nil) + let controller = sb.instantiateViewController(identifier: "EventsController") as EventsController + controller.vehicle = self.vehicle + self.navigationController?.pushViewController(controller, animated: true) + } + + if self.vehicle?.ownershipPeriods.count ?? 0 > 0 { + generalSection <<< LabelRow() { $0.title = "Owners" }.cellUpdate { cell, _ in + cell.detailTextLabel?.text = String(self.vehicle?.ownershipPeriods.count ?? 0) + cell.accessoryType = .disclosureIndicator + } + .onCellSelection { _, _ in + let sb = UIStoryboard(name: "Main", bundle: nil) + let controller = sb.instantiateViewController(identifier: "OwnersController") as OwnersController + controller.owners = self.vehicle?.ownershipPeriods.toArray() ?? [] + self.navigationController?.pushViewController(controller, animated: true) + } + } + + if self.vehicle?.photos.count ?? 0 > 0 { + generalSection <<< LabelRow() { $0.title = "Photos" }.cellUpdate { cell, _ in + cell.detailTextLabel?.text = String(self.vehicle?.photos.count ?? 0) + cell.accessoryType = .disclosureIndicator + } + .onCellSelection { _, _ in + let mediaBrowser = MediaBrowserViewController(index: 0, dataSource: self, delegate: self) + mediaBrowser.shouldShowTitle = true + mediaBrowser.title = self.vehicle?.photos.first?.description + self.present(mediaBrowser, animated: true, completion: nil) + } + } + + form +++ Section("Identifiers") + <<< LabelRow() { $0.title = "Number" }.cellUpdate { cell, _ in + guard let vehicle = self.vehicle else { + cell.detailTextLabel?.text = "" + return + } + + var num = vehicle.getNumber() + if vehicle.outdated, let current = vehicle.currentNumber { + num = "\(vehicle.getNumber()) (\(current))" + } + cell.detailTextLabel?.text = num + } + <<< LabelRow() { $0.title = "VIN" }.cellUpdate { cell, _ in cell.detailTextLabel?.text = self.vehicle?.vin1 ?? "" } + <<< LabelRow() { $0.title = "STS" }.cellUpdate { cell, _ in cell.detailTextLabel?.text = self.vehicle?.sts ?? "" } + <<< LabelRow() { $0.title = "PTS" }.cellUpdate { cell, _ in cell.detailTextLabel?.text = self.vehicle?.pts ?? "" } + + form +++ Section("Engine") + <<< LabelRow() { $0.title = "Number" }.cellUpdate { cell, _ in cell.detailTextLabel?.text = self.vehicle?.engine?.number ?? "" } + <<< LabelRow() { $0.title = "Fuel type" }.cellUpdate { cell, _ in cell.detailTextLabel?.text = self.vehicle?.engine?.fuelType ?? "" } + <<< LabelRow() { $0.title = "Volume (cm³)" }.cellUpdate { cell, _ in cell.detailTextLabel?.text = String(self.vehicle?.engine?.volume.value ?? 0) } + <<< LabelRow() { $0.title = "Power (HP)" }.cellUpdate { cell, _ in cell.detailTextLabel?.text = String(self.vehicle?.engine?.powerHp ?? 0) } + <<< LabelRow() { $0.title = "Power (kw)" }.cellUpdate { cell, _ in cell.detailTextLabel?.text = String(self.vehicle?.engine?.powerKw.value ?? 0) } + } + + func stringFromBool(_ value: Bool?, yes: String, no: String) -> String { + guard let value = value else { return "" } + return value ? yes : no } override func viewWillAppear(_ animated: Bool) { @@ -136,216 +137,7 @@ class ReportController: UIViewController, UICollectionViewDataSource, UICollecti break } - self.collection.reloadData() - } - - // MARK: - UICollectionViewDataSource - - func numberOfSections(in collectionView: UICollectionView) -> Int { - guard self.vehicle != nil else { return 0 } - return ReportSection.allCases.count - } - - func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { - guard let vehicle = self.vehicle else { return 0 } - guard let section = ReportSection(rawValue: section) else { return 0 } - - switch section { - case .header: return 1 - case .general: return ReportGeneralSection.allCases.count - case .identifiers: return ReportIdSection.allCases.count - case .engine: return ReportEngineSection.allCases.count - case .photos: return vehicle.photos.count - } - } - - func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { - guard let section = ReportSection(rawValue: indexPath.section) else { return UICollectionViewCell() } - guard let vehicle = self.vehicle else { return UICollectionViewCell() } - - switch section { - case .header: - let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "VehicleHeaderCell", for: indexPath) as? VehicleHeaderCell - cell?.configure(with: vehicle) - return cell ?? UICollectionViewCell() - case .general: - let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "VehicleTextParamCell", for: indexPath) as? VehicleTextParamCell - if let generalSection = ReportGeneralSection(rawValue: indexPath.item) { - switch generalSection { - case .year: - cell?.configure(param: generalSection.description, value: String(vehicle.year)) - break - case .color: - cell?.configure(param: generalSection.description, value: vehicle.color ?? "") - break - case .category: - cell?.configure(param: generalSection.description, value: vehicle.category ?? "") - break - case .wheelPosition: - var position = "" - if let rightWheel = vehicle.isRightWheel.value { - position = rightWheel ? "Right" : "Left" - } - cell?.configure(param: generalSection.description, value: position) - break - case .japanese: - var japanese = "" - if let isJapanese = vehicle.isJapanese.value { - japanese = isJapanese ? "Yes" : "No" - } - cell?.configure(param: generalSection.description, value: japanese) - break - case .owners: - cell?.configure(param: generalSection.description, value: String(vehicle.ownershipPeriods.count)) - break - case .events: - cell?.configure(param: generalSection.description, value: String(vehicle.events.count)) - } - } - return cell ?? UICollectionViewCell() - case .identifiers: - let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "VehicleTextParamCell", for: indexPath) as? VehicleTextParamCell - if let idSection = ReportIdSection(rawValue: indexPath.item) { - switch idSection { - case .number: - var num = vehicle.getNumber() - if vehicle.outdated, let current = vehicle.currentNumber { - num = "\(vehicle.getNumber()) (\(current))" - } - cell?.configure(param: idSection.description, value: num) - break - case .vin: - cell?.configure(param: idSection.description, value: vehicle.vin1 ?? "") - break - case .sts: - cell?.configure(param: idSection.description, value: vehicle.sts ?? "") - break - case .pts: - cell?.configure(param: idSection.description, value: vehicle.pts ?? "") - break - } - } - return cell ?? UICollectionViewCell() - case .engine: - let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "VehicleTextParamCell", for: indexPath) as? VehicleTextParamCell - if let engineSection = ReportEngineSection(rawValue: indexPath.item), let engine = vehicle.engine { - switch engineSection { - case .number: - cell?.configure(param: engineSection.description, value: engine.number ?? "") - break - case .fuelType: - cell?.configure(param: engineSection.description, value: engine.fuelType ?? "") - break - case .volume: - cell?.configure(param: engineSection.description, value: String(engine.volume.value ?? 0)) - break - case .powerHp: - cell?.configure(param: engineSection.description, value: String(engine.powerHp)) - break - case .powerKw: - cell?.configure(param: engineSection.description, value: String(engine.powerKw.value ?? 0)) - break - } - } - return cell ?? UICollectionViewCell() - case .photos: - let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "VehiclePhotoCell", for: indexPath) as? VehiclePhotoCell - let photo = vehicle.photos[indexPath.item] - cell?.configure(with: photo) - return cell ?? UICollectionViewCell() - } - } - - func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView - { - guard let section = ReportSection(rawValue: indexPath.section) else { return UICollectionReusableView() } - - if let sectionHeader = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: "SectionHeader", for: indexPath) as? SectionHeader { - sectionHeader.configure(with: section) - return sectionHeader - } - return UICollectionReusableView() - } - - func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { - if indexPath.section == ReportSection.photos.rawValue { - let mediaBrowser = MediaBrowserViewController(index: indexPath.item, dataSource: self, delegate: self) - mediaBrowser.shouldShowTitle = true - mediaBrowser.title = self.vehicle?.photos[indexPath.item].description - present(mediaBrowser, animated: true, completion: nil) - } - - if indexPath.section == ReportSection.general.rawValue { - let sb = UIStoryboard(name: "Main", bundle: nil) - if indexPath.row == ReportGeneralSection.owners.rawValue { - let controller = sb.instantiateViewController(identifier: "OwnersController") as OwnersController - controller.owners = self.vehicle?.ownershipPeriods.toArray() ?? [] - self.navigationController?.pushViewController(controller, animated: true) - } - else if indexPath.row == ReportGeneralSection.events.rawValue { - let controller = sb.instantiateViewController(identifier: "EventsController") as EventsController - controller.vehicle = self.vehicle - self.navigationController?.pushViewController(controller, animated: true) - } - } - } - - // MARK: - UICollectionViewDelegateMagazineLayout - - func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeModeForItemAt indexPath: IndexPath) -> MagazineLayoutItemSizeMode - { - guard let section = ReportSection(rawValue: indexPath.section) else { return self.fullWidth } - switch section { - case .header: return self.fullWidth - case .general: return self.fullWidth - case .identifiers: return self.fullWidth - case .engine: return self.fullWidth - case .photos: - let wMode: MagazineLayoutItemWidthMode = self.traitCollection.horizontalSizeClass != .compact ? .thirdWidth : .halfWidth - return .init(widthMode: wMode, heightMode: .dynamic) - } - } - - func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, visibilityModeForHeaderInSectionAtIndex index: Int) -> MagazineLayoutHeaderVisibilityMode - { - guard let section = ReportSection(rawValue: index) else { return .hidden } - switch section { - case .header: return .hidden - case .general: return .visible(heightMode: .dynamic) - case .identifiers: return .visible(heightMode: .dynamic) - case .engine: return .visible(heightMode: .dynamic) - case .photos: return .visible(heightMode: .dynamic) - } - } - - func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, visibilityModeForFooterInSectionAtIndex index: Int) -> MagazineLayoutFooterVisibilityMode - { - return .hidden - } - - func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, visibilityModeForBackgroundInSectionAtIndex index: Int) -> MagazineLayoutBackgroundVisibilityMode - { - return .hidden - } - - func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, horizontalSpacingForItemsInSectionAtIndex index: Int) -> CGFloat - { - return 16 - } - - func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, verticalSpacingForElementsInSectionAtIndex index: Int) -> CGFloat - { - return index == ReportSection.photos.rawValue ? 16 : 0 - } - - func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetsForSectionAtIndex index: Int) -> UIEdgeInsets - { - return index == ReportSection.photos.rawValue ? UIEdgeInsets(top: 0, left: 0, bottom: 16, right: 0) : .zero - } - - func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetsForItemsInSectionAtIndex index: Int) -> UIEdgeInsets - { - return index == ReportSection.photos.rawValue ? UIEdgeInsets(top: 0, left: 16, bottom: 0, right: 16) : .zero + self.form.allSections.forEach { $0.reload() } } // MARK: - MediaBrowserViewControllerDataSource & MediaBrowserViewControllerDelegate @@ -388,7 +180,7 @@ class ReportController: UIViewController, UICollectionViewDataSource, UICollecti let cancel = UIAlertAction(title: "Cancel", style: .cancel) { _ in sheet.dismiss(animated: true, completion: nil) } let shareImage = UIAlertAction(title: "As one image", style: .default) { _ in - let image = vehicle.reportImage(width: self.collection.contentSize.width) + let image = vehicle.reportImage(width: self.tableView.contentSize.width) do { let fm = FileManager.default diff --git a/AutoCat/Utils/RxRealmDataSource.swift b/AutoCat/Utils/RxRealmDataSource.swift index 248a05f..c0ba6ef 100644 --- a/AutoCat/Utils/RxRealmDataSource.swift +++ b/AutoCat/Utils/RxRealmDataSource.swift @@ -10,6 +10,7 @@ class RealmSectionedDataSource: NSObject, UITableViewDataSource where private var notificationToken: NotificationToken? private var sections: [DateSection] = [] private var cellIdentifier: String + private var lastUpdateTime = Date() init(table: UITableView, data: Results, cellIdentifier: String = String(describing: Cell.self)) { self.tv = table @@ -24,6 +25,12 @@ class RealmSectionedDataSource: NSObject, UITableViewDataSource where self.sections = self.data.groupedByDate() self.tv.reloadData() case .update(_, let deletions, let insertions, let modifications): + if !Calendar.current.isDateInToday(self.lastUpdateTime) { + self.sections = self.data.groupedByDate() + self.tv.reloadData() + return + } + var actions = "Deletions: \(deletions), Insertions: \(insertions), Modifications: \(modifications)" let newSections = self.data.groupedByDate() let changeset = StagedChangeset(source: self.sections, target: newSections, section: 0)