mirror of
https://github.com/element-hq/element-x-ios.git
synced 2025-03-11 13:59:13 +00:00
Pinning items Feature Flag (#3063)
This commit is contained in:
parent
7fbdc2c20f
commit
d437e1f3ed
@ -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
|
||||||
@ -282,6 +283,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
|
||||||
|
|
||||||
// MARK: - Shared
|
// MARK: - Shared
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
|
||||||
@ -65,6 +66,11 @@ struct TimelineItemMenuActionProvider {
|
|||||||
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
|
||||||
|
BIN
PreviewTests/__Snapshots__/PreviewTests/test_timelineItemMenu-iPad-en-GB.With-button-shapes-off.png
(Stored with Git LFS)
BIN
PreviewTests/__Snapshots__/PreviewTests/test_timelineItemMenu-iPad-en-GB.With-button-shapes-off.png
(Stored with Git LFS)
Binary file not shown.
BIN
PreviewTests/__Snapshots__/PreviewTests/test_timelineItemMenu-iPad-en-GB.With-button-shapes-on.png
(Stored with Git LFS)
BIN
PreviewTests/__Snapshots__/PreviewTests/test_timelineItemMenu-iPad-en-GB.With-button-shapes-on.png
(Stored with Git LFS)
Binary file not shown.
BIN
PreviewTests/__Snapshots__/PreviewTests/test_timelineItemMenu-iPad-pseudo.With-button-shapes-off.png
(Stored with Git LFS)
BIN
PreviewTests/__Snapshots__/PreviewTests/test_timelineItemMenu-iPad-pseudo.With-button-shapes-off.png
(Stored with Git LFS)
Binary file not shown.
BIN
PreviewTests/__Snapshots__/PreviewTests/test_timelineItemMenu-iPad-pseudo.With-button-shapes-on.png
(Stored with Git LFS)
BIN
PreviewTests/__Snapshots__/PreviewTests/test_timelineItemMenu-iPad-pseudo.With-button-shapes-on.png
(Stored with Git LFS)
Binary file not shown.
BIN
PreviewTests/__Snapshots__/PreviewTests/test_timelineItemMenu-iPhone-15-en-GB.With-button-shapes-off.png
(Stored with Git LFS)
BIN
PreviewTests/__Snapshots__/PreviewTests/test_timelineItemMenu-iPhone-15-en-GB.With-button-shapes-off.png
(Stored with Git LFS)
Binary file not shown.
BIN
PreviewTests/__Snapshots__/PreviewTests/test_timelineItemMenu-iPhone-15-en-GB.With-button-shapes-on.png
(Stored with Git LFS)
BIN
PreviewTests/__Snapshots__/PreviewTests/test_timelineItemMenu-iPhone-15-en-GB.With-button-shapes-on.png
(Stored with Git LFS)
Binary file not shown.
Binary file not shown.
BIN
PreviewTests/__Snapshots__/PreviewTests/test_timelineItemMenu-iPhone-15-pseudo.With-button-shapes-on.png
(Stored with Git LFS)
BIN
PreviewTests/__Snapshots__/PreviewTests/test_timelineItemMenu-iPhone-15-pseudo.With-button-shapes-on.png
(Stored with Git LFS)
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user