diff --git a/Core/Core/View/Base/FlexibleKeyboardInputView.swift b/Core/Core/View/Base/FlexibleKeyboardInputView.swift index ce167c986..83360f42c 100644 --- a/Core/Core/View/Base/FlexibleKeyboardInputView.swift +++ b/Core/Core/View/Base/FlexibleKeyboardInputView.swift @@ -88,6 +88,7 @@ public struct FlexibleKeyboardInputView: View { }.frame(maxWidth: .infinity, maxHeight: commentSize + 16) .background( CoreAssets.commentCellBackground.swiftUIColor + .ignoresSafeArea() ) .overlay( GeometryReader { proxy in diff --git a/Core/Core/View/Base/PickerMenu.swift b/Core/Core/View/Base/PickerMenu.swift index ea0a78ce5..14da74cdd 100644 --- a/Core/Core/View/Base/PickerMenu.swift +++ b/Core/Core/View/Base/PickerMenu.swift @@ -42,68 +42,103 @@ public struct PickerMenu: View { self.items = items self.titleText = titleText self.router = router - if let selectedItem { - self._selectedItem = State(initialValue: selectedItem) - } + self._selectedItem = State(initialValue: selectedItem ?? items.first ?? PickerItem(key: "", value: "")) self.selected = selected } - + + private var filteredItems: [PickerItem] { + if search.isEmpty { + return items + } else { + return items.filter { $0.value.localizedCaseInsensitiveContains(search) } + } + } + + private var isSingleSelection: Bool { + return filteredItems.count == 1 + } + + private var isItemSelected: Bool { + return filteredItems.contains(selectedItem) + } + + private var acceptButtonDisabled: Bool { + return !isItemSelected && !isSingleSelection + } + public var body: some View { VStack { ZStack(alignment: .bottom) { - Color.black.opacity(0.4) - .onTapGesture(perform: { - router.dismiss(animated: true) - }) + Color.black.opacity(0.4) + .ignoresSafeArea() + .onTapGesture { + router.dismiss(animated: true) + } + VStack { + Spacer() VStack { - VStack { - Text(titleText) - .foregroundColor(CoreAssets.textPrimary.swiftUIColor) - TextField(CoreLocalization.Picker.search, text: $search) - .padding(.all, 8) - .background( - CoreAssets.textInputStroke.swiftUIColor - .cornerRadius(6)) - Picker("", selection: $selectedItem) { - let filteredItems = items - .filter({ $0.value.contains(search) }) - ForEach(filteredItems.count != 0 ? filteredItems : items, - id: \.self) { - Text($0.value) - .foregroundColor(CoreAssets.textPrimary.swiftUIColor) - } - }.pickerStyle(.wheel) - - }.frame(minWidth: 0, maxWidth: idiom == .pad ? ipadPickerWidth : .infinity) - .padding() - .background( - CoreAssets.textInputBackground.swiftUIColor - .cornerRadius(16) - ).padding(.horizontal, 16) - - Button(action: { - if items - .filter({ $0.value.contains(search) }).count == 1 { - selectedItem = items - .filter({ $0.value.contains(search) })[0] + Text(titleText) + .foregroundColor(CoreAssets.textPrimary.swiftUIColor) + TextField(CoreLocalization.Picker.search, text: $search) + .padding(.all, 8) + .background(CoreAssets.textInputStroke.swiftUIColor.cornerRadius(6)) + Picker("", selection: $selectedItem) { + ForEach(filteredItems, id: \.self) { item in + Text(item.value) + .foregroundColor(CoreAssets.textPrimary.swiftUIColor) } - selected(selectedItem) - router.dismiss(animated: true) - }, label: { - Text(CoreLocalization.Picker.accept) - .foregroundColor(CoreAssets.textPrimary.swiftUIColor) - .frame(minWidth: 0, maxWidth: idiom == .pad ? ipadPickerWidth : .infinity) - .padding() - .background( - CoreAssets.textInputBackground.swiftUIColor - .cornerRadius(16) - ).padding(.horizontal, 16) - }) - .padding(.bottom, 50) - - }.transition(.move(edge: .bottom)) + } + .pickerStyle(.wheel) + } + .frame(minWidth: 0, maxWidth: idiom == .pad ? ipadPickerWidth : .infinity) + .padding() + .background(CoreAssets.textInputBackground.swiftUIColor.cornerRadius(16)) + .padding(.horizontal, 16) + .onChange(of: search, perform: { _ in + if let first = filteredItems.first { + self.selectedItem = first + } + }) + + Button(action: { + selected(selectedItem) + router.dismiss(animated: true) + }) { + Text(CoreLocalization.Picker.accept) + .foregroundColor(CoreAssets.textPrimary.swiftUIColor) + .frame(minWidth: 0, maxWidth: idiom == .pad ? ipadPickerWidth : .infinity) + .padding() + .background(CoreAssets.textInputBackground.swiftUIColor.cornerRadius(16)) + .padding(.horizontal, 16) + } + .padding(.bottom, 4) + .disabled(acceptButtonDisabled) + } + .avoidKeyboard(dismissKeyboardByTap: true) + .transition(.move(edge: .bottom)) } - }.transition(.opacity) - .ignoresSafeArea() + } + .transition(.opacity) + + } + +} + +#if DEBUG +struct PickerMenu_Previews: PreviewProvider { + static var previews: some View { + + let items = [ + PickerItem(key: "Uk", value: "Ukraine"), + PickerItem(key: "Us", value: "United States of America"), + PickerItem(key: "En", value: "England") + ] + + return PickerMenu(items: items, + titleText: "Select country", + router: BaseRouterMock(), + selectedItem: items.first, + selected: {_ in}) } } +#endif diff --git a/Discussion/Discussion/Presentation/Comments/Responses/ResponsesView.swift b/Discussion/Discussion/Presentation/Comments/Responses/ResponsesView.swift index 1a410b953..3df3ebdcf 100644 --- a/Discussion/Discussion/Presentation/Comments/Responses/ResponsesView.swift +++ b/Discussion/Discussion/Presentation/Comments/Responses/ResponsesView.swift @@ -195,7 +195,7 @@ public struct ResponsesView: View { } } } - } + }.edgesIgnoringSafeArea(.bottom) .background( CoreAssets.background.swiftUIColor .ignoresSafeArea() diff --git a/Discussion/Discussion/Presentation/Comments/Thread/ThreadView.swift b/Discussion/Discussion/Presentation/Comments/Thread/ThreadView.swift index 38909a86d..acafd1bd9 100644 --- a/Discussion/Discussion/Presentation/Comments/Thread/ThreadView.swift +++ b/Discussion/Discussion/Presentation/Comments/Thread/ThreadView.swift @@ -232,7 +232,7 @@ public struct ThreadView: View { } } } - } + }.edgesIgnoringSafeArea(.bottom) .background( CoreAssets.background.swiftUIColor .ignoresSafeArea() diff --git a/OpenEdX.xcodeproj/project.pbxproj b/OpenEdX.xcodeproj/project.pbxproj index 35a452168..a1df4ef51 100644 --- a/OpenEdX.xcodeproj/project.pbxproj +++ b/OpenEdX.xcodeproj/project.pbxproj @@ -227,7 +227,7 @@ 07D5DA2E28D075AA00752FD9 /* Frameworks */, 07D5DA2F28D075AA00752FD9 /* Resources */, 0770DE1528D07845006D8A5D /* Embed Frameworks */, - 02F175442A4E3B320019CD70 /* ShellScript */, + 02F175442A4E3B320019CD70 /* FirebaseCrashlytics */, ); buildRules = ( ); @@ -288,7 +288,7 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ - 02F175442A4E3B320019CD70 /* ShellScript */ = { + 02F175442A4E3B320019CD70 /* FirebaseCrashlytics */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 8; files = ( @@ -296,16 +296,15 @@ inputFileListPaths = ( ); inputPaths = ( - "${DWARF_DSYM_FOLDER_PATH}/${DWARF_DSYM_FILE_NAME}/Contents/Resources/DWARF/${TARGET_NAME}", - "$(SRCROOT)/$(BUILT_PRODUCTS_DIR)/$(INFOPLIST_PATH)", ); + name = FirebaseCrashlytics; outputFileListPaths = ( ); outputPaths = ( ); runOnlyForDeploymentPostprocessing = 1; shellPath = /bin/sh; - shellScript = "# Type a script or drag a script file from your workspace to insert its path.\n\"${BUILD_DIR%/Build/*}/SourcePackages/checkouts/firebase-ios-sdk/Crashlytics/run\"\n"; + shellScript = "case $CONFIGURATION in\n \"DebugDev\" | \"ReleaseDev\" )\n googleAppID=$(grep -A 4 'case .debugDev, .releaseDev:' ${PROJECT_DIR}/${TARGET_NAME}/Environment.swift | grep 'googleAppID:' | awk -F'\"' '{print $2}')\n ;;\n \"DebugStage\" | \"ReleaseStage\" )\n googleAppID=$(grep -A 4 'case .debugStage, .releaseStage:' ${PROJECT_DIR}/${TARGET_NAME}/Environment.swift | grep 'googleAppID:' | awk -F'\"' '{print $2}')\n ;;\n \"DebugProd\" | \"RelesaseProd\" )\n googleAppID=$(grep -A 4 'case .debugProd, .releaseProd:' ${PROJECT_DIR}/${TARGET_NAME}/Environment.swift | grep 'googleAppID:' | awk -F'\"' '{print $2}')\n ;;\n *)\n echo \"Unknown configuration\"\n ;;\nesac\n\nif [ -z \"$googleAppID\" ]\nthen\n echo \"GoogleAppID is empty. The FirebaseCrashlytics script will be skipped.\"\nelse\n \"${PODS_ROOT}/FirebaseCrashlytics/run\" --app-id \"$googleAppID\" -p ios ${DWARF_DSYM_FOLDER_PATH}\nfi\n"; }; 0770DE2328D08647006D8A5D /* SwiftLint */ = { isa = PBXShellScriptBuildPhase;