diff --git a/.github/workflows/swiftlint.yml b/.github/workflows/swiftlint.yml index b54caa63..ba5023f4 100644 --- a/.github/workflows/swiftlint.yml +++ b/.github/workflows/swiftlint.yml @@ -9,10 +9,11 @@ on: jobs: SwiftLint: - runs-on: ubuntu-latest + runs-on: macos-latest steps: - uses: actions/checkout@v1 - - name: GitHub Action for SwiftLint - uses: norio-nomura/action-swiftlint@3.1.0 - with: - args: --config Emitron/.swiftlint.yml + - name: Install Swiftlint + run: brew install swiftlint + + - name: Run Swiftlint + run: swiftlint --config Emitron/.swiftlint.yml diff --git a/Emitron/Emitron.xcodeproj/project.pbxproj b/Emitron/Emitron.xcodeproj/project.pbxproj index a4ad81e4..a0ea10e7 100644 --- a/Emitron/Emitron.xcodeproj/project.pbxproj +++ b/Emitron/Emitron.xcodeproj/project.pbxproj @@ -2394,7 +2394,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.0.5; + MARKETING_VERSION = 1.0.6; PRODUCT_BUNDLE_IDENTIFIER = "com.razeware.emitron.ios$(BUNDLE_ID_SUFFIX)"; PRODUCT_MODULE_NAME = Emitron; PRODUCT_NAME = raywenderlich; @@ -2599,7 +2599,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.0.5; + MARKETING_VERSION = 1.0.6; PRODUCT_BUNDLE_IDENTIFIER = "com.razeware.emitron.ios$(BUNDLE_ID_SUFFIX)"; PRODUCT_MODULE_NAME = Emitron; PRODUCT_NAME = raywenderlich; @@ -2625,7 +2625,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.0.5; + MARKETING_VERSION = 1.0.6; PRODUCT_BUNDLE_IDENTIFIER = "com.razeware.emitron.ios$(BUNDLE_ID_SUFFIX)"; PRODUCT_MODULE_NAME = Emitron; PRODUCT_NAME = raywenderlich; diff --git a/Emitron/Emitron/Assets.xcassets/Colours/Text/Contents.json b/Emitron/Emitron/Assets.xcassets/Colours/Text/Contents.json index da4a164c..73c00596 100644 --- a/Emitron/Emitron/Assets.xcassets/Colours/Text/Contents.json +++ b/Emitron/Emitron/Assets.xcassets/Colours/Text/Contents.json @@ -1,6 +1,6 @@ { "info" : { - "version" : 1, - "author" : "xcode" + "author" : "xcode", + "version" : 1 } -} \ No newline at end of file +} diff --git a/Emitron/Emitron/Assets.xcassets/Colours/Text/textButtonTextDisabled.colorset/Contents.json b/Emitron/Emitron/Assets.xcassets/Colours/Text/textButtonTextDisabled.colorset/Contents.json new file mode 100644 index 00000000..d2808066 --- /dev/null +++ b/Emitron/Emitron/Assets.xcassets/Colours/Text/textButtonTextDisabled.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "display-p3", + "components" : { + "alpha" : "1.000", + "blue" : "1.000", + "green" : "1.000", + "red" : "1.000" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "1.000", + "green" : "1.000", + "red" : "1.000" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Emitron/Emitron/Constants.swift b/Emitron/Emitron/Constants.swift index d0f59aaf..ce933268 100644 --- a/Emitron/Emitron/Constants.swift +++ b/Emitron/Emitron/Constants.swift @@ -46,7 +46,7 @@ extension String { static let library = "Library" static let loading = "Loading…" static let myTutorials = "My Tutorials" - static let newest = "Newest" + static let newest = "Newest" static let popularity = "Popularity" static let resetFilters = "Reset Filters" static let search = "Search…" diff --git a/Emitron/Emitron/Downloads/DownloadService.swift b/Emitron/Emitron/Downloads/DownloadService.swift index 00503fbb..5804e607 100644 --- a/Emitron/Emitron/Downloads/DownloadService.swift +++ b/Emitron/Emitron/Downloads/DownloadService.swift @@ -555,7 +555,7 @@ extension DownloadService { extension DownloadService { private func configureWifiObservation() { // Track the network status - networkMonitor.pathUpdateHandler = { [weak self] path in + networkMonitor.pathUpdateHandler = { [weak self] _ in self?.checkQueueStatus() } networkMonitor.start(queue: DispatchQueue.global(qos: .utility)) diff --git a/Emitron/Emitron/Models/ContentSubscriptionPlan.swift b/Emitron/Emitron/Models/ContentSubscriptionPlan.swift index 93b5b073..98bc525c 100644 --- a/Emitron/Emitron/Models/ContentSubscriptionPlan.swift +++ b/Emitron/Emitron/Models/ContentSubscriptionPlan.swift @@ -37,9 +37,9 @@ enum ContentSubscriptionPlan: Int, Codable { var displayString: String { switch self { case .beginner: - return "Beginner" + return "Beginner Subscription" case .professional: - return "Professional" + return "Professional Subscription" } } diff --git a/Emitron/Emitron/Models/SettingsOption.swift b/Emitron/Emitron/Models/SettingsOption.swift index 0e25f86f..9b33941d 100644 --- a/Emitron/Emitron/Models/SettingsOption.swift +++ b/Emitron/Emitron/Models/SettingsOption.swift @@ -84,3 +84,14 @@ enum SettingsOption: Int, Identifiable, CaseIterable { } } } + +// MARK: - Option Selection +extension SettingsOption { + static func getOptions(for canDownload: Bool) -> [SettingsOption] { + if canDownload { + return SettingsOption.allCases + } else { + return [.playbackSpeed, .closedCaptionOn] + } + } +} diff --git a/Emitron/Emitron/Networking/JSONAPI/JSONAPIDocument.swift b/Emitron/Emitron/Networking/JSONAPI/JSONAPIDocument.swift index 2fc24bbf..f97629f4 100644 --- a/Emitron/Emitron/Networking/JSONAPI/JSONAPIDocument.swift +++ b/Emitron/Emitron/Networking/JSONAPI/JSONAPIDocument.swift @@ -33,7 +33,7 @@ class JSONAPIDocument { // MARK: - Properties var meta: [String: Any] = [:] var included: [JSONAPIResource] = [] - var data: [JSONAPIResource] = [] + var data: [JSONAPIResource] = [] var errors: [JSONAPIError] = [] var links: [String: URL] = [:] diff --git a/Emitron/Emitron/Networking/JSONAPI/JSONAPIRelationship.swift b/Emitron/Emitron/Networking/JSONAPI/JSONAPIRelationship.swift index 23a3fa8b..072acedb 100644 --- a/Emitron/Emitron/Networking/JSONAPI/JSONAPIRelationship.swift +++ b/Emitron/Emitron/Networking/JSONAPI/JSONAPIRelationship.swift @@ -32,7 +32,7 @@ import SwiftyJSON public class JSONAPIRelationship { // MARK: - Properties var meta: [String: Any] = [:] - var data: [JSONAPIResource] = [] + var data: [JSONAPIResource] = [] var links: [String: URL] = [:] var type: String = "" diff --git a/Emitron/Emitron/Networking/Requests/Parameters.swift b/Emitron/Emitron/Networking/Requests/Parameters.swift index f18081b6..e68c88ca 100644 --- a/Emitron/Emitron/Networking/Requests/Parameters.swift +++ b/Emitron/Emitron/Networking/Requests/Parameters.swift @@ -206,7 +206,7 @@ enum Param { static func sort(for value: ParameterSortValue, descending: Bool) -> Parameter { - let key = "sort" + let key = "sort" let value = "\(descending ? "-" : "")\(value.rawValue)" return Parameter(key: key, value: value, displayName: "Sort", sortOrdinal: 0) diff --git a/Emitron/Emitron/Sessions/SessionController.swift b/Emitron/Emitron/Sessions/SessionController.swift index 6630d654..6130f0ba 100644 --- a/Emitron/Emitron/Sessions/SessionController.swift +++ b/Emitron/Emitron/Sessions/SessionController.swift @@ -196,7 +196,7 @@ class SessionController: NSObject, UserModelController, ObservablePrePostFactoOb // Update the user self.user = user.with(permissions: permissions) // Ensure guardpost is aware, and hence the keychain is updated - self.guardpost.updateUser(with: user) + self.guardpost.updateUser(with: self.user) } } } diff --git a/Emitron/Emitron/UI/App Root/LoginView.swift b/Emitron/Emitron/UI/App Root/LoginView.swift index 0fe26084..5dcd856e 100644 --- a/Emitron/Emitron/UI/App Root/LoginView.swift +++ b/Emitron/Emitron/UI/App Root/LoginView.swift @@ -41,6 +41,7 @@ struct LoginView: View { PagerView(pageCount: 2, showIndicator: true) { VStack { + Spacer() Image("welcomeArtwork1") .resizable() .aspectRatio(contentMode: .fit) @@ -57,6 +58,7 @@ struct LoginView: View { .font(.uiLabel) .foregroundColor(.contentText) .multilineTextAlignment(.center) + Spacer() } .background(Color.backgroundColor) diff --git a/Emitron/Emitron/UI/Library/Filtering/FiltersHeaderView.swift b/Emitron/Emitron/UI/Library/Filtering/FiltersHeaderView.swift index 3c14f2ea..af576502 100644 --- a/Emitron/Emitron/UI/Library/Filtering/FiltersHeaderView.swift +++ b/Emitron/Emitron/UI/Library/Filtering/FiltersHeaderView.swift @@ -50,13 +50,13 @@ struct FiltersHeaderView: View { isExpanded.toggle() }) { HStack { - Text(filterGroup.type.name) + Text("\(filterGroup.type.name)\(filterCount)") .foregroundColor(.titleText) .font(.uiLabelBold) Spacer() - - Text(isExpanded ? "Hide (\(numOfOnFilters))" : "Show (\(numOfOnFilters))") + + Image(systemName: isExpanded ? "chevron.up" : "chevron.down") .foregroundColor(.contentText) .font(.uiLabelBold) } @@ -72,11 +72,18 @@ struct FiltersHeaderView: View { } } } - + + private var filterCount: String { + if numOfOnFilters > 0 { + return "・\(numOfOnFilters)" + } + return "" + } + private var numOfOnFilters: Int { filterGroup.filters.filter(\.isOn).count } - + private var expandedView: some View { VStack(alignment: .leading, spacing: 8) { ForEach(Array(filterGroup.filters), id: \.self) { filter in diff --git a/Emitron/Emitron/UI/Library/LibraryView.swift b/Emitron/Emitron/UI/Library/LibraryView.swift index 5b796de7..fdada262 100644 --- a/Emitron/Emitron/UI/Library/LibraryView.swift +++ b/Emitron/Emitron/UI/Library/LibraryView.swift @@ -50,7 +50,7 @@ struct LibraryView: View { .background(Color.backgroundColor.edgesIgnoringSafeArea(.all)) } } - + private var contentControlsSection: some View { VStack { searchAndFilterControls @@ -104,12 +104,17 @@ struct LibraryView: View { HStack { Image("sort") .foregroundColor(.textButtonText) - - Text(filters.sortFilter.name) - .font(.uiLabelBold) - .foregroundColor(.textButtonText) + if [.loading, .loadingAdditional].contains(libraryRepository.state) { + Text(filters.sortFilter.name) + .font(.uiLabel) + .foregroundColor(Color.gray) + } else { + Text(filters.sortFilter.name) + .font(.uiLabelBold) + .foregroundColor(.textButtonText) + } } - } + }.disabled([.loading, .loadingAdditional].contains(libraryRepository.state)) } } diff --git a/Emitron/Emitron/UI/Settings/SettingsList.swift b/Emitron/Emitron/UI/Settings/SettingsList.swift index 2a6690e0..98f96180 100644 --- a/Emitron/Emitron/UI/Settings/SettingsList.swift +++ b/Emitron/Emitron/UI/Settings/SettingsList.swift @@ -30,13 +30,14 @@ import SwiftUI struct SettingsList { @ObservedObject private var settingsManager: SettingsManager + private var canDownload: Bool } // MARK: - View extension SettingsList: View { var body: some View { VStack(spacing: 0) { - ForEach(SettingsOption.allCases) { self[$0] } + ForEach(SettingsOption.getOptions(for: canDownload)) { self[$0] } } } } @@ -48,15 +49,16 @@ struct SettingsList_Previews: PreviewProvider { } static var list: some View { - SettingsList( settingsManager: .init(initialValue: .current) ) + SettingsList(settingsManager: .init(initialValue: .current), canDownload: true) .background(Color.backgroundColor) } } // MARK: - internal extension SettingsList { - init(settingsManager: ObservedObject) { + init(settingsManager: ObservedObject, canDownload: Bool) { _settingsManager = settingsManager + self.canDownload = canDownload } } diff --git a/Emitron/Emitron/UI/Settings/SettingsView.swift b/Emitron/Emitron/UI/Settings/SettingsView.swift index 4feff105..8e309b2d 100644 --- a/Emitron/Emitron/UI/Settings/SettingsView.swift +++ b/Emitron/Emitron/UI/Settings/SettingsView.swift @@ -45,7 +45,10 @@ struct SettingsView: View { var body: some View { NavigationView { VStack { - SettingsList(settingsManager: _settingsManager) + SettingsList( + settingsManager: _settingsManager, + canDownload: sessionController.user?.canDownload ?? false + ) .navigationBarTitle(String.settings) .navigationBarItems(trailing: dismissButton) .padding([.horizontal], 20) diff --git a/Emitron/Emitron/UI/Shared/Content List/ContentListView.swift b/Emitron/Emitron/UI/Shared/Content List/ContentListView.swift index b3ea34a1..54cfcbe7 100644 --- a/Emitron/Emitron/UI/Shared/Content List/ContentListView.swift +++ b/Emitron/Emitron/UI/Shared/Content List/ContentListView.swift @@ -93,7 +93,7 @@ private extension ContentListView { cardsView loadMoreView // Hack to make sure there's some spacing at the bottom of the list - Color.clear.frame(height: 0) + Color.backgroundColor } } diff --git a/Emitron/Emitron/UI/Shared/Tags/TagView.swift b/Emitron/Emitron/UI/Shared/Tags/TagView.swift index 1f7e5fdb..0c134652 100644 --- a/Emitron/Emitron/UI/Shared/Tags/TagView.swift +++ b/Emitron/Emitron/UI/Shared/Tags/TagView.swift @@ -29,6 +29,8 @@ import SwiftUI struct TagView: View { + private static let defaultIconHeight: CGFloat = 12.0 + private struct SizeKey: PreferenceKey { static func reduce(value: inout CGSize?, nextValue: () -> CGSize?) { value = value ?? nextValue() @@ -49,7 +51,7 @@ struct TagView: View { .resizable() .aspectRatio(contentMode: .fit) .foregroundColor(textColor) - .frame(height: height) + .frame(height: Self.defaultIconHeight) Text(text.uppercased()) .foregroundColor(textColor) diff --git a/Emitron/emitronScreenshots/SnapshotHelper.swift b/Emitron/emitronScreenshots/SnapshotHelper.swift index baefa99d..0c253881 100644 --- a/Emitron/emitronScreenshots/SnapshotHelper.swift +++ b/Emitron/emitronScreenshots/SnapshotHelper.swift @@ -238,7 +238,7 @@ open class Snapshot: NSObject { private extension XCUIElementAttributes { var isNetworkLoadingIndicator: Bool { - if hasWhiteListedIdentifier { + if hasAllowedIdentifier { return false } @@ -248,10 +248,10 @@ private extension XCUIElementAttributes { return hasOldLoadingIndicatorSize || hasNewLoadingIndicatorSize } - var hasWhiteListedIdentifier: Bool { - let whiteListedIdentifiers = ["GeofenceLocationTrackingOn", "StandardLocationTrackingOn"] + var hasAllowedIdentifier: Bool { + let allowedIdentifiers = ["GeofenceLocationTrackingOn", "StandardLocationTrackingOn"] - return whiteListedIdentifiers.contains(identifier) + return allowedIdentifiers.contains(identifier) } func isStatusBar(_ deviceWidth: CGFloat) -> Bool {