Blocklist and mutelist

This commit is contained in:
Lumaa 2024-03-23 11:16:47 +01:00
parent af2d85dcc1
commit 81f2814374
6 changed files with 312 additions and 11 deletions

View File

@ -10,6 +10,7 @@
B9029FC22B81259400AA9B68 /* Secret.plist in Resources */ = {isa = PBXBuildFile; fileRef = B9029FC12B81259400AA9B68 /* Secret.plist */; };
B9029FC42B8125CE00AA9B68 /* HuggingFace.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9029FC32B8125CE00AA9B68 /* HuggingFace.swift */; };
B915C4422B6F908C00042DDB /* ProfileView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B915C4412B6F908C00042DDB /* ProfileView.swift */; };
B934EA242BAB5E7F001F4345 /* RestrictedView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B934EA232BAB5E7F001F4345 /* RestrictedView.swift */; };
B93757112B7FB8D400652F91 /* AltClients.swift in Sources */ = {isa = PBXBuildFile; fileRef = B93757102B7FB8D400652F91 /* AltClients.swift */; };
B93ADFCB2B7625CD00FF9172 /* DiscoveryView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B93ADFCA2B7625CD00FF9172 /* DiscoveryView.swift */; };
B93B676D2B42C94F000892E9 /* Nuke in Frameworks */ = {isa = PBXBuildFile; productRef = B93B676C2B42C94F000892E9 /* Nuke */; };
@ -190,6 +191,7 @@
B9029FC12B81259400AA9B68 /* Secret.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Secret.plist; sourceTree = "<group>"; };
B9029FC32B8125CE00AA9B68 /* HuggingFace.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HuggingFace.swift; sourceTree = "<group>"; };
B915C4412B6F908C00042DDB /* ProfileView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileView.swift; sourceTree = "<group>"; };
B934EA232BAB5E7F001F4345 /* RestrictedView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RestrictedView.swift; sourceTree = "<group>"; };
B93757102B7FB8D400652F91 /* AltClients.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AltClients.swift; sourceTree = "<group>"; };
B93ADFCA2B7625CD00FF9172 /* DiscoveryView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiscoveryView.swift; sourceTree = "<group>"; };
B93B67772B42E8F0000892E9 /* TextEmoji.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextEmoji.swift; sourceTree = "<group>"; };
@ -569,6 +571,7 @@
B98BC7482B46CEDA00595441 /* AppearenceView.swift */,
B97798882B853E6600DC869F /* UpdateView.swift */,
B9B469B12B9A6E8300AD5585 /* PrivacyView.swift */,
B934EA232BAB5E7F001F4345 /* RestrictedView.swift */,
);
path = Settings;
sourceTree = "<group>";
@ -870,6 +873,7 @@
B93B677A2B42EC51000892E9 /* MetaPicker.swift in Sources */,
B9D9C6C32B6A576C00C26A41 /* NotificationsView.swift in Sources */,
B9FA6E772B82788A00D63E30 /* AccountRow.swift in Sources */,
B934EA242BAB5E7F001F4345 /* RestrictedView.swift in Sources */,
B9FB94722B2DF49700D81C07 /* ConnectView.swift in Sources */,
B9FB945B2B2DEECE00D81C07 /* ThreadedApp.swift in Sources */,
B9FB94862B2E211200D81C07 /* Account+Elms.swift in Sources */,

View File

@ -741,3 +741,33 @@ public enum Polls: Endpoint {
}
}
}
public enum Restricted: Endpoint {
case mutes(maxId: String?)
case blockedUsers(maxId: String?)
case blockedDomains(maxId: String?) // array of strings
public func path() -> String {
switch self {
case .mutes:
"mutes"
case .blockedUsers:
"blocks"
case .blockedDomains:
"domain_blocks"
}
}
public func queryItems() -> [URLQueryItem]? {
switch self {
case let .mutes(maxId):
return makePaginationParam(sinceId: nil, maxId: maxId, mindId: nil)
case let .blockedUsers(maxId):
return makePaginationParam(sinceId: nil, maxId: maxId, mindId: nil)
case let .blockedDomains(maxId):
return makePaginationParam(sinceId: nil, maxId: maxId, mindId: nil)
}
}
}

View File

@ -127,6 +127,7 @@ public enum RouterDestination: Hashable {
case appearence
case about
case privacy
case restricted
case account(acc: Account)
case post(status: Status)
@ -135,7 +136,7 @@ public enum RouterDestination: Hashable {
}
extension RouterDestination {
static let allSettings: [RouterDestination] = [.settings, .support, .about, .appearence]
static let allSettings: [RouterDestination] = [.settings, .support, .about, .appearence, .privacy, .restricted]
}
extension View {
@ -143,7 +144,7 @@ extension View {
navigationDestination(for: RouterDestination.self) { destination in
switch destination {
case .settings:
SettingsView(navigator: navigator)
SettingsView()
case .support:
SupportView()
case .appearence:
@ -158,6 +159,8 @@ extension View {
ContactsView()
case .privacy:
PrivacyView()
case .restricted:
RestrictedView()
case .timeline(let timeline):
PostsView(filter: timeline ?? .home, showHero: false)
}

View File

@ -1415,6 +1415,89 @@
}
}
},
"restricted.blocked-domain" : {
"extractionState" : "manual",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Hidden"
}
},
"fr" : {
"stringUnit" : {
"state" : "translated",
"value" : "Caché"
}
}
}
},
"restricted.blocked-user" : {
"extractionState" : "manual",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Blocked"
}
},
"fr" : {
"stringUnit" : {
"state" : "translated",
"value" : "Bloqué(e)"
}
}
}
},
"restricted.muted" : {
"extractionState" : "manual",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Muted"
}
},
"fr" : {
"stringUnit" : {
"state" : "translated",
"value" : "Muet(te)"
}
}
}
},
"restricted.no-restricted" : {
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "No restrictions"
}
},
"fr" : {
"stringUnit" : {
"state" : "translated",
"value" : "Aucun restreints"
}
}
}
},
"restricted.no-restricted.description" : {
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "You have no mutes and blocks, it means you are peaceful."
}
},
"fr" : {
"stringUnit" : {
"state" : "translated",
"value" : "Vous n'avez aucun muets ou bloqués, vous ne faites qu'un avec la paix."
}
}
}
},
"setting.appearence" : {
"localizations" : {
"en" : {
@ -1847,6 +1930,38 @@
}
}
},
"settings.privacy.restricted" : {
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Restricted"
}
},
"fr" : {
"stringUnit" : {
"state" : "translated",
"value" : "Restreints"
}
}
}
},
"settings.restart-app" : {
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Some settings might require the app to be restarted"
}
},
"fr" : {
"stringUnit" : {
"state" : "translated",
"value" : "Certains paramètres nécessite le redémarrage de l'application"
}
}
}
},
"shop.best" : {
"localizations" : {
"en" : {
@ -3384,4 +3499,4 @@
}
},
"version" : "1.0"
}
}

View File

@ -12,7 +12,16 @@ struct PrivacyView: View {
var body: some View {
List {
//TODO: Blocklist & Mutelist
Button {
navigator.navigate(to: .restricted)
} label: {
Label("settings.privacy.restricted", systemImage: "speaker.badge.exclamationmark")
}
.listRowThreaded()
Spacer()
.frame(height: 30)
.listRowThreaded()
Picker(LocalizedStringKey("setting.privacy.default-visibility"), selection: $userPreferences.defaultVisibility) {
ForEach(Visibility.allCases, id: \.self) { visibility in
@ -100,7 +109,3 @@ struct PrivacyView: View {
}
}
}
#Preview {
PrivacyView()
}

View File

@ -3,11 +3,155 @@
import SwiftUI
struct RestrictedView: View {
@Environment(AccountManager.self) private var accountManager: AccountManager
@EnvironmentObject private var navigator: Navigator
@State private var foundAccounts: [Account] = []
@State private var foundRelations: [Relationship] = []
@State private var blockedDomains: [String] = []
var body: some View {
Text(/*@START_MENU_TOKEN@*/"Hello, World!"/*@END_MENU_TOKEN@*/)
List {
if foundAccounts.count > 0 && foundRelations.count > 0 {
ForEach(foundAccounts) { acc in
let correctRelation: Relationship = foundRelations.filter({ $0.id == acc.id })[0]
let restrictionType: RestrictionType = .find(isMuted: correctRelation.muting, isBlocked: correctRelation.blocking)
AccountRow(acct: acc.acct) {
restrictionType.rowLabel()
}
.listRowThreaded()
}
}
if blockedDomains.count > 0 {
ForEach(blockedDomains, id: \.self) { dom in
let restrictionType: RestrictionType = .blockedDomains
HStack {
VStack(alignment: .leading, spacing: 3.5) {
restrictionType.rowLabel()
Text(dom)
.multilineTextAlignment(.leading)
}
Spacer()
}
.listRowThreaded()
}
}
if foundAccounts.count <= 0 && blockedDomains.count <= 0 {
ContentUnavailableView("restricted.no-restricted", systemImage: "person.and.background.dotted", description: Text("restricted.no-restricted.description"))
.listRowThreaded()
}
}
.task {
await refresh()
}
.refreshable {
await refresh()
}
.navigationTitle(Text("settings.privacy.restricted"))
.navigationBarTitleDisplayMode(.inline)
.listThreaded()
}
private func refresh() async {
guard let client = accountManager.getClient() else { return }
foundAccounts = []
do {
let muted: [Account] = try await client.get(endpoint: Restricted.mutes(maxId: nil))
let blocked: [Account] = try await client.get(endpoint: Restricted.blockedUsers(maxId: nil))
blockedDomains = try await client.get(endpoint: Restricted.blockedDomains(maxId: nil))
foundAccounts.append(contentsOf: muted)
foundAccounts.append(contentsOf: blocked)
foundRelations = try await client.get(endpoint: Accounts.relationships(ids: foundAccounts.map({ $0.id })))
} catch {
print(error)
}
}
func asyncAction(endpoint: Endpoint) {
guard let client = accountManager.getClient() else { return }
Task {
_ = try await client.post(endpoint: endpoint)
}
}
}
#Preview {
RestrictedView()
public enum RestrictionType {
case muted
case blockedUsers
case blockedDomains
static func find(isMuted: Bool = false, isBlocked: Bool = false, isBlockedDomain: Bool = false) -> RestrictionType {
if isMuted && !isBlocked {
return RestrictionType.muted
} else if isBlocked {
return RestrictionType.blockedUsers
} else if isBlockedDomain {
return RestrictionType.blockedDomains
}
return RestrictionType.muted
}
func localizedTitle() -> LocalizedStringKey {
switch self {
case .muted:
return .init("restricted.mutes")
case .blockedUsers:
return .init("restricted.users")
case .blockedDomains:
return .init("restricted.domains")
}
}
func localizedType() -> LocalizedStringKey {
switch self {
case .muted:
return .init("restricted.muted")
case .blockedUsers:
return .init("restricted.blocked-user")
case .blockedDomains:
return .init("restricted.blocked-domain")
}
}
func assimilatedIcon() -> String {
switch self {
case .muted:
return "speaker.slash.fill"
case .blockedUsers:
return "hand.raised.slash.fill"
case .blockedDomains:
return "network.slash"
}
}
func assimilatedColor() -> Color {
switch self {
case .muted:
return Color.yellow
case .blockedUsers:
return Color.orange
case .blockedDomains:
return Color.red
}
}
@ViewBuilder
func rowLabel() -> some View {
HStack {
Image(systemName: self.assimilatedIcon())
.font(.body.bold())
.foregroundStyle(self.assimilatedColor())
Text(self.localizedType())
.accountRowLabel(self.assimilatedColor())
}
}
}