From 8b40a973c5a9d9e4536af2f0daaeb51fbab6d2dc Mon Sep 17 00:00:00 2001 From: Itunu Raimi Date: Wed, 16 Oct 2024 19:58:58 +0100 Subject: [PATCH 1/4] remove new moderation featureflag --- Nos/Service/FeatureFlags.swift | 10 ++-------- Nos/Views/Settings/SettingsView.swift | 21 +++------------------ NosTests/Service/MockFeatureFlags.swift | 4 +--- 3 files changed, 6 insertions(+), 29 deletions(-) diff --git a/Nos/Service/FeatureFlags.swift b/Nos/Service/FeatureFlags.swift index 3a1b70dca..8f0a2c835 100644 --- a/Nos/Service/FeatureFlags.swift +++ b/Nos/Service/FeatureFlags.swift @@ -3,11 +3,7 @@ import Dependencies import SwiftUI /// Feature flags for enabling experimental or beta features. -enum FeatureFlag { - /// Whether the new moderation flow should be enabled or not. - /// - Note: See [#1489](https://github.com/planetary-social/nos/issues/1489) for details on the new moderation flow. - case newModerationFlow -} +enum FeatureFlag: Hashable {} /// The set of feature flags used by the app. protocol FeatureFlags { @@ -29,9 +25,7 @@ protocol FeatureFlags { private init() {} /// Feature flags and their values. - private var featureFlags: [FeatureFlag: Bool] = [ - .newModerationFlow: false, - ] + private var featureFlags: [FeatureFlag: Bool] = [:] /// Returns true if the feature is enabled. func isEnabled(_ feature: FeatureFlag) -> Bool { diff --git a/Nos/Views/Settings/SettingsView.swift b/Nos/Views/Settings/SettingsView.swift index 3456c4c9d..7fea4cad7 100644 --- a/Nos/Views/Settings/SettingsView.swift +++ b/Nos/Views/Settings/SettingsView.swift @@ -271,29 +271,15 @@ struct SettingsView: View { // DEBUG builds will have everything that's in STAGING builds and more. #if STAGING || DEBUG -extension SettingsView { - /// Whether the new moderation flow is enabled. - private var isNewModerationFlowEnabled: Binding { - Binding( - get: { featureFlags.isEnabled(.newModerationFlow) }, - set: { featureFlags.setFeature(.newModerationFlow, enabled: $0) } - ) - } - - /// A toggle for the new moderation flow that allows the user to turn the feature on or off. - private var newModerationFlowToggle: some View { - NosToggle(isOn: isNewModerationFlowEnabled, labelText: .localizable.enableNewModerationFlow) - } -} +extension SettingsView {} #endif #if STAGING extension SettingsView { /// Controls that will appear when the app is built for STAGING. @MainActor private var stagingControls: some View { - Group { - newModerationFlowToggle - } + // To be replaced by featureflag toggle views. + EmptyView() } } #endif @@ -303,7 +289,6 @@ extension SettingsView { /// Controls that will appear when the app is built for DEBUG. @MainActor private var debugControls: some View { Group { - newModerationFlowToggle Text(.localizable.sampleDataInstructions) .foregroundColor(.primaryTxt) Button(String(localized: .localizable.loadSampleData)) { diff --git a/NosTests/Service/MockFeatureFlags.swift b/NosTests/Service/MockFeatureFlags.swift index 7d2eb5969..86bcd2bb2 100644 --- a/NosTests/Service/MockFeatureFlags.swift +++ b/NosTests/Service/MockFeatureFlags.swift @@ -1,9 +1,7 @@ /// A set of feature flag values used for testing that can be customized. class MockFeatureFlags: FeatureFlags { /// Mock feature flags and their values. - private var featureFlags: [FeatureFlag: Bool] = [ - .newModerationFlow: false, - ] + private var featureFlags: [FeatureFlag: Bool] = [:] func isEnabled(_ feature: FeatureFlag) -> Bool { featureFlags[feature] ?? false From 756f26e9d914dfd9a4ac5a53082cdfeacedf23a8 Mon Sep 17 00:00:00 2001 From: Itunu Raimi Date: Wed, 16 Oct 2024 19:59:16 +0100 Subject: [PATCH 2/4] remove old moderation code --- Nos/Views/Modifiers/ReportMenuModifier.swift | 237 +------------------ 1 file changed, 11 insertions(+), 226 deletions(-) diff --git a/Nos/Views/Modifiers/ReportMenuModifier.swift b/Nos/Views/Modifiers/ReportMenuModifier.swift index 6839a30b9..0dabd0d0e 100644 --- a/Nos/Views/Modifiers/ReportMenuModifier.swift +++ b/Nos/Views/Modifiers/ReportMenuModifier.swift @@ -10,11 +10,7 @@ struct ReportMenuModifier: ViewModifier { @Binding var isPresented: Bool var reportedObject: ReportTarget - - @State private var userSelection: UserSelection? - @State private var confirmReport = false - @State private var showMuteDialog = false - @State private var confirmationDialogState: ConfirmationDialogState? + @State private var selectedFlagOption: FlagOption? @State private var selectedFlagSendOption: FlagOption? @State private var selectedVisibilityOption: FlagOption? @@ -24,18 +20,6 @@ struct ReportMenuModifier: ViewModifier { @Dependency(\.featureFlags) private var featureFlags func body(content: Content) -> some View { - Group { - if featureFlags.isEnabled(.newModerationFlow) { - newModerationFlow(content: content) - } else { - oldModerationFlow(content: content) - } - } - } - - /// Displays the moderation flow based on the reported object type. The old flow is still displayed for the author. - @ViewBuilder - private func newModerationFlow(content: Content) -> some View { switch reportedObject { case .note: content @@ -44,11 +28,11 @@ struct ReportMenuModifier: ViewModifier { ContentFlagView( selectedFlagOptionCategory: $selectedFlagOption, selectedSendOptionCategory: $selectedFlagSendOption, - showSuccessView: $showFlagSuccessView, + showSuccessView: $showFlagSuccessView, flagTarget: reportedObject, sendAction: { if let selectCategory = selectedFlagOption?.category { - publishReportForNewModerationFlow(selectCategory) + publishReport(selectCategory) showFlagSuccessView = true } } @@ -63,11 +47,11 @@ struct ReportMenuModifier: ViewModifier { selectedFlagOption: $selectedFlagOption, selectedSendOption: $selectedFlagSendOption, selectedVisibilityOption: $selectedVisibilityOption, - showSuccessView: $showFlagSuccessView, + showSuccessView: $showFlagSuccessView, flagTarget: reportedObject, sendAction: { let selectCategory = selectedVisibilityOption?.category ?? .visibility(.dontMute) - publishReportForNewModerationFlow(selectCategory) + publishReport(selectCategory) Task { await muteUserIfNeeded() showFlagSuccessView = true @@ -78,122 +62,6 @@ struct ReportMenuModifier: ViewModifier { } } } - - // swiftlint:disable function_body_length - @ViewBuilder - func oldModerationFlow(content: Content) -> some View { - content - // ReportCategory menu - .confirmationDialog(unwrapping: $confirmationDialogState, action: processUserSelection) - .alert( - String(localized: .localizable.confirmFlag), - isPresented: $confirmReport, - actions: { - Button(String(localized: .localizable.confirm)) { - publishReport(userSelection) - - if let author = reportedObject.author, !author.muted { - showMuteDialog = true - } - } - Button(String(localized: .localizable.cancel), role: .cancel) { - userSelection = nil - } - }, - message: { - let text = getAlertMessage(for: userSelection, with: reportedObject) - Text(text) - } - ) - // Mute user menu - .alert( - String(localized: .localizable.muteUser), - isPresented: $showMuteDialog, - actions: { - if let author = reportedObject.author { - Button(String(localized: .localizable.yes)) { - Task { - await mute(author: author) - } - } - Button(String(localized: .localizable.no)) {} - } - }, - message: { - if let author = reportedObject.author { - Text(.localizable.mutePrompt(author.safeName)) - } else { - Text(.localizable.error) - } - } - ) - .onChange(of: isPresented) { _, shouldPresent in - if shouldPresent { - let message: LocalizedStringResource - if case .noteCategorySelected = userSelection { - message = .localizable.reportContentMessage - } else { - message = .localizable.flagUserMessage - } - confirmationDialogState = ConfirmationDialogState( - title: TextState(String(localized: .localizable.reportContent)), - message: TextState(String(localized: message)), - buttons: topLevelButtons() - ) - } - } - .onChange(of: confirmationDialogState) { _, newValue in - if newValue == nil { - isPresented = false - } - } - } - // swiftlint:enable function_body_length - - func processUserSelection(_ userSelection: UserSelection?) { - self.userSelection = userSelection - - guard let userSelection else { - return - } - - switch userSelection { - case .noteCategorySelected(let category): - Task { - confirmationDialogState = ConfirmationDialogState( - title: TextState(String(localized: .localizable.reportActionTitle(category.displayName))), - message: TextState(String(localized: .localizable.reportActionTitle(category.displayName))), - buttons: [ - ButtonState(action: .send(.sendToNos(category))) { - TextState("Send to Nos") - }, - ButtonState(action: .send(.flagPublicly(category))) { - TextState("Flag Publicly") - } - ] - ) - } - - case .authorCategorySelected(let category): - Task { - confirmationDialogState = ConfirmationDialogState( - title: TextState(String(localized: .localizable.reportActionTitle(category.displayName))), - message: TextState(String(localized: .localizable.reportActionTitle(category.displayName))), - buttons: [ - ButtonState(action: .send(.sendToNos(category))) { - TextState("Send to Nos") - }, - ButtonState(action: .send(.flagPublicly(category))) { - TextState("Flag Publicly") - } - ] - ) - } - - case .sendToNos, .flagPublicly: - confirmReport = true - } - } func mute(author: Author) async { do { @@ -215,66 +83,16 @@ struct ReportMenuModifier: ViewModifier { } } - /// An enum to simplify the user selection through the sequence of connected - /// dialogs - enum UserSelection: Equatable { - case noteCategorySelected(ReportCategory) - case authorCategorySelected(ReportCategory) - case sendToNos(ReportCategory) - case flagPublicly(ReportCategory) - - func confirmationAlertMessage(for reportedObject: ReportTarget) -> String { - switch self { - case .sendToNos(let category): - switch reportedObject { - case .note: - return String(localized: .localizable.reportNoteSendToNosConfirmation(category.displayName)) - case .author: - return String(localized: .localizable.reportAuthorSendToNosConfirmation) - } - - case .flagPublicly(let category): - return String(localized: .localizable.reportFlagPubliclyConfirmation(category.displayName)) - - case .noteCategorySelected(let category), - .authorCategorySelected(let category): - return String(localized: .localizable.reportFlagPubliclyConfirmation(category.displayName)) - } - } - } - - /// List of the top-level report categories we care about. - func topLevelButtons() -> [ButtonState] { - switch reportedObject { - case .note: - ReportCategory.noteCategories.map { category in - let userSelection = UserSelection.noteCategorySelected(category) - - return ButtonState(action: .send(userSelection)) { - TextState(verbatim: category.displayName) - } - } - case .author: - ReportCategory.authorCategories.map { category in - let userSelection = UserSelection.authorCategorySelected(category) - - return ButtonState(action: .send(userSelection)) { - TextState(verbatim: category.displayName) - } - } - } - } - - /// Publishes a report based on the categories the user selected for the new moderation flow. - private func publishReportForNewModerationFlow(_ selectedCategory: FlagCategory) { + /// Publishes a report based on the category the user selected. + private func publishReport(_ selectedCategory: FlagCategory) { if case .privacy(let privacyCategory) = selectedFlagSendOption?.category, privacyCategory == .sendToNos { - sendToNosForNewModerationFlow(selectedCategory) + sendToNos(selectedCategory) } else { - flagPubliclyForNewModerationFlow(selectedCategory) + flagPublicly(selectedCategory) } } - private func sendToNosForNewModerationFlow(_ selectedCategory: FlagCategory) { + private func sendToNos(_ selectedCategory: FlagCategory) { if case .report(let reportCategory) = selectedCategory { // Call the publisher with the extracted ReportCategory ReportPublisher().publishPrivateReport( @@ -285,7 +103,7 @@ struct ReportMenuModifier: ViewModifier { } } - private func flagPubliclyForNewModerationFlow(_ selectedCategory: FlagCategory) { + private func flagPublicly(_ selectedCategory: FlagCategory) { if case .report(let reportCategory) = selectedCategory { ReportPublisher().publishPublicReport( for: reportedObject, @@ -294,39 +112,6 @@ struct ReportMenuModifier: ViewModifier { ) } } - - /// Publishes a report based on user input for the old moderation flow. - func publishReport(_ userSelection: UserSelection?) { - switch userSelection { - case .sendToNos(let selectedCategory): - sendToNos(selectedCategory) - case .flagPublicly(let selectedCategory): - flagPublicly(selectedCategory) - case .noteCategorySelected, .authorCategorySelected, .none: - // This would be a dev error - Log.error("Invalid user selection") - } - } - - func sendToNos(_ selectedCategory: ReportCategory) { - ReportPublisher().publishPrivateReport( - for: reportedObject, - category: selectedCategory, - context: viewContext - ) - } - - func flagPublicly(_ selectedCategory: ReportCategory) { - ReportPublisher().publishPublicReport( - for: reportedObject, - category: selectedCategory, - context: viewContext - ) - } - - func getAlertMessage(for userSelection: UserSelection?, with reportedObject: ReportTarget) -> String { - userSelection?.confirmationAlertMessage(for: reportedObject) ?? String(localized: .localizable.error) - } } extension View { From 8175cf19680389e6bf5818bde5e382e7f5b7ab40 Mon Sep 17 00:00:00 2001 From: Itunu Raimi Date: Wed, 16 Oct 2024 20:02:55 +0100 Subject: [PATCH 3/4] update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 367ccddda..98abb4f7b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Removed integration with Universal Name Space [#1636](https://github.com/planetary-social/nos/issues/1636) ### Internal Changes +- Removed new moderation feature flag. [#1646](https://github.com/planetary-social/nos/issues/1646) ## [0.2.2] - 2024-10-11Z From f327fd2a62a7b018f52534e0c780af0bdf872919 Mon Sep 17 00:00:00 2001 From: Itunu Raimi Date: Fri, 18 Oct 2024 14:16:31 +0100 Subject: [PATCH 4/4] remove enableNewModerationFlow key --- Nos/Assets/Localization/Localizable.xcstrings | 29 ------------------- 1 file changed, 29 deletions(-) diff --git a/Nos/Assets/Localization/Localizable.xcstrings b/Nos/Assets/Localization/Localizable.xcstrings index b65461f57..0f5d62668 100644 --- a/Nos/Assets/Localization/Localizable.xcstrings +++ b/Nos/Assets/Localization/Localizable.xcstrings @@ -5509,35 +5509,6 @@ } } }, - "enableNewModerationFlow" : { - "extractionState" : "manual", - "localizations" : { - "en" : { - "stringUnit" : { - "state" : "translated", - "value" : "Enable new moderation flow" - } - }, - "es" : { - "stringUnit" : { - "state" : "translated", - "value" : "Activar nuevo flujo de moderación" - } - }, - "ko" : { - "stringUnit" : { - "state" : "translated", - "value" : "새로운 모더레이션 흐름 활성화" - } - }, - "zh-Hans" : { - "stringUnit" : { - "state" : "translated", - "value" : "启用新审核流程" - } - } - } - }, "enterCode" : { "extractionState" : "manual", "localizations" : {