Pinning items Feature Flag (#3063)

This commit is contained in:
Mauro
2024-07-18 18:28:30 +02:00
committed by GitHub
parent 7fbdc2c20f
commit d437e1f3ed
24 changed files with 66 additions and 21 deletions
+1 -2
View File
@@ -24,8 +24,7 @@ line_length:
error: 1000 error: 1000
file_length: file_length:
warning: 1000 warning: 2000
error: 1000
type_name: type_name:
min_length: 3 min_length: 3
@@ -102,6 +102,7 @@
"action_view_source" = "View source"; "action_view_source" = "View source";
"action_yes" = "Yes"; "action_yes" = "Yes";
"action.load_more" = "Load more"; "action.load_more" = "Load more";
"action.pin" = "Pin";
"common_about" = "About"; "common_about" = "About";
"common_acceptable_use_policy" = "Acceptable use policy"; "common_acceptable_use_policy" = "Acceptable use policy";
"common_advanced_settings" = "Advanced settings"; "common_advanced_settings" = "Advanced settings";
@@ -252,6 +253,10 @@
"error_no_compatible_app_found" = "No compatible app was found to handle this action."; "error_no_compatible_app_found" = "No compatible app was found to handle this action.";
"error_some_messages_have_not_been_sent" = "Some messages have not been sent"; "error_some_messages_have_not_been_sent" = "Some messages have not been sent";
"error_unknown" = "Sorry, an error occurred"; "error_unknown" = "Sorry, an error occurred";
"event_shield_reason_authenticity_not_guaranteed" = "The authenticity of this encrypted message can't be guaranteed on this device.";
"event_shield_reason_unknown_device" = "Encrypted by an unknown or deleted device.";
"event_shield_reason_unsigned_device" = "Encrypted by a device not verified by its owner.";
"event_shield_reason_unverified_identity" = "Encrypted by an unverified user.";
"full_screen_intent_banner_message" = "To ensure you never miss an important call, please change your settings to allow full-screen notifications when your phone is locked."; "full_screen_intent_banner_message" = "To ensure you never miss an important call, please change your settings to allow full-screen notifications when your phone is locked.";
"full_screen_intent_banner_title" = "Enhance your call experience"; "full_screen_intent_banner_title" = "Enhance your call experience";
"invite_friends_rich_title" = "🔐️ Join me on %1$@"; "invite_friends_rich_title" = "🔐️ Join me on %1$@";
@@ -46,6 +46,7 @@ final class AppSettings {
case simplifiedSlidingSyncEnabled case simplifiedSlidingSyncEnabled
case publicSearchEnabled case publicSearchEnabled
case fuzzyRoomListSearchEnabled case fuzzyRoomListSearchEnabled
case pinningEnabled
} }
private static var suiteName: String = InfoPlistReader.main.appGroupIdentifier private static var suiteName: String = InfoPlistReader.main.appGroupIdentifier
@@ -281,6 +282,9 @@ final class AppSettings {
@UserPreference(key: UserDefaultsKeys.fuzzyRoomListSearchEnabled, defaultValue: false, storageType: .userDefaults(store)) @UserPreference(key: UserDefaultsKeys.fuzzyRoomListSearchEnabled, defaultValue: false, storageType: .userDefaults(store))
var fuzzyRoomListSearchEnabled var fuzzyRoomListSearchEnabled
@UserPreference(key: UserDefaultsKeys.pinningEnabled, defaultValue: false, storageType: .userDefaults(store))
var pinningEnabled
#endif #endif
@@ -19,7 +19,6 @@ import SwiftState
import SwiftUI import SwiftUI
import UserNotifications import UserNotifications
// swiftlint:disable file_length
enum RoomFlowCoordinatorAction: Equatable { enum RoomFlowCoordinatorAction: Equatable {
case presentCallScreen(roomProxy: RoomProxyProtocol) case presentCallScreen(roomProxy: RoomProxyProtocol)
case finished case finished
+10
View File
@@ -562,6 +562,14 @@ internal enum L10n {
internal static var errorSomeMessagesHaveNotBeenSent: String { return L10n.tr("Localizable", "error_some_messages_have_not_been_sent") } internal static var errorSomeMessagesHaveNotBeenSent: String { return L10n.tr("Localizable", "error_some_messages_have_not_been_sent") }
/// Sorry, an error occurred /// Sorry, an error occurred
internal static var errorUnknown: String { return L10n.tr("Localizable", "error_unknown") } internal static var errorUnknown: String { return L10n.tr("Localizable", "error_unknown") }
/// The authenticity of this encrypted message can't be guaranteed on this device.
internal static var eventShieldReasonAuthenticityNotGuaranteed: String { return L10n.tr("Localizable", "event_shield_reason_authenticity_not_guaranteed") }
/// Encrypted by an unknown or deleted device.
internal static var eventShieldReasonUnknownDevice: String { return L10n.tr("Localizable", "event_shield_reason_unknown_device") }
/// Encrypted by a device not verified by its owner.
internal static var eventShieldReasonUnsignedDevice: String { return L10n.tr("Localizable", "event_shield_reason_unsigned_device") }
/// Encrypted by an unverified user.
internal static var eventShieldReasonUnverifiedIdentity: String { return L10n.tr("Localizable", "event_shield_reason_unverified_identity") }
/// To ensure you never miss an important call, please change your settings to allow full-screen notifications when your phone is locked. /// To ensure you never miss an important call, please change your settings to allow full-screen notifications when your phone is locked.
internal static var fullScreenIntentBannerMessage: String { return L10n.tr("Localizable", "full_screen_intent_banner_message") } internal static var fullScreenIntentBannerMessage: String { return L10n.tr("Localizable", "full_screen_intent_banner_message") }
/// Enhance your call experience /// Enhance your call experience
@@ -2221,6 +2229,8 @@ internal enum L10n {
internal enum Action { internal enum Action {
/// Load more /// Load more
internal static var loadMore: String { return L10n.tr("Localizable", "action.load_more") } internal static var loadMore: String { return L10n.tr("Localizable", "action.load_more") }
/// Pin
internal static var pin: String { return L10n.tr("Localizable", "action.pin") }
} }
internal enum Common { internal enum Common {
@@ -171,6 +171,9 @@ class RoomScreenInteractionHandler {
Task { await roomProxy.timeline.toggleReaction(key, to: eventID) } Task { await roomProxy.timeline.toggleReaction(key, to: eventID) }
case .endPoll(let pollStartID): case .endPoll(let pollStartID):
endPoll(pollStartID: pollStartID) endPoll(pollStartID: pollStartID)
case .pin:
// TODO: Implement the pin action
break
} }
if action.switchToDefaultComposer { if action.switchToDefaultComposer {
@@ -163,6 +163,7 @@ struct RoomScreenViewState: BindableState {
var ownUserID: String var ownUserID: String
var canCurrentUserRedactOthers = false var canCurrentUserRedactOthers = false
var canCurrentUserRedactSelf = false var canCurrentUserRedactSelf = false
var canCurrentUserPin = false
var isViewSourceEnabled: Bool var isViewSourceEnabled: Bool
var canJoinCall = false var canJoinCall = false
@@ -359,6 +359,13 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol
} else { } else {
state.canCurrentUserRedactSelf = false state.canCurrentUserRedactSelf = false
} }
if appSettings.pinningEnabled,
case let .success(value) = await roomProxy.canUser(userID: roomProxy.ownUserID, sendStateEvent: .roomPinnedEvents) {
state.canCurrentUserPin = value
} else {
state.canCurrentUserPin = false
}
} }
private func setupSubscriptions() { private func setupSubscriptions() {
@@ -183,7 +183,7 @@ struct TimelineItemMenu_Previews: PreviewProvider, TestablePreview {
@ViewBuilder @ViewBuilder
static var testView: some View { static var testView: some View {
if let item = RoomTimelineItemFixtures.singleMessageChunk.first as? EventBasedTimelineItemProtocol, if let item = RoomTimelineItemFixtures.singleMessageChunk.first as? EventBasedTimelineItemProtocol,
let actions = TimelineItemMenuActions(isReactable: true, actions: [.copy, .edit, .reply(isThread: false), .redact], debugActions: [.viewSource]) { let actions = TimelineItemMenuActions(isReactable: true, actions: [.copy, .edit, .reply(isThread: false), .pin, .redact], debugActions: [.viewSource]) {
TimelineItemMenu(item: item, actions: actions) TimelineItemMenu(item: item, actions: actions)
.environmentObject(viewModel.context) .environmentObject(viewModel.context)
} }
@@ -61,6 +61,7 @@ enum TimelineItemMenuAction: Identifiable, Hashable {
case react case react
case toggleReaction(key: String) case toggleReaction(key: String)
case endPoll(pollStartID: String) case endPoll(pollStartID: String)
case pin
var id: Self { self } var id: Self { self }
@@ -133,6 +134,8 @@ enum TimelineItemMenuAction: Identifiable, Hashable {
Label(L10n.actionReact, icon: \.reactionAdd) Label(L10n.actionReact, icon: \.reactionAdd)
case .endPoll: case .endPoll:
Label(L10n.actionEndPoll, icon: \.pollsEnd) Label(L10n.actionEndPoll, icon: \.pollsEnd)
case .pin:
Label(L10n.Action.pin, icon: \.pin)
} }
} }
} }
@@ -20,6 +20,7 @@ struct TimelineItemMenuActionProvider {
let timelineItem: RoomTimelineItemProtocol let timelineItem: RoomTimelineItemProtocol
let canCurrentUserRedactSelf: Bool let canCurrentUserRedactSelf: Bool
let canCurrentUserRedactOthers: Bool let canCurrentUserRedactOthers: Bool
let canCurrentUserPin: Bool
let isDM: Bool let isDM: Bool
let isViewSourceEnabled: Bool let isViewSourceEnabled: Bool
@@ -64,6 +65,11 @@ struct TimelineItemMenuActionProvider {
if item.isForwardable { if item.isForwardable {
actions.append(.forward(itemID: item.id)) actions.append(.forward(itemID: item.id))
} }
if canCurrentUserPin {
// TODO: If the event is already pinned use the unpinned action
actions.append(.pin)
}
if item.isEditable { if item.isEditable {
actions.append(.edit) actions.append(.edit)
@@ -60,6 +60,7 @@ struct RoomScreen: View {
let actions = TimelineItemMenuActionProvider(timelineItem: info.item, let actions = TimelineItemMenuActionProvider(timelineItem: info.item,
canCurrentUserRedactSelf: context.viewState.canCurrentUserRedactSelf, canCurrentUserRedactSelf: context.viewState.canCurrentUserRedactSelf,
canCurrentUserRedactOthers: context.viewState.canCurrentUserRedactOthers, canCurrentUserRedactOthers: context.viewState.canCurrentUserRedactOthers,
canCurrentUserPin: context.viewState.canCurrentUserPin,
isDM: context.viewState.isEncryptedOneToOneRoom, isDM: context.viewState.isEncryptedOneToOneRoom,
isViewSourceEnabled: context.viewState.isViewSourceEnabled).makeActions() isViewSourceEnabled: context.viewState.isViewSourceEnabled).makeActions()
if let actions { if let actions {
@@ -146,6 +146,7 @@ struct TimelineItemBubbledStylerView<Content: View>: View {
let provider = TimelineItemMenuActionProvider(timelineItem: timelineItem, let provider = TimelineItemMenuActionProvider(timelineItem: timelineItem,
canCurrentUserRedactSelf: context.viewState.canCurrentUserRedactSelf, canCurrentUserRedactSelf: context.viewState.canCurrentUserRedactSelf,
canCurrentUserRedactOthers: context.viewState.canCurrentUserRedactOthers, canCurrentUserRedactOthers: context.viewState.canCurrentUserRedactOthers,
canCurrentUserPin: context.viewState.canCurrentUserPin,
isDM: context.viewState.isEncryptedOneToOneRoom, isDM: context.viewState.isEncryptedOneToOneRoom,
isViewSourceEnabled: context.viewState.isViewSourceEnabled) isViewSourceEnabled: context.viewState.isViewSourceEnabled)
TimelineItemMacContextMenu(item: timelineItem, actionProvider: provider) { action in TimelineItemMacContextMenu(item: timelineItem, actionProvider: provider) { action in
@@ -50,6 +50,7 @@ protocol DeveloperOptionsProtocol: AnyObject {
var hideUnreadMessagesBadge: Bool { get set } var hideUnreadMessagesBadge: Bool { get set }
var elementCallBaseURLOverride: URL? { get set } var elementCallBaseURLOverride: URL? { get set }
var fuzzyRoomListSearchEnabled: Bool { get set } var fuzzyRoomListSearchEnabled: Bool { get set }
var pinningEnabled: Bool { get set }
} }
extension AppSettings: DeveloperOptionsProtocol { } extension AppSettings: DeveloperOptionsProtocol { }
@@ -34,6 +34,12 @@ struct DeveloperOptionsScreen: View {
} }
} }
Section("Message Pinning") {
Toggle(isOn: $context.pinningEnabled) {
Text("Enable message pinning")
}
}
Section("Room List") { Section("Room List") {
Toggle(isOn: $context.hideUnreadMessagesBadge) { Toggle(isOn: $context.hideUnreadMessagesBadge) {
Text("Hide grey dots") Text("Hide grey dots")
@@ -21,7 +21,6 @@ import OrderedCollections
import MatrixRustSDK import MatrixRustSDK
// swiftlint:disable file_length
class ClientProxy: ClientProxyProtocol { class ClientProxy: ClientProxyProtocol {
private let client: ClientProtocol private let client: ClientProtocol
private let networkMonitor: NetworkMonitorProtocol private let networkMonitor: NetworkMonitorProtocol
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:f46e822288b874113cb394100fbbff35a8616cda0dc6cfa7c1a1410e5b49e91d oid sha256:0b9ef697532f30ecb4ad0c1ae42cec52c495999da9e2ff238e486be621626692
size 127003 size 128275
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:67c315bf682af0c5854e37c82750ca989b9bfb3c603ac69c5103ba2893950258 oid sha256:b98860688a9a13f02ed226c6db06b208381c0938242b923b24669826ea30ad5c
size 143638 size 146954
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:ea560b1062c00a38384b0dc8328a14f838a2cebab67283bd0deea992df4be2bc oid sha256:5438bd086e097841f104bd6d6b43b308a2116a8be81253fbef9666267403c26f
size 128580 size 130069
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:bf9f9f7c473075e01e4e19c0c0cd4fa0ffe993df1b5ce08e5d4620a3690a97c4 oid sha256:d39ea3ad6fe5325875e6449b08c6d5f4c8a56ded6d8b52a2a71aba606af01302
size 145322 size 148904
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:0ba6183390b1f17c1dac61022e3e737a00a2e8f83ab3fe95ec7b11f0a9a97e93 oid sha256:babe7ac92847207fe9c42db76a25c443fc056d0cb5236bb74123df1eb1c75fc7
size 80182 size 81558
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:ae2277fff27f324b3c599e106b73b7478bd31f9dc8c5107541ab51abbbd30a77 oid sha256:b92834dc9f0ea920743fd9336de180eafdc87071209a27e8bd880d21e8e6a39f
size 89235 size 91943
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:4aafeeb6bf21e5d3e1cda0acd6f8341e266c1f38673608ec173416d9644c2dc3 oid sha256:8bdb7a577de87f2e99570feda71222da953c4321e3a681c62d0d80b6079cdf81
size 85427 size 87175
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:460efbd1e2ed063b9ecc37ba9e7a1d466a16c3931c362b0e5b69d837b936f73f oid sha256:5d2ba9cfa065c63a2e62df7ed84bf4838cb01b29124b70a6c9a220d8c037cc50
size 94636 size 97569