From fa814146bfb2838ab312a6abbde52e003c424d13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20H=C3=BChne?= Date: Fri, 12 Nov 2021 13:28:31 +0100 Subject: [PATCH] [fix/branding refinement] Branding: Color and UI Improvements (#1057) * Fixed branding issues * - fixed default searchBar background and placeholder text color for branded builds - show single account server list, if only one account is configured for branded and unbranded builds * - fixed default (unselected) tab bar color - added table view section border to branded account table view * - fixed rounded border for text fields in branded login UI - removed table row separator in branding login view - fixed colors in contrast mode, if tint color is white - fixed UIAlertView tint color * fixed tint color in UIAlertController in dark mode for branding colors * fixed color value again * fixed tint color in single account server list cell view * fixed missing profile UI * removed optional branding values (only two color values are now needed for a complete branding, all other values are optional) * fixed border color in single account server view, if navigationbar background color is white * added gomplate template for Branding.plist creation to the iOS repo adopted template for new Parameter and removed default values i template * fixed some color issues, if tint color is white * fixed setting custom UISearchBar backgroundColor on iOS 12 * set profile url as prefilled default value into setup url field * added a new color style loginStatusBarStyle to set a custom status bar style for the login view * if the key app.version-number exists, fastlane will use this value as app and extension short version number, which gives the possibility to set custom version numbers * Fixed CR findings: - added a protocol for setting the custom status bar style, instead of using static class names - using the correct SDK method for round rect * fixed merge error --- enterprise/gomplate/Branding.plist.tmpl | 98 +++++++ fastlane/Fastfile | 17 ++ ownCloud/AppDelegate.swift | 10 +- ownCloud/SceneDelegate.swift | 10 +- .../Server List/ServerListBookmarkCell.swift | 8 +- .../ServerListTableViewController.swift | 22 +- .../StaticLoginServerListViewController.swift | 16 +- .../StaticLoginSetupViewController.swift | 11 +- ...ingleAccountServerListViewController.swift | 244 +++++++++++++----- .../StaticLoginStepViewController.swift | 32 ++- .../Interface/StaticLoginViewController.swift | 10 +- .../Static Login/StaticLoginProfile.swift | 4 +- .../AppLock/PasscodeViewController.swift | 8 + ownCloudAppShared/Branding/Branding+App.swift | 19 +- .../UITableViewController+Extension.swift | 49 ++++ .../StaticTableView/StaticTableViewRow.swift | 16 +- .../Theme/NSObject+ThemeApplication.swift | 8 +- .../User Interface/Theme/Theme.swift | 10 +- .../Theme/ThemeCollection.swift | 44 +++- .../Theme/UI/ThemeNavigationController.swift | 12 + .../Theme/UI/ThemeTableViewCell.swift | 2 +- .../Theme/UI/ThemedAlertController.swift | 4 +- 22 files changed, 540 insertions(+), 114 deletions(-) create mode 100644 enterprise/gomplate/Branding.plist.tmpl diff --git a/enterprise/gomplate/Branding.plist.tmpl b/enterprise/gomplate/Branding.plist.tmpl new file mode 100644 index 000000000..a8befa16b --- /dev/null +++ b/enterprise/gomplate/Branding.plist.tmpl @@ -0,0 +1,98 @@ + + +{{- $config := .config }} +{{- $hasThemeDefinitionsStyles := false }} +{{- $hasThemeNavigationColors := false }} +{{- $hasThemeSearchColors := false }} +{{- $hasDarkColor := false }} +{{- $hasLightColor := false }} +{{- $darkColor := "" }} +{{- $lightColor := "" }} +{{- $brandingStyle := "" }} +{{- $brandingNavigationStyle := "" }} + +{{- range $key, $value := $config }} +{{- if eq (printf "%T" $value) ""}} +{{- if strings.HasSuffix "_check" $key }} +{{$value = false }} +{{- else if strings.HasSuffix "_text" $key }} +{{$value = "" }} +{{- end }}{{- end }} +{{- if hasPrefix $key "ios_branding" }} +{{- if $key | strings.Contains "ios_branding.theme-definitions$[0].darkBrandColor_color" }} +{{ $darkColor = $value }} +{{- else if $key | strings.Contains "ios_branding.theme-definitions$[0].lightBrandColor_color" }} +{{ $lightColor = $value }} +{{- else if $key | strings.Contains "ios_branding.style_select" }} +{{ $brandingStyle = $value }} +{{- else if $key | strings.Contains "ios_branding.navigation.style_select" }} +{{ $brandingNavigationStyle = $value }} +{{- else }} +{{ $key | strings.TrimPrefix "ios_" | strings.TrimSuffix "_check" | strings.TrimSuffix "_text" | strings.TrimSuffix "_color" }} +{{- if eq (printf "%T" $value) "string"}} +{{$value}} +{{- else if eq $value true}} + +{{- else if eq $value false}} +{{end}}{{end}}{{end}} +{{- if hasPrefix $key "ios_json_override_longtext"}} +{{- if $value | strings.Contains "branding.theme-definitions" }} +{{- if $value | strings.Contains ".Styles." }} +{{ $hasThemeDefinitionsStyles = true}} +{{end}} +{{- if $value | strings.Contains ".Colors.NavigationBar." }} +{{ $hasThemeNavigationColors = true}} +{{end}} +{{- if $value | strings.Contains ".Colors.Searchbar." }} +{{ $hasThemeSearchColors = true}} +{{end}} +{{end}} +{{- if $value | strings.Contains "branding.theme-definitions$[0].darkBrandColor" }} +{{ $hasDarkColor = true }}{{end}} +{{- if $value | strings.Contains "branding.theme-definitions$[0].lightBrandColor" }} +{{ $hasLightColor = true }}{{end}} +{{$value}}{{end}}{{end}} +{{- if $brandingNavigationStyle | strings.Contains "bright" }} +{{- if eq $hasThemeSearchColors false }} +branding.theme-definitions$[0].Colors.Searchbar.tintColor +#666666 +branding.theme-definitions$[0].Colors.Searchbar.secondaryLabelColor +#666666 +branding.theme-definitions$[0].Colors.Searchbar.backgroundColor +#F2F2F3 +branding.theme-definitions$[0].Colors.Searchbar.labelColor +#000000 +{{end}} +{{- if eq $hasThemeNavigationColors false }} +branding.theme-definitions$[0].Colors.NavigationBar.tintColor +{{$darkColor}} +branding.theme-definitions$[0].Colors.NavigationBar.backgroundColor +#FFFFFF +branding.theme-definitions$[0].Colors.NavigationBar.labelColor +#000000 +{{end}}{{- end }} +{{- if eq $hasThemeDefinitionsStyles false }} +{{- if $brandingStyle | strings.Contains "dark" }} +branding.theme-definitions$[0].Styles.searchBarActivityIndicatorViewStyle +gray +branding.theme-definitions$[0].Styles.statusBarStyle +lightContent +branding.theme-definitions$[0].Styles.backgroundBlurEffectStyle +dark +branding.theme-definitions$[0].Styles.interfaceStyle +dark +branding.theme-definitions$[0].Styles.keyboardAppearance +dark +branding.theme-definitions$[0].Styles.activityIndicatorViewStyle +white +branding.theme-definitions$[0].Styles.barStyle +default +{{- end }}{{end}} +{{- if eq $hasDarkColor false }} +branding.theme-definitions$[0].darkBrandColor +{{$darkColor}}{{end}} +{{- if eq $hasLightColor false }} +branding.theme-definitions$[0].lightBrandColor +{{$lightColor}}{{end}} + + diff --git a/fastlane/Fastfile b/fastlane/Fastfile index 501fd51d1..01a47e959 100644 --- a/fastlane/Fastfile +++ b/fastlane/Fastfile @@ -513,6 +513,20 @@ end set_info_plist_value(path: "ownCloud/Resources/Info.plist", key: "CFBundleDisplayName", value: appName) set_info_plist_value(path: "ownCloud/Resources/Info.plist", key: "CFBundleName", value: appName) + if File.exist?("../" + themePath) + tmpCustomAppVersionNumber = get_info_plist_value(path: themePath, key: "app.version-number") + if tmpCustomAppVersionNumber && !tmpCustomAppVersionNumber.empty? + customAppVersionNumber = tmpCustomAppVersionNumber + + puts "Set Version Number from Branding.plist: " + customAppVersionNumber + set_info_plist_value(path: "ownCloud/Resources/Info.plist", key: "CFBundleShortVersionString", value: customAppVersionNumber) + set_info_plist_value(path: "ownCloud File Provider/Info.plist", key: "CFBundleShortVersionString", value: customAppVersionNumber) + set_info_plist_value(path: "ownCloud File Provider UI/Info.plist", key: "CFBundleShortVersionString", value: customAppVersionNumber) + set_info_plist_value(path: "ownCloud Share Extension/Info.plist", key: "CFBundleShortVersionString", value: customAppVersionNumber) + set_info_plist_value(path: "ownCloud Intents/Info.plist", key: "CFBundleShortVersionString", value: customAppVersionNumber) + end + end + if !values[:BUILD_NUMBER].nil? puts "Set Drone Build Number: " + BUILD_NUMBER set_info_plist_value(path: "ownCloud/Resources/Info.plist", key: "CFBundleVersion", value: BUILD_NUMBER) @@ -715,6 +729,9 @@ end elsif time = Time.now ipaSuffix = EXPORT_METHOD + "-" + time.strftime("%Y%m%d-%k%M") + if !customAppVersionNumber.nil? + version = customAppVersionNumber + end if !values[:BUILD_NUMBER].nil? version += "." + BUILD_NUMBER end diff --git a/ownCloud/AppDelegate.swift b/ownCloud/AppDelegate.swift index f3bd4f29b..ae61b10ac 100644 --- a/ownCloud/AppDelegate.swift +++ b/ownCloud/AppDelegate.swift @@ -55,7 +55,15 @@ class AppDelegate: UIResponder, UIApplicationDelegate { navigationController?.setNavigationBarHidden(true, animated: false) rootViewController = navigationController } else { - serverListTableViewController = ServerListTableViewController(style: .plain) + if OCBookmarkManager.shared.bookmarks.count == 1 { + if #available(iOS 13.0, *) { + serverListTableViewController = StaticLoginSingleAccountServerListViewController(style: .insetGrouped) + } else { + serverListTableViewController = StaticLoginSingleAccountServerListViewController(style: .grouped) + } + } else { + serverListTableViewController = ServerListTableViewController(style: .plain) + } navigationController = ThemeNavigationController(rootViewController: serverListTableViewController!) rootViewController = navigationController diff --git a/ownCloud/SceneDelegate.swift b/ownCloud/SceneDelegate.swift index c514272b5..b420f5bc1 100644 --- a/ownCloud/SceneDelegate.swift +++ b/ownCloud/SceneDelegate.swift @@ -35,7 +35,15 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate { navigationController = ThemeNavigationController(rootViewController: staticLoginViewController) navigationController?.setNavigationBarHidden(true, animated: false) } else { - let serverListTableViewController = ServerListTableViewController(style: .plain) + var serverListTableViewController : ServerListTableViewController? + if OCBookmarkManager.shared.bookmarks.count == 1 { + serverListTableViewController = StaticLoginSingleAccountServerListViewController(style: .insetGrouped) + } else { + serverListTableViewController = ServerListTableViewController(style: .plain) + } + + guard let serverListTableViewController = serverListTableViewController else { return } + serverListTableViewController.restorationIdentifier = "ServerListTableViewController" navigationController = ThemeNavigationController(rootViewController: serverListTableViewController) diff --git a/ownCloud/Server List/ServerListBookmarkCell.swift b/ownCloud/Server List/ServerListBookmarkCell.swift index 923dd4832..f3ed91a7f 100644 --- a/ownCloud/Server List/ServerListBookmarkCell.swift +++ b/ownCloud/Server List/ServerListBookmarkCell.swift @@ -164,7 +164,9 @@ class ServerListBookmarkCell : ThemeTableViewCell { self.titleLabel.applyThemeCollection(collection, itemStyle: .title, itemState: itemState) self.detailLabel.applyThemeCollection(collection, itemStyle: .message, itemState: itemState) - self.iconView.image = self.iconView.image?.tinted(with: collection.tableRowColors.labelColor) + if !VendorServices.shared.isBranded { + self.iconView.image = self.iconView.image?.tinted(with: collection.tableRowColors.labelColor) + } } override func applyThemeCollection(theme: Theme, collection: ThemeCollection, event: ThemeEvent) { @@ -174,6 +176,8 @@ class ServerListBookmarkCell : ThemeTableViewCell { self.titleLabel.applyThemeCollection(collection, itemStyle: .title, itemState: itemState) self.detailLabel.applyThemeCollection(collection, itemStyle: .message, itemState: itemState) - self.iconView.image = self.iconView.image?.tinted(with: collection.tableRowColors.labelColor) + if !VendorServices.shared.isBranded { + self.iconView.image = self.iconView.image?.tinted(with: collection.tableRowColors.labelColor) + } } } diff --git a/ownCloud/Server List/ServerListTableViewController.swift b/ownCloud/Server List/ServerListTableViewController.swift index 9f2c5e367..78e6e5ddb 100644 --- a/ownCloud/Server List/ServerListTableViewController.swift +++ b/ownCloud/Server List/ServerListTableViewController.swift @@ -373,7 +373,7 @@ class ServerListTableViewController: UITableViewController, Themeable, StateRest // MARK: - Actions @IBAction func addBookmark() { - showBookmarkUI() + showBookmarkUI(attemptLoginOnSuccess: true) } func showBookmarkUI(edit bookmark: OCBookmark? = nil, performContinue: Bool = false, attemptLoginOnSuccess: Bool = false, autosolveErrorOnSuccess: NSError? = nil, removeAuthDataFromCopy: Bool = true) { @@ -395,6 +395,7 @@ class ServerListTableViewController: UITableViewController, Themeable, StateRest if attemptLoginOnSuccess { bookmarkViewController.userActionCompletionHandler = { [weak self] (bookmark, success) in if success, let bookmark = bookmark, let self = self { + self.didUpdateServerList() if let error = autosolveErrorOnSuccess as Error? { OCMessageQueue.global.resolveIssues(forError: error, forBookmarkUUID: bookmark.uuid) } @@ -646,6 +647,21 @@ class ServerListTableViewController: UITableViewController, Themeable, StateRest func didUpdateServerList() { // This is a hook for subclasses + + if !VendorServices.shared.isBranded { + if OCBookmarkManager.shared.bookmarks.count == 1 { + var serverListTableViewController : ServerListTableViewController? + if #available(iOS 13.0, *) { + serverListTableViewController = StaticLoginSingleAccountServerListViewController(style: .insetGrouped) + } else { + serverListTableViewController = StaticLoginSingleAccountServerListViewController(style: .grouped) + } + + guard let serverListTableViewController = serverListTableViewController else { return } + + self.navigationController?.setViewControllers([ serverListTableViewController ], animated: false) + } + } } var clientViewController : ClientRootViewController? { @@ -743,6 +759,7 @@ class ServerListTableViewController: UITableViewController, Themeable, StateRest self.tableView.deleteRows(at: [indexPath], with: UITableView.RowAnimation.fade) }, completion: { (_) in self.ignoreServerListChanges = false + self.didUpdateServerList() }) } } @@ -808,7 +825,8 @@ class ServerListTableViewController: UITableViewController, Themeable, StateRest self.tableView.deleteRows(at: [indexPath], with: UITableView.RowAnimation.fade) } }, completion: { (_) in - self.ignoreServerListChanges = false + self.ignoreServerListChanges = false + self.didUpdateServerList() }) } } diff --git a/ownCloud/Static Login/Interface/StaticLoginServerListViewController.swift b/ownCloud/Static Login/Interface/StaticLoginServerListViewController.swift index 1186bedd9..a1b8d07f4 100644 --- a/ownCloud/Static Login/Interface/StaticLoginServerListViewController.swift +++ b/ownCloud/Static Login/Interface/StaticLoginServerListViewController.swift @@ -41,6 +41,12 @@ class StaticLoginServerListViewController: ServerListTableViewController { } } + override func viewDidAppear(_ animated: Bool) { + super.viewDidAppear(animated) + + staticLoginViewController?.navigationController?.setNeedsStatusBarAppearanceUpdate() + } + override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) @@ -79,6 +85,12 @@ class StaticLoginServerListViewController: ServerListTableViewController { return bookmarkCell } + override func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) { + if VendorServices.shared.isBranded { + self.colorSection(tableView, willDisplay: cell, forRowAt: indexPath, borderColor: Theme.shared.activeCollection.navigationBarColors.backgroundColor) + } + } + override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? { if headerView == nil { headerView = StaticTableViewSection.buildHeader(title: "Accounts".localized) @@ -98,9 +110,7 @@ class StaticLoginServerListViewController: ServerListTableViewController { } override func didUpdateServerList() { - if OCBookmarkManager.shared.bookmarks.count == 0 { - self.staticLoginViewController?.showFirstScreen() - } + self.staticLoginViewController?.showFirstScreen() } override func applyThemeCollection(theme: Theme, collection: ThemeCollection, event: ThemeEvent) { diff --git a/ownCloud/Static Login/Interface/StaticLoginSetupViewController.swift b/ownCloud/Static Login/Interface/StaticLoginSetupViewController.swift index 4e28d553d..f91860306 100644 --- a/ownCloud/Static Login/Interface/StaticLoginSetupViewController.swift +++ b/ownCloud/Static Login/Interface/StaticLoginSetupViewController.swift @@ -47,7 +47,10 @@ class StaticLoginSetupViewController : StaticLoginStepViewController { override func viewDidLoad() { super.viewDidLoad() + self.tableView.separatorStyle = .none + if profile.canConfigureURL { + self.urlString = profile.url?.absoluteString self.addSection(urlSection()) if OCBookmarkManager.shared.bookmarks.count == 0, profile.isOnboardingEnabled { self.addSection(onboardingSection()) @@ -121,7 +124,7 @@ class StaticLoginSetupViewController : StaticLoginStepViewController { if let value = row.value as? String { self?.username = value } - }, placeholder: "Username".localized, keyboardType: .asciiCapable, autocorrectionType: .no, autocapitalizationType: .none, returnKeyType: .continue, identifier: "username")) + }, placeholder: "Username".localized, keyboardType: .asciiCapable, autocorrectionType: .no, autocapitalizationType: .none, returnKeyType: .continue, identifier: "username", borderStyle: .roundedRect)) passwordRow = StaticTableViewRow(secureTextFieldWithAction: { [weak self] (row, _, type) in if type == .didBegin, let cell = row.cell, let indexPath = self?.tableView.indexPath(for: cell) { @@ -133,7 +136,7 @@ class StaticLoginSetupViewController : StaticLoginStepViewController { if type == .didReturn, let value = row.value as? String, value.count > 0 { self?.startAuthentication(nil) } - }, placeholder: "Password".localized, keyboardType: .asciiCapable, autocorrectionType: .no, autocapitalizationType: .none, returnKeyType: .continue, identifier: "password") + }, placeholder: "Password".localized, keyboardType: .asciiCapable, autocorrectionType: .no, autocapitalizationType: .none, returnKeyType: .continue, identifier: "password", borderStyle: .roundedRect) if let passwordRow = passwordRow { loginMaskSection.add(row: passwordRow) } @@ -289,7 +292,9 @@ class StaticLoginSetupViewController : StaticLoginStepViewController { guard self.bookmark != nil else { let alertController = ThemedAlertController(title: "Missing Profile URL".localized, message: String(format: "The Profile '%@' does not have a URL configured.\nPlease provide a URL via configuration or MDM.".localized, profile.name ?? ""), preferredStyle: .alert) - alertController.addAction(UIAlertAction(title: "OK".localized, style: .default, handler: nil)) + alertController.addAction(UIAlertAction(title: "OK".localized, style: .default, handler: { _ in + self.popViewController() + })) self.loginViewController?.present(alertController, animated: true, completion: nil) return diff --git a/ownCloud/Static Login/Interface/StaticLoginSingleAccountServerListViewController.swift b/ownCloud/Static Login/Interface/StaticLoginSingleAccountServerListViewController.swift index 3eb5c3cc6..e880a2f11 100644 --- a/ownCloud/Static Login/Interface/StaticLoginSingleAccountServerListViewController.swift +++ b/ownCloud/Static Login/Interface/StaticLoginSingleAccountServerListViewController.swift @@ -20,7 +20,7 @@ import UIKit import ownCloudSDK import ownCloudAppShared -class StaticLoginSingleAccountServerListViewController: ServerListTableViewController { +class StaticLoginSingleAccountServerListViewController: ServerListTableViewController, CustomStatusBarViewControllerProtocol { // Sections in the table view controller private enum SingleAccountSection : Int, CaseIterable { case accessFiles @@ -41,6 +41,7 @@ class StaticLoginSingleAccountServerListViewController: ServerListTableViewContr private enum SettingsRowIndex : Int, CaseIterable { case settings + case addAccount } // Implementation @@ -48,10 +49,24 @@ class StaticLoginSingleAccountServerListViewController: ServerListTableViewContr weak var staticLoginViewController : StaticLoginViewController? var canConfigureURL: Bool = true private var actionRows: [ActionRowIndex] = [.editLogin, .manageStorage, .logout] + private var settingsRows: [SettingsRowIndex] = [.settings] + + var themeApplierToken : ThemeApplierToken? + + deinit { + Theme.shared.unregister(client: self) + + if themeApplierToken != nil { + Theme.shared.remove(applierForToken: themeApplierToken) + themeApplierToken = nil + } + } override func viewDidLoad() { super.viewDidLoad() + Theme.shared.register(client: self, applyImmediately: true) + self.tableView.isScrollEnabled = true self.tableView.register(ThemeTableViewCell.self, forCellReuseIdentifier: "login-cell") self.tableView.register(ServerListToolCell.self, forCellReuseIdentifier: "tool-cell") @@ -59,12 +74,43 @@ class StaticLoginSingleAccountServerListViewController: ServerListTableViewContr if !VendorServices.shared.canEditAccount { actionRows = [.manageStorage, .logout] } + + if VendorServices.shared.canAddAccount { + staticLoginViewController?.toolbarShown = true + settingsRows = [.settings, .addAccount] + } else { + staticLoginViewController?.toolbarShown = false + } } override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) - staticLoginViewController?.toolbarShown = false + if !VendorServices.shared.isBranded, UIDevice.current.isIpad { + // Set a maximum table view width of 400 on iPad + let width = self.view.frame.size.width + let height = self.view.frame.size.height + var margin : CGFloat = 0 + + if width > height { + margin = (height - 400) / 2 + } else { + margin = (width - 400) / 2 + } + + self.tableView.layoutMargins.left = margin + self.tableView.layoutMargins.right = margin + } + } + + override func viewDidAppear(_ animated: Bool) { + super.viewDidAppear(animated) + + staticLoginViewController?.navigationController?.setNeedsStatusBarAppearanceUpdate() + } + + func statusBarStyle() -> UIStatusBarStyle { + return Theme.shared.activeCollection.loginStatusBarStyle } override func numberOfSections(in tableView: UITableView) -> Int { @@ -75,7 +121,7 @@ class StaticLoginSingleAccountServerListViewController: ServerListTableViewContr switch SingleAccountSection(rawValue: section) { case .accessFiles: return AccessFilesRowIndex.allCases.count case .actions: return actionRows.count - case .settings: return SettingsRowIndex.allCases.count + case .settings: return settingsRows.count default: return 0 } @@ -86,61 +132,70 @@ class StaticLoginSingleAccountServerListViewController: ServerListTableViewContr var rowCell : UITableViewCell switch section { - case .accessFiles: - guard let bookmarkCell = self.tableView.dequeueReusableCell(withIdentifier: "login-cell", for: indexPath) as? ThemeTableViewCell else { - return ThemeTableViewCell() - } + case .accessFiles: + guard let bookmarkCell = self.tableView.dequeueReusableCell(withIdentifier: "login-cell", for: indexPath) as? ThemeTableViewCell else { + return ThemeTableViewCell() + } - bookmarkCell.textLabel?.text = "Access Files".localized - bookmarkCell.textLabel?.font = UIFont.preferredFont(forTextStyle: .headline) - if #available(iOS 13.0, *) { - bookmarkCell.imageView?.image = UIImage(systemName: "folder") - } else { - bookmarkCell.imageView?.image = UIImage(named: "folder")?.scaledImageFitting(in: CGSize(width: 28, height: 28)) - } + bookmarkCell.textLabel?.text = "Access Files".localized + bookmarkCell.textLabel?.font = UIFont.preferredFont(forTextStyle: .headline) + if #available(iOS 13.0, *) { + bookmarkCell.imageView?.image = UIImage(systemName: "folder") + } else { + bookmarkCell.imageView?.image = UIImage(named: "folder")?.scaledImageFitting(in: CGSize(width: 28, height: 28)) + } - rowCell = bookmarkCell + themeApplierToken = Theme.shared.add(applier: { (_, themeCollection, _) in + bookmarkCell.imageView?.tintColor = themeCollection.tableRowColors.labelColor + }) - case .actions: - guard let bookmarkCell = self.tableView.dequeueReusableCell(withIdentifier: "tool-cell", for: indexPath) as? ServerListToolCell else { - return ServerListToolCell() - } + rowCell = bookmarkCell - switch actionRows[indexPath.row] { - case .editLogin: - bookmarkCell.textLabel?.text = "Edit Login".localized - - if #available(iOS 13.0, *) { - bookmarkCell.imageView?.image = UIImage(systemName: "square.and.pencil") - } else { - bookmarkCell.imageView?.image = UIImage(named: "square.and.pencil")?.scaledImageFitting(in: CGSize(width: 28, height: 28)) - } - - case .manageStorage: - bookmarkCell.textLabel?.text = "Manage Storage".localized - - if #available(iOS 13.0, *) { - bookmarkCell.imageView?.image = UIImage(systemName: "arrow.3.trianglepath") - } else { - bookmarkCell.imageView?.image = UIImage(named: "arrow.3.trianglepath")?.scaledImageFitting(in: CGSize(width: 28, height: 28)) - } - - case .logout: - bookmarkCell.textLabel?.text = "Log out".localized - - if #available(iOS 13.0, *) { - bookmarkCell.imageView?.image = UIImage(systemName: "power") - } else { - bookmarkCell.imageView?.image = UIImage(named: "power")?.scaledImageFitting(in: CGSize(width: 28, height: 28)) - } - } + case .actions: + guard let bookmarkCell = self.tableView.dequeueReusableCell(withIdentifier: "tool-cell", for: indexPath) as? ServerListToolCell else { + return ServerListToolCell() + } + + switch actionRows[indexPath.row] { + case .editLogin: + bookmarkCell.textLabel?.text = "Edit Login".localized + + if #available(iOS 13.0, *) { + bookmarkCell.imageView?.image = UIImage(systemName: "square.and.pencil") + } else { + bookmarkCell.imageView?.image = UIImage(named: "square.and.pencil")?.scaledImageFitting(in: CGSize(width: 28, height: 28)) + } + + case .manageStorage: + bookmarkCell.textLabel?.text = "Manage Storage".localized + + if #available(iOS 13.0, *) { + bookmarkCell.imageView?.image = UIImage(systemName: "arrow.3.trianglepath") + } else { + bookmarkCell.imageView?.image = UIImage(named: "arrow.3.trianglepath")?.scaledImageFitting(in: CGSize(width: 28, height: 28)) + } - rowCell = bookmarkCell + case .logout: + bookmarkCell.textLabel?.text = "Log out".localized + + if #available(iOS 13.0, *) { + bookmarkCell.imageView?.image = UIImage(systemName: "power") + } else { + bookmarkCell.imageView?.image = UIImage(named: "power")?.scaledImageFitting(in: CGSize(width: 28, height: 28)) + } + } + + rowCell = bookmarkCell + + case .settings: + + guard let bookmarkCell = self.tableView.dequeueReusableCell(withIdentifier: "tool-cell", for: indexPath) as? ServerListToolCell else { + return ServerListToolCell() + } + + switch settingsRows[indexPath.row] { case .settings: - guard let bookmarkCell = self.tableView.dequeueReusableCell(withIdentifier: "tool-cell", for: indexPath) as? ServerListToolCell else { - return ServerListToolCell() - } bookmarkCell.textLabel?.text = "Settings".localized if #available(iOS 13.0, *) { @@ -149,20 +204,45 @@ class StaticLoginSingleAccountServerListViewController: ServerListTableViewContr bookmarkCell.imageView?.image = UIImage(named: "gear")?.scaledImageFitting(in: CGSize(width: 28, height: 28)) } - rowCell = bookmarkCell + case .addAccount: + bookmarkCell.textLabel?.text = "Add Account".localized + if #available(iOS 13.0, *) { + bookmarkCell.imageView?.image = UIImage(systemName: "plus") + } else { + bookmarkCell.imageView?.image = UIImage(named: "round-add-button")?.scaledImageFitting(in: CGSize(width: 28, height: 28)) + } + + } + + rowCell = bookmarkCell - default: - rowCell = ServerListToolCell() + default: + rowCell = ServerListToolCell() } return rowCell } + override func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) { + if VendorServices.shared.isBranded { + var borderColor = Theme.shared.activeCollection.navigationBarColors.backgroundColor + if borderColor == UIColor(hex: 0xFFFFFF) { + borderColor = Theme.shared.activeCollection.navigationBarColors.tintColor + } + + self.colorSection(tableView, willDisplay: cell, forRowAt: indexPath, borderColor: borderColor) + } + } + override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? { if SingleAccountSection(rawValue: section) == .accessFiles { if headerView == nil, let bookmark : OCBookmark = OCBookmarkManager.shared.bookmarks.first, let userName = bookmark.userName { let headerText = String(format: "You are connected as\n%@".localized, userName) - headerView = StaticTableViewSection.buildHeader(title: headerText) + if VendorServices.shared.isBranded { + headerView = StaticTableViewSection.buildHeader(title: headerText) + } else { + headerView = StaticTableViewSection.buildHeader(title: headerText, image: UIImage(named: "branding-login-logo"), topSpacing: 10) + } } return headerView @@ -188,14 +268,19 @@ class StaticLoginSingleAccountServerListViewController: ServerListTableViewContr case .logout: delete(bookmark: bookmark, at: IndexPath(row: 0, section: 0) ) { - self.staticLoginViewController?.showFirstScreen() + self.didUpdateServerList() } } } case .settings: tableView.deselectRow(at: indexPath, animated: true) - settings() + switch settingsRows[indexPath.row] { + case .settings: + settings() + case .addAccount: + addAccount() + } default: break } @@ -211,23 +296,38 @@ class StaticLoginSingleAccountServerListViewController: ServerListTableViewContr } override func didUpdateServerList() { - if OCBookmarkManager.shared.bookmarks.count == 0 { - self.staticLoginViewController?.showFirstScreen() + if VendorServices.shared.isBranded { + if OCBookmarkManager.shared.bookmarks.count == 0 { + self.staticLoginViewController?.showFirstScreen() + } + } else { + if OCBookmarkManager.shared.bookmarks.count != 1 { + let serverListTableViewController = ServerListTableViewController(style: .plain) + self.navigationController?.setViewControllers([serverListTableViewController], animated: false) + } } } override func applyThemeCollection(theme: Theme, collection: ThemeCollection, event: ThemeEvent) { super.applyThemeCollection(theme: theme, collection: collection, event: event) - self.tableView.backgroundColor = .clear + if VendorServices.shared.isBranded { + self.tableView.backgroundColor = .clear + } else { + self.tableView.backgroundColor = collection.navigationBarColors.backgroundColor + } } override func showModal(viewController: UIViewController, completion: (() -> Void)? = nil) { - // Ensure the presenting view controller isn't removed when the presentation ends - if viewController.modalPresentationStyle == .fullScreen { - viewController.modalPresentationStyle = .overFullScreen - } + if let staticLoginViewController = self.staticLoginViewController { + // Ensure the presenting view controller isn't removed when the presentation ends + if viewController.modalPresentationStyle == .fullScreen { + viewController.modalPresentationStyle = .overFullScreen + } - self.staticLoginViewController?.present(viewController, animated: true, completion: completion) + staticLoginViewController.present(viewController, animated: true, completion: completion) + } else { + super.showModal(viewController: viewController, completion: completion) + } } func openBookmark(_ bookmark: OCBookmark, closeHandler: (() -> Void)? = nil) { @@ -243,4 +343,18 @@ class StaticLoginSingleAccountServerListViewController: ServerListTableViewContr self.showModal(viewController: navigationController) } + + @objc func addAccount() { + if VendorServices.shared.isBranded { + if staticLoginViewController?.loginBundle.profiles.count == 1, let profile = staticLoginViewController?.loginBundle.profiles.first { + if let setupViewController = staticLoginViewController?.buildSetupViewController(for: profile) { + self.navigationController?.pushViewController(setupViewController, animated: true) + } + } else if let viewController = staticLoginViewController?.buildProfileSetupSelector(title: "Add account".localized, includeCancelOption: true) { + self.navigationController?.pushViewController(viewController, animated: false) + } + } else { + super.addBookmark() + } + } } diff --git a/ownCloud/Static Login/Interface/StaticLoginStepViewController.swift b/ownCloud/Static Login/Interface/StaticLoginStepViewController.swift index fac5f5a11..7e5486a98 100644 --- a/ownCloud/Static Login/Interface/StaticLoginStepViewController.swift +++ b/ownCloud/Static Login/Interface/StaticLoginStepViewController.swift @@ -67,12 +67,28 @@ class FullWidthHeaderView : ThemeView { } extension StaticTableViewSection { - static func buildHeader(title: String, message: String? = nil, cellSpacing: CGFloat = 20, topSpacing : CGFloat = 30, bottomSpacing : CGFloat = 20 ) -> UIView { + static func buildHeader(title: String, message: String? = nil, image: UIImage? = nil, cellSpacing: CGFloat = 20, topSpacing: CGFloat = 30, bottomSpacing: CGFloat = 20, imageWidth: CGFloat = 100) -> UIView { let horizontalPadding: CGFloat = 0 let headerView = FullWidthHeaderView() headerView.translatesAutoresizingMaskIntoConstraints = false + let imageView = UIImageView() + if let image = image { + imageView.image = image + imageView.translatesAutoresizingMaskIntoConstraints = false + imageView.contentMode = .scaleAspectFit + + headerView.addSubview(imageView) + + NSLayoutConstraint.activate([ + imageView.centerXAnchor.constraint(equalTo: headerView.safeAreaLayoutGuide.centerXAnchor), + imageView.widthAnchor.constraint(equalToConstant: imageWidth), + imageView.heightAnchor.constraint(equalTo: imageView.widthAnchor), + imageView.topAnchor.constraint(equalTo: headerView.safeAreaLayoutGuide.topAnchor, constant: topSpacing) + ]) + } + let titleLabel = UILabel() titleLabel.translatesAutoresizingMaskIntoConstraints = false titleLabel.setContentHuggingPriority(.defaultLow, for: .horizontal) @@ -83,18 +99,28 @@ extension StaticTableViewSection { headerView.addSubview(titleLabel) headerView.addThemeApplier({ (_, collection, _) in - titleLabel.applyThemeCollection(collection, itemStyle: .welcomeTitle) + if VendorServices.shared.isBranded { + titleLabel.applyThemeCollection(collection, itemStyle: .welcomeTitle) + } else { + titleLabel.applyThemeCollection(collection, itemStyle: .logo) + imageView.image = imageView.image?.tinted(with: collection.navigationBarColors.labelColor) + } }) titleLabel.textColor = .red titleLabel.font = UIFont.systemFont(ofSize: UIFont.systemFontSize * 1.5, weight: .bold) + var layoutAnchor = headerView.safeAreaLayoutGuide.topAnchor + if image != nil { + layoutAnchor = imageView.bottomAnchor + } + NSLayoutConstraint.activate([ titleLabel.leftAnchor.constraint(greaterThanOrEqualTo: headerView.safeAreaLayoutGuide.leftAnchor, constant: horizontalPadding), titleLabel.rightAnchor.constraint(lessThanOrEqualTo: headerView.safeAreaLayoutGuide.rightAnchor, constant: -horizontalPadding), titleLabel.centerXAnchor.constraint(equalTo: headerView.safeAreaLayoutGuide.centerXAnchor), - titleLabel.topAnchor.constraint(equalTo: headerView.safeAreaLayoutGuide.topAnchor, constant: topSpacing) + titleLabel.topAnchor.constraint(equalTo: layoutAnchor, constant: topSpacing) ]) if message != nil { diff --git a/ownCloud/Static Login/Interface/StaticLoginViewController.swift b/ownCloud/Static Login/Interface/StaticLoginViewController.swift index 922539ba1..a88762eb7 100644 --- a/ownCloud/Static Login/Interface/StaticLoginViewController.swift +++ b/ownCloud/Static Login/Interface/StaticLoginViewController.swift @@ -21,7 +21,8 @@ import ownCloudSDK import ownCloudApp import ownCloudAppShared -class StaticLoginViewController: UIViewController, Themeable, StateRestorationConnectProtocol { +class StaticLoginViewController: UIViewController, Themeable, StateRestorationConnectProtocol, CustomStatusBarViewControllerProtocol { + private var bookmark: OCBookmark? private var lastVisibleItemId: String? @@ -112,6 +113,10 @@ class StaticLoginViewController: UIViewController, Themeable, StateRestorationCo fatalError("init(coder:) has not been implemented") } + func statusBarStyle() -> UIStatusBarStyle { + return Theme.shared.activeCollection.loginStatusBarStyle + } + override func loadView() { let rootView = UIView() let headerVerticalSpacing : CGFloat = 40 @@ -309,7 +314,8 @@ class StaticLoginViewController: UIViewController, Themeable, StateRestorationCo func buildBookmarkSelector() -> UIViewController { var serverList : ServerListTableViewController? - if OCBookmarkManager.shared.bookmarks.count > 1 || VendorServices.shared.canAddAccount { + if OCBookmarkManager.shared.bookmarks.count > 1 { + //if OCBookmarkManager.shared.bookmarks.count > 1 || VendorServices.shared.canAddAccount { if #available(iOS 13.0, *) { serverList = StaticLoginServerListViewController(style: .insetGrouped) } else { diff --git a/ownCloud/Static Login/StaticLoginProfile.swift b/ownCloud/Static Login/StaticLoginProfile.swift index 6b3cb19d7..bed78fe6d 100644 --- a/ownCloud/Static Login/StaticLoginProfile.swift +++ b/ownCloud/Static Login/StaticLoginProfile.swift @@ -119,9 +119,9 @@ class StaticLoginProfile: NSObject { } else if let promptForHelpURL = profileDict[Key.promptForHelpURL.settingsKey.rawValue] as? String { self.promptForHelpURL = promptForHelpURL } - if let helpURLButtonString = profileDict[Key.helpURLButtonString.rawValue] as? String { + if let helpURLButtonString = profileDict[Key.helpURLButtonString.rawValue] as? String, helpURLButtonString.count > 0 { self.helpURLButtonString = helpURLButtonString - } else if let helpURLButtonString = profileDict[Key.helpURLButtonString.settingsKey.rawValue] as? String { + } else if let helpURLButtonString = profileDict[Key.helpURLButtonString.settingsKey.rawValue] as? String, helpURLButtonString.count > 0 { self.helpURLButtonString = helpURLButtonString } if let welcome = profileDict[Key.welcome.rawValue] as? String, welcome.count > 0 { diff --git a/ownCloudAppShared/AppLock/PasscodeViewController.swift b/ownCloudAppShared/AppLock/PasscodeViewController.swift index 96e5aea22..7fb5ae2b1 100644 --- a/ownCloudAppShared/AppLock/PasscodeViewController.swift +++ b/ownCloudAppShared/AppLock/PasscodeViewController.swift @@ -285,6 +285,14 @@ public class PasscodeViewController: UIViewController, Themeable { // MARK: - Themeing public override var preferredStatusBarStyle : UIStatusBarStyle { + if VendorServices.shared.isBranded { + if #available(iOSApplicationExtension 13.0, *) { + return .darkContent + } else { + return .default + } + } + return Theme.shared.activeCollection.statusBarStyle } diff --git a/ownCloudAppShared/Branding/Branding+App.swift b/ownCloudAppShared/Branding/Branding+App.swift index 92d8b391e..71cc251de 100644 --- a/ownCloudAppShared/Branding/Branding+App.swift +++ b/ownCloudAppShared/Branding/Branding+App.swift @@ -253,14 +253,15 @@ extension Branding { extension Branding { func generateThemeStyle(from theme: [String : Any], generic: [String : Any]) -> ThemeStyle? { - if let identifier = theme["Identifier"] as? String, - let name = theme["Name"] as? String, - let style = theme["ThemeStyle"] as? String, - let themeStyle = ThemeCollectionStyle(rawValue: style), - let colors = theme["Colors"] as? NSDictionary, + let style = theme["ThemeStyle"] as? String ?? "contrast" + let identifier = theme["Identifier"] as? String ?? "com.owncloud.branding" + let name = theme["Name"] as? String ?? "ownCloud-branding-theme" + + if let themeStyle = ThemeCollectionStyle(rawValue: style), let darkBrandColor = theme["darkBrandColor"] as? String, - let lightBrandColor = theme["lightBrandColor"] as? String, - let styles = theme["Styles"] as? NSDictionary { + let lightBrandColor = theme["lightBrandColor"] as? String { + let colors = theme["Colors"] as? NSDictionary + let styles = theme["Styles"] as? NSDictionary return ThemeStyle(styleIdentifier: identifier, localizedName: name.localized, lightColor: lightBrandColor.colorFromHex ?? UIColor.red, darkColor: darkBrandColor.colorFromHex ?? UIColor.blue, themeStyle: themeStyle, customizedColorsByPath: nil, customColors: colors, genericColors: generic as NSDictionary?, interfaceStyles: styles) } @@ -270,8 +271,8 @@ extension Branding { public func setupThemeStyles() -> Bool { var extractedThemeStyles : [ThemeStyle] = [] - if let generic = self.computedValue(forClassSettingsKey: .themeGenericColors) as? [String : Any], - let themeStyleDefinitions = self.computedValue(forClassSettingsKey: .themeDefinitions) as? [[String : Any]] { + if let themeStyleDefinitions = self.computedValue(forClassSettingsKey: .themeDefinitions) as? [[String : Any]] { + let generic = self.computedValue(forClassSettingsKey: .themeGenericColors) as? [String : Any] ?? [:] for themeStyleDefinition in themeStyleDefinitions { if let themeStyle = self.generateThemeStyle(from: themeStyleDefinition, generic: generic) { extractedThemeStyles.append(themeStyle) diff --git a/ownCloudAppShared/UIKit Extension/UITableViewController+Extension.swift b/ownCloudAppShared/UIKit Extension/UITableViewController+Extension.swift index 7b83dbb55..eb236353d 100644 --- a/ownCloudAppShared/UIKit Extension/UITableViewController+Extension.swift +++ b/ownCloudAppShared/UIKit Extension/UITableViewController+Extension.swift @@ -19,6 +19,7 @@ import UIKit public extension UITableViewController { + func addThemableBackgroundView() { // UITableView background view is nil for default. Set a UIView with clear color to can insert a subview above let backgroundView = UIView.init(frame: self.tableView.frame) @@ -38,4 +39,52 @@ public extension UITableViewController { coloredView.heightAnchor.constraint(equalToConstant: self.view.frame.size.height + 1) ]) } + + func colorSection(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath, borderColor: UIColor?) { + let cornerRadius: CGFloat = 10.0 + let layer: CAShapeLayer = CAShapeLayer() + let pathRef: CGMutablePath = CGMutablePath() + + let bounds: CGRect = cell.bounds.insetBy(dx: 0, dy: 0) + + if indexPath.row == 0 && indexPath.row == tableView.numberOfRows(inSection: indexPath.section) - 1 { + pathRef.addRoundedRect(in: bounds, cornerWidth: cornerRadius, cornerHeight: cornerRadius, transform: .identity) + } else if indexPath.row == 0 { + pathRef.move(to: CGPoint(x: bounds.minX, y: bounds.maxY)) + pathRef.addArc(tangent1End: CGPoint(x: bounds.minX, y: bounds.minY), + tangent2End: CGPoint(x: bounds.midX, y: bounds.minY), + radius: cornerRadius) + + pathRef.addArc(tangent1End: CGPoint(x: bounds.maxX, y: bounds.minY), + tangent2End: CGPoint(x: bounds.maxX, y: bounds.midY), + radius: cornerRadius) + pathRef.addLine(to: CGPoint(x: bounds.maxX, y: bounds.maxY)) + } else if indexPath.row == tableView.numberOfRows(inSection: indexPath.section) - 1 { + pathRef.move(to: CGPoint(x: bounds.minX, y: bounds.minY)) + pathRef.addArc(tangent1End: CGPoint(x: bounds.minX, y: bounds.maxY), + tangent2End: CGPoint(x: bounds.midX, y: bounds.maxY), + radius: cornerRadius) + + pathRef.addArc(tangent1End: CGPoint(x: bounds.maxX, y: bounds.maxY), + tangent2End: CGPoint(x: bounds.maxX, y: bounds.midY), + radius: cornerRadius) + pathRef.addLine(to: CGPoint(x: bounds.maxX, y: bounds.minY)) + } else { + pathRef.move(to: CGPoint(x: bounds.minX, y: bounds.minY)) + pathRef.addLine(to: CGPoint(x: bounds.minX, y: bounds.maxY)) + + pathRef.move(to: CGPoint(x: bounds.maxX, y: bounds.maxY)) + pathRef.addLine(to: CGPoint(x: bounds.maxX, y: bounds.minY)) + } + + layer.path = pathRef + layer.strokeColor = borderColor?.cgColor ?? UIColor.lightGray.cgColor + layer.lineWidth = 1.0 + layer.fillColor = UIColor.clear.cgColor + + let backgroundView: UIView = UIView(frame: bounds) + backgroundView.layer.insertSublayer(layer, at: 0) + backgroundView.backgroundColor = .clear + cell.backgroundView = backgroundView + } } diff --git a/ownCloudAppShared/User Interface/StaticTableView/StaticTableViewRow.swift b/ownCloudAppShared/User Interface/StaticTableView/StaticTableViewRow.swift index 7d1290ff8..cab42eb1e 100644 --- a/ownCloudAppShared/User Interface/StaticTableView/StaticTableViewRow.swift +++ b/ownCloudAppShared/User Interface/StaticTableView/StaticTableViewRow.swift @@ -196,7 +196,7 @@ open class StaticTableViewRow : NSObject, UITextFieldDelegate { themeApplierToken = Theme.shared.add(applier: { [weak self] (_, themeCollection, _) in var textColor, selectedTextColor, backgroundColor, selectedBackgroundColor : UIColor? - textColor = themeCollection.tintColor + textColor = themeCollection.tableRowColors.labelColor backgroundColor = themeCollection.tableRowColors.backgroundColor self?.cell?.textLabel?.textColor = textColor @@ -297,7 +297,7 @@ open class StaticTableViewRow : NSObject, UITextFieldDelegate { if withButtonStyle { themeApplierToken = Theme.shared.add(applier: { [weak self] (_, themeCollection, _) in - let textColor = themeCollection.tintColor + let textColor = themeCollection.tableRowColors.labelColor self?.cell?.textLabel?.textColor = textColor self?.cell?.detailTextLabel?.textColor = textColor @@ -403,7 +403,7 @@ open class StaticTableViewRow : NSObject, UITextFieldDelegate { // MARK: - Text Field public var textField : UITextField? - convenience public init(textFieldWithAction action: StaticTableViewRowTextAction?, placeholder placeholderString: String = "", value textValue: String = "", secureTextEntry : Bool = false, keyboardType: UIKeyboardType = .default, autocorrectionType: UITextAutocorrectionType = .default, autocapitalizationType: UITextAutocapitalizationType = UITextAutocapitalizationType.none, enablesReturnKeyAutomatically: Bool = true, returnKeyType : UIReturnKeyType = .default, inputAccessoryView : UIView? = nil, identifier : String? = nil, accessibilityLabel: String? = nil, actionEvent: UIControl.Event = .editingChanged, clearButtonMode : UITextField.ViewMode = .never ) { + convenience public init(textFieldWithAction action: StaticTableViewRowTextAction?, placeholder placeholderString: String = "", value textValue: String = "", secureTextEntry : Bool = false, keyboardType: UIKeyboardType = .default, autocorrectionType: UITextAutocorrectionType = .default, autocapitalizationType: UITextAutocapitalizationType = UITextAutocapitalizationType.none, enablesReturnKeyAutomatically: Bool = true, returnKeyType : UIReturnKeyType = .default, inputAccessoryView : UIView? = nil, identifier : String? = nil, accessibilityLabel: String? = nil, actionEvent: UIControl.Event = .editingChanged, clearButtonMode : UITextField.ViewMode = .never, borderStyle: UITextField.BorderStyle = .none) { self.init() if secureTextEntry { @@ -436,6 +436,7 @@ open class StaticTableViewRow : NSObject, UITextFieldDelegate { cellTextField.text = textValue cellTextField.accessibilityIdentifier = identifier cellTextField.clearButtonMode = clearButtonMode + cellTextField.borderStyle = borderStyle cellTextField.addTarget(self, action: #selector(textFieldContentChanged(_:)), for: actionEvent) @@ -467,7 +468,7 @@ open class StaticTableViewRow : NSObject, UITextFieldDelegate { cellTextField.accessibilityLabel = accessibilityLabel } - convenience public init(secureTextFieldWithAction action: StaticTableViewRowTextAction?, placeholder placeholderString: String = "", value textValue: String = "", keyboardType: UIKeyboardType = UIKeyboardType.default, autocorrectionType: UITextAutocorrectionType = UITextAutocorrectionType.default, autocapitalizationType: UITextAutocapitalizationType = UITextAutocapitalizationType.none, enablesReturnKeyAutomatically: Bool = true, returnKeyType : UIReturnKeyType = UIReturnKeyType.default, inputAccessoryView : UIView? = nil, identifier : String? = nil, accessibilityLabel: String? = nil, actionEvent: UIControl.Event = UIControl.Event.editingChanged) { + convenience public init(secureTextFieldWithAction action: StaticTableViewRowTextAction?, placeholder placeholderString: String = "", value textValue: String = "", keyboardType: UIKeyboardType = UIKeyboardType.default, autocorrectionType: UITextAutocorrectionType = UITextAutocorrectionType.default, autocapitalizationType: UITextAutocapitalizationType = UITextAutocapitalizationType.none, enablesReturnKeyAutomatically: Bool = true, returnKeyType : UIReturnKeyType = UIReturnKeyType.default, inputAccessoryView : UIView? = nil, identifier : String? = nil, accessibilityLabel: String? = nil, actionEvent: UIControl.Event = UIControl.Event.editingChanged, borderStyle: UITextField.BorderStyle = .none) { self.init( textFieldWithAction: action, placeholder: placeholderString, value: textValue, secureTextEntry: true, @@ -479,7 +480,8 @@ open class StaticTableViewRow : NSObject, UITextFieldDelegate { inputAccessoryView: inputAccessoryView, identifier : identifier, accessibilityLabel: accessibilityLabel, - actionEvent: actionEvent) + actionEvent: actionEvent, + borderStyle: borderStyle) } @objc func textFieldContentChanged(_ sender: UITextField) { @@ -603,7 +605,7 @@ open class StaticTableViewRow : NSObject, UITextFieldDelegate { switch style { case .plain: - textColor = themeCollection.tintColor + textColor = themeCollection.tableRowColors.tintColor tintColor = textColor backgroundColor = themeCollection.tableRowColors.backgroundColor @@ -758,7 +760,7 @@ open class StaticTableViewRow : NSObject, UITextFieldDelegate { switch style { case .plain: - textColor = themeCollection.tintColor + textColor = themeCollection.tableRowColors.labelColor backgroundColor = themeCollection.tableRowColors.backgroundColor case .plainNonOpaque: diff --git a/ownCloudAppShared/User Interface/Theme/NSObject+ThemeApplication.swift b/ownCloudAppShared/User Interface/Theme/NSObject+ThemeApplication.swift index 11244ba97..f7d510802 100644 --- a/ownCloudAppShared/User Interface/Theme/NSObject+ThemeApplication.swift +++ b/ownCloudAppShared/User Interface/Theme/NSObject+ThemeApplication.swift @@ -170,6 +170,12 @@ public extension NSObject { clearButton.setImage(UIImage(systemName: "xmark.circle.fill"), for: .normal) clearButton.tintColor = collection.searchBarColors.secondaryLabelColor } + } else { + if let textField = searchBar.subviews.first?.subviews.last as? UITextField, let backgroundview = textField.subviews.first { + backgroundview.backgroundColor = collection.searchBarColors.backgroundColor + backgroundview.layer.cornerRadius = 10 + backgroundview.clipsToBounds = true + } } } @@ -233,7 +239,7 @@ public extension NSObject { if let cell = self as? UITableViewCell { cell.backgroundColor = collection.tableRowColors.backgroundColor - cell.tintColor = collection.tintColor + cell.tintColor = collection.tableRowColors.labelColor if cell.selectionStyle != .none { if collection.tableRowHighlightColors.backgroundColor != nil { diff --git a/ownCloudAppShared/User Interface/Theme/Theme.swift b/ownCloudAppShared/User Interface/Theme/Theme.swift index dd2524a5e..3cc15f861 100644 --- a/ownCloudAppShared/User Interface/Theme/Theme.swift +++ b/ownCloudAppShared/User Interface/Theme/Theme.swift @@ -236,7 +236,15 @@ public class Theme: NSObject { UITextField.appearance(whenContainedInInstancesOf: [UISearchBar.self]).tintColor = collection.searchBarColors.tintColor } UITextField.appearance(whenContainedInInstancesOf: [UISearchBar.self]).keyboardAppearance = collection.keyboardAppearance - UIView.appearance(whenContainedInInstancesOf: [UIAlertController.self]).tintColor = collection.tintColor + if #available(iOS 13, *) { + if ThemeStyle.preferredStyle.themeStyle == .dark { + UIView.appearance(whenContainedInInstancesOf: [UIAlertController.self]).tintColor = .lightGray + } else { + UIView.appearance(whenContainedInInstancesOf: [UIAlertController.self]).tintColor = .black + } + } else { + UIView.appearance(whenContainedInInstancesOf: [UIAlertController.self]).tintColor = .black + } UITextField.appearance().tintColor = collection.searchBarColors.tintColor } } diff --git a/ownCloudAppShared/User Interface/Theme/ThemeCollection.swift b/ownCloudAppShared/User Interface/Theme/ThemeCollection.swift index c5c9569f2..58e5bf405 100644 --- a/ownCloudAppShared/User Interface/Theme/ThemeCollection.swift +++ b/ownCloudAppShared/User Interface/Theme/ThemeCollection.swift @@ -138,6 +138,7 @@ public class ThemeCollection : NSObject { @objc public var navigationBarColors : ThemeColorCollection @objc public var toolbarColors : ThemeColorCollection @objc public var statusBarStyle : UIStatusBarStyle + @objc public var loginStatusBarStyle : UIStatusBarStyle @objc public var barStyle : UIBarStyle // MARK: - SearchBar @@ -243,10 +244,15 @@ public class ThemeCollection : NSObject { let rowColor : UIColor? = UIColor.black.withAlphaComponent(0.1) self.tableRowBorderColor = colors.resolveColor("Table.tableRowBorderColor", rowColor) + var defaultTableRowLabelColor = darkColor + if VendorServices.shared.isBranded { + defaultTableRowLabelColor = UIColor(hex: 0x000000) + } + self.tableRowColors = colors.resolveThemeColorCollection("Table.tableRowColors", ThemeColorCollection( backgroundColor: tableBackgroundColor, tintColor: nil, - labelColor: darkColor, + labelColor: defaultTableRowLabelColor, secondaryLabelColor: UIColor(hex: 0x475770), symbolColor: UIColor(hex: 0x475770), filledColorPairCollection: ThemeColorPairCollection(fromPair: ThemeColorPair(foreground: UIColor.white, background: lightBrandColor)) @@ -304,7 +310,8 @@ public class ThemeCollection : NSObject { )) // Bar styles - self.statusBarStyle = styleResolver.resolveStatusBarStyle(fallback: .lightContent) + self.statusBarStyle = styleResolver.resolveStatusBarStyle(for: "statusBarStyle", fallback: .lightContent) + self.loginStatusBarStyle = styleResolver.resolveStatusBarStyle(for: "loginStatusBarStyle", fallback: self.statusBarStyle) self.barStyle = styleResolver.resolveBarStyle(fallback: .black) // Progress @@ -340,10 +347,11 @@ public class ThemeCollection : NSObject { // Bar styles if #available(iOS 13, *) { - self.statusBarStyle = styleResolver.resolveStatusBarStyle(fallback: .darkContent) + self.statusBarStyle = styleResolver.resolveStatusBarStyle(for: "statusBarStyle", fallback: .darkContent) } else { - self.statusBarStyle = styleResolver.resolveStatusBarStyle(fallback: .default) + self.statusBarStyle = styleResolver.resolveStatusBarStyle(for: "statusBarStyle", fallback: .default) } + self.loginStatusBarStyle = styleResolver.resolveStatusBarStyle(for: "loginStatusBarStyle", fallback: self.statusBarStyle) self.barStyle = styleResolver.resolveBarStyle(fallback: .default) // Progress @@ -366,13 +374,26 @@ public class ThemeCollection : NSObject { // Bars self.navigationBarColors = colors.resolveThemeColorCollection("NavigationBar", self.darkBrandColors) let tmpDarkBrandColors = self.darkBrandColors - tmpDarkBrandColors.secondaryLabelColor = .lightGray + tmpDarkBrandColors.secondaryLabelColor = UIColor(hex: 0xF7F7F7) + if self.tintColor == UIColor(hex: 0xFFFFFF) { + tmpDarkBrandColors.secondaryLabelColor = .lightGray + } self.toolbarColors = colors.resolveThemeColorCollection("Toolbar", tmpDarkBrandColors) - self.searchBarColors = colors.resolveThemeColorCollection("Searchbar", self.darkBrandColors) + + let defaultSearchBarColor = self.darkBrandColors + if VendorServices.shared.isBranded { + defaultSearchBarColor.labelColor = UIColor(hex: 0x000000) + defaultSearchBarColor.secondaryLabelColor = UIColor.gray + defaultSearchBarColor.backgroundColor = UIColor(hex: 0xF7F7F7) + } + + self.searchBarColors = colors.resolveThemeColorCollection("Searchbar", defaultSearchBarColor) + self.loginColors = colors.resolveThemeColorCollection("Login", self.darkBrandColors) // Bar styles - self.statusBarStyle = styleResolver.resolveStatusBarStyle(fallback: .lightContent) + self.statusBarStyle = styleResolver.resolveStatusBarStyle(for: "statusBarStyle", fallback: .lightContent) + self.loginStatusBarStyle = styleResolver.resolveStatusBarStyle(for: "loginStatusBarStyle", fallback: self.statusBarStyle) self.barStyle = styleResolver.resolveBarStyle(fallback: .black) // Progress @@ -384,6 +405,11 @@ public class ThemeCollection : NSObject { // Logo fill color logoFillColor = UIColor.lightGray + + if lightBrandColor.isEqual(UIColor(hex: 0xFFFFFF)) { + self.neutralColors.normal.background = self.darkBrandColor + self.lightBrandColors.filledColorPairCollection.normal.background = self.darkBrandColor + } } self.informalColors = colors.resolveThemeColorCollection("Informal", self.lightBrandColors) @@ -413,8 +439,8 @@ class ThemeStyleValueResolver : NSObject { styles = styleValues } - func resolveStatusBarStyle(fallback: UIStatusBarStyle) -> UIStatusBarStyle { - if let styleValue = styles?.value(forKeyPath: "statusBarStyle") as? String { + func resolveStatusBarStyle(for key: String, fallback: UIStatusBarStyle) -> UIStatusBarStyle { + if let styleValue = styles?.value(forKeyPath: key) as? String { switch styleValue { case "default": return .default diff --git a/ownCloudAppShared/User Interface/Theme/UI/ThemeNavigationController.swift b/ownCloudAppShared/User Interface/Theme/UI/ThemeNavigationController.swift index 5bf5bac65..aaa129251 100644 --- a/ownCloudAppShared/User Interface/Theme/UI/ThemeNavigationController.swift +++ b/ownCloudAppShared/User Interface/Theme/UI/ThemeNavigationController.swift @@ -18,10 +18,22 @@ import UIKit +public protocol CustomStatusBarViewControllerProtocol : class { + func statusBarStyle() -> UIStatusBarStyle +} + open class ThemeNavigationController: UINavigationController { private var themeToken : ThemeApplierToken? override open var preferredStatusBarStyle : UIStatusBarStyle { + if let object = self.viewControllers.last { + if self.presentedViewController == nil, let loginViewController = object as? CustomStatusBarViewControllerProtocol { + return loginViewController.statusBarStyle() + } else { + return Theme.shared.activeCollection.statusBarStyle + } + } + return Theme.shared.activeCollection.statusBarStyle } diff --git a/ownCloudAppShared/User Interface/Theme/UI/ThemeTableViewCell.swift b/ownCloudAppShared/User Interface/Theme/UI/ThemeTableViewCell.swift index 307813f21..12e8a8831 100644 --- a/ownCloudAppShared/User Interface/Theme/UI/ThemeTableViewCell.swift +++ b/ownCloudAppShared/User Interface/Theme/UI/ThemeTableViewCell.swift @@ -138,7 +138,7 @@ open class ThemeTableViewCell: UITableViewCell, Themeable { switch messageStyle { case .plain: - textColor = collection.tintColor + textColor = collection.tableRowColors.labelColor backgroundColor = collection.tableRowColors.backgroundColor case .text: diff --git a/ownCloudAppShared/User Interface/Theme/UI/ThemedAlertController.swift b/ownCloudAppShared/User Interface/Theme/UI/ThemedAlertController.swift index 3f6124716..0e1752c30 100644 --- a/ownCloudAppShared/User Interface/Theme/UI/ThemedAlertController.swift +++ b/ownCloudAppShared/User Interface/Theme/UI/ThemedAlertController.swift @@ -27,7 +27,7 @@ public class ThemedAlertController: UIAlertController, Themeable { if #available(iOSApplicationExtension 13.0, *) { self.overrideUserInterfaceStyle = Theme.shared.activeCollection.interfaceStyle.userInterfaceStyle } - view.tintColor = Theme.shared.activeCollection.navigationBarColors.tintColor + view.tintColor = Theme.shared.activeCollection.tableRowColors.labelColor } override open func viewWillAppear(_ animated: Bool) { @@ -39,7 +39,7 @@ public class ThemedAlertController: UIAlertController, Themeable { if #available(iOS 13, *) { self.overrideUserInterfaceStyle = collection.interfaceStyle.userInterfaceStyle } - view.tintColor = collection.navigationBarColors.tintColor + view.tintColor = collection.tableRowColors.labelColor } deinit {