Timeline Reactions: Emoji picker (#350)

* Screens template

* Loading and parsing

* Gridview

* New json

* Search method

* Unit tests

* Added emoji provider state

* Removed containsIgnoringCase

* Added plus icon, added double tap gesture, dismiss sheet after selecting emoji

* Renamed EmojisProvider to EmojiProvider

* Renamed EmojiPickerScreenScreen

* Extra padding

* Renamed EmojisLoaderProtocol

* Category names

* Moved method into public section of the class

* Return all categories when search string is empty

* Added cancel button and tittle

* Removed empty lines

* Removed swiftlint warning
This commit is contained in:
Aleksandrs Proskurins
2022-12-06 16:04:48 +02:00
committed by GitHub
parent dcedb3fb98
commit 7f91852291
30 changed files with 30941 additions and 21 deletions
@@ -19,6 +19,7 @@ import SwiftUI
struct RoomScreen: View {
@ObservedObject private var settings = ElementSettings.shared
@ObservedObject var context: RoomScreenViewModel.Context
@State private var showReactionsMenuForItemId = ""
var body: some View {
timeline
@@ -0,0 +1,51 @@
//
// Copyright 2022 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 SwiftUI
struct TimelineItemReactionsMenuView: View {
private let emojis = ["👍🏼", "👎🏼", "😄", "🙏🏼", "😇"]
var onDisplayEmojiPicker: (() -> Void)?
var body: some View {
HStack {
HStack(spacing: 10) {
ForEach(emojis, id: \.self) { emoji in
Text(emoji)
}
}
.padding(10)
.background(.gray)
.cornerRadius(15)
HStack(spacing: 10) {
Text("➕")
}
.padding(10)
.background(.gray)
.cornerRadius(15)
.onTapGesture {
onDisplayEmojiPicker?()
}
}
}
}
struct TimelineItemReactionsMenuView_Previews: PreviewProvider {
static var previews: some View {
TimelineItemReactionsMenuView(onDisplayEmojiPicker: nil)
}
}
@@ -102,6 +102,12 @@ struct TimelineTableView: UIViewRepresentable {
}
}
var displayReactionsMenuForItemId = "" {
didSet {
tableView?.reloadData()
}
}
/// The table's diffable data source.
private var dataSource: UITableViewDiffableDataSource<TimelineSection, RoomTimelineViewProvider>?
private var cancellables: Set<AnyCancellable> = []
@@ -175,25 +181,35 @@ struct TimelineTableView: UIViewRepresentable {
cell.item = timelineItem
cell.contentConfiguration = UIHostingConfiguration {
timelineItem
.frame(maxWidth: .infinity, alignment: .leading)
.opacity(viewModelContext.viewState.opacity(for: timelineItem))
.contextMenu {
viewModelContext.viewState.contextMenuBuilder?(timelineItem.id)
}
.onAppear {
viewModelContext.send(viewAction: .itemAppeared(id: timelineItem.id))
}
.onDisappear {
viewModelContext.send(viewAction: .itemDisappeared(id: timelineItem.id))
}
.environment(\.openURL, OpenURLAction { url in
viewModelContext.send(viewAction: .linkClicked(url: url))
return .systemAction
})
.onTapGesture {
viewModelContext.send(viewAction: .itemTapped(id: timelineItem.id))
VStack {
if viewModelContext.viewState.displayReactionsMenuForItemId == timelineItem.id {
TimelineItemReactionsMenuView {
viewModelContext.send(viewAction: .displayEmojiPicker(itemId: timelineItem.id))
}
}
timelineItem
.frame(maxWidth: .infinity, alignment: .leading)
.opacity(viewModelContext.viewState.opacity(for: timelineItem))
.contextMenu {
viewModelContext.viewState.contextMenuBuilder?(timelineItem.id)
}
.onAppear {
viewModelContext.send(viewAction: .itemAppeared(id: timelineItem.id))
}
.onDisappear {
viewModelContext.send(viewAction: .itemDisappeared(id: timelineItem.id))
}
.environment(\.openURL, OpenURLAction { url in
viewModelContext.send(viewAction: .linkClicked(url: url))
return .systemAction
})
.onTapGesture(count: 2) {
viewModelContext.send(viewAction: .displayReactionsMenuForItemId(itemId: timelineItem.id))
}
.onTapGesture {
viewModelContext.send(viewAction: .itemTapped(id: timelineItem.id))
}
}
}
.margins(.all, self.timelineStyle.rowInsets)
.minSize(height: 1)
@@ -240,6 +256,9 @@ struct TimelineTableView: UIViewRepresentable {
if composerMode != viewModelContext.viewState.composerMode {
composerMode = viewModelContext.viewState.composerMode
}
if displayReactionsMenuForItemId != viewModelContext.viewState.displayReactionsMenuForItemId {
displayReactionsMenuForItemId = viewModelContext.viewState.displayReactionsMenuForItemId
}
}
/// Updates the table view with the latest items from the ``timelineItems`` array. After