Skip to content

Commit

Permalink
Pinned Items Banner UI (#3072)
Browse files Browse the repository at this point in the history
  • Loading branch information
Velin92 authored Jul 22, 2024
1 parent ff33c07 commit 5cb44ee
Show file tree
Hide file tree
Showing 15 changed files with 236 additions and 24 deletions.
54 changes: 31 additions & 23 deletions ElementX.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions ElementX/Sources/Screens/RoomScreen/RoomScreenModels.swift
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,7 @@ struct RoomScreenViewState: BindableState {
var canCurrentUserRedactSelf = false
var canCurrentUserPin = false
var isViewSourceEnabled: Bool
var isPinningEnabled = false

var canJoinCall = false
var hasOngoingCall = false
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -360,7 +360,7 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol
state.canCurrentUserRedactSelf = false
}

if appSettings.pinningEnabled,
if state.isPinningEnabled,
case let .success(value) = await roomProxy.canUser(userID: roomProxy.ownUserID, sendStateEvent: .roomPinnedEvents) {
state.canCurrentUserPin = value
} else {
Expand Down Expand Up @@ -414,6 +414,10 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol
.weakAssign(to: \.state.isViewSourceEnabled, on: self)
.store(in: &cancellables)

appSettings.$pinningEnabled
.weakAssign(to: \.state.isPinningEnabled, on: self)
.store(in: &cancellables)

roomProxy.membersPublisher
.receive(on: DispatchQueue.main)
.sink { [weak self] in self?.updateMembers($0) }
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
//
// Copyright 2024 New Vector Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

import Compound
import SwiftUI

struct PinnedItemsBannerView: View {
let pinIndex: Int
let pinsCount: Int
let pinContent: AttributedString

let onMainButtonTap: () -> Void
let onViewAllButtonTap: () -> Void

private var bannerIndicatorDescription: AttributedString {
let index = pinIndex + 1
let boldPlaceholder = "{bold}"
var finalString = AttributedString(L10n.Screen.Room.pinnedBannerIndicatorDescription(boldPlaceholder))
var boldString = AttributedString(L10n.Screen.Room.pinnedBannerIndicator(index, pinsCount))
boldString.bold()
finalString.replace(boldPlaceholder, with: boldString)
return finalString
}

var body: some View {
HStack(spacing: 0) {
mainButton
viewAllButton
}
.padding(.vertical, 16)
.padding(.leading, 16)
.background(Color.compound.bgCanvasDefault)
.shadow(color: Color(red: 0.11, green: 0.11, blue: 0.13).opacity(0.1), radius: 12, x: 0, y: 4)
}

private var mainButton: some View {
Button { onMainButtonTap() } label: {
HStack(spacing: 0) {
HStack(spacing: 10) {
PinnedItemsIndicatorView(pinIndex: pinIndex, pinsCount: pinsCount)
.accessibilityHidden(true)
CompoundIcon(\.pinSolid, size: .small, relativeTo: .compound.bodyMD)
.foregroundColor(Color.compound.iconSecondaryAlpha)
.accessibilityHidden(true)
content
}
.frame(maxWidth: .infinity, alignment: .leading)
}
}
.accessibilityElement(children: .contain)
}

private var viewAllButton: some View {
Button { onViewAllButtonTap() } label: {
Text(L10n.Screen.Room.pinnedBannerViewAllButtonTitle)
.font(.compound.bodyMDSemibold)
.foregroundStyle(Color.compound.textPrimary)
.padding(.horizontal, 16)
.padding(.vertical, 5)
}
}

private var content: some View {
VStack(alignment: .leading, spacing: 0) {
Text(bannerIndicatorDescription)
.font(.compound.bodySM)
.foregroundColor(.compound.textActionAccent)
.lineLimit(1)
Text(pinContent)
.font(.compound.bodyMD)
.foregroundColor(.compound.textPrimary)
.lineLimit(1)
}
}
}

struct PinnedItemsBannerView_Previews: PreviewProvider, TestablePreview {
static var previews: some View {
PinnedItemsBannerView(pinIndex: 0,
pinsCount: 3,
pinContent: .init(stringLiteral: "Content"),
onMainButtonTap: { },
onViewAllButtonTap: { })
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
//
// Copyright 2024 New Vector Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

import Compound
import SwiftUI

struct PinnedItemsIndicatorView: View {
let pinIndex: Int
let pinsCount: Int

private var activeIndex: Int {
pinIndex % 3
}

private var shownIndicators: Int {
if pinsCount <= 3 {
return pinsCount
}
let remainingPins = pinsCount - pinIndex
return remainingPins >= 3 ? 3 : pinsCount % 3
}

var body: some View {
VStack(spacing: 2) {
ForEach(0..<3, id: \.self) { index in
Rectangle()
.fill(index == activeIndex ? Color.compound.iconAccentPrimary : Color.compound._borderInteractiveSecondaryAlpha)
.scaledFrame(width: 2, height: 11)
.opacity(index < shownIndicators ? 1 : 0)
}
}
}
}

struct PinnedItemsIndicatorView_Previews: PreviewProvider, TestablePreview {
static var previews: some View {
HStack(spacing: 10) {
PinnedItemsIndicatorView(pinIndex: 0, pinsCount: 1)
PinnedItemsIndicatorView(pinIndex: 0, pinsCount: 2)
PinnedItemsIndicatorView(pinIndex: 1, pinsCount: 2)
PinnedItemsIndicatorView(pinIndex: 0, pinsCount: 3)
PinnedItemsIndicatorView(pinIndex: 1, pinsCount: 3)
PinnedItemsIndicatorView(pinIndex: 2, pinsCount: 3)
PinnedItemsIndicatorView(pinIndex: 0, pinsCount: 5)
PinnedItemsIndicatorView(pinIndex: 1, pinsCount: 5)
PinnedItemsIndicatorView(pinIndex: 2, pinsCount: 5)
PinnedItemsIndicatorView(pinIndex: 3, pinsCount: 5)
PinnedItemsIndicatorView(pinIndex: 4, pinsCount: 5)
PinnedItemsIndicatorView(pinIndex: 3, pinsCount: 4)
}
.previewLayout(.sizeThatFits)
}
}
10 changes: 10 additions & 0 deletions ElementX/Sources/Screens/RoomScreen/View/RoomScreen.swift
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,16 @@ struct RoomScreen: View {
.environmentObject(context)
.environment(\.roomContext, context)
}
.overlay(alignment: .top) {
if context.viewState.isPinningEnabled {
// TODO: Implement tapping logic + hiding when scrolling
PinnedItemsBannerView(pinIndex: 1,
pinsCount: 3,
pinContent: .init(stringLiteral: "Content"),
onMainButtonTap: { },
onViewAllButtonTap: { })
}
}
.navigationTitle(L10n.screenRoomTitle) // Hidden but used for back button text.
.navigationBarTitleDisplayMode(.inline)
.navigationBarHidden(isNavigationBarHidden)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ struct DeveloperOptionsScreen: View {
Section("Message Pinning") {
Toggle(isOn: $context.pinningEnabled) {
Text("Enable message pinning")
Text("WIP - uses mocked content")
}
}

Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 5cb44ee

Please sign in to comment.