Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Chat] Showcase app UI #293 #317

Merged
merged 3 commits into from
Jul 8, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions Example/ExampleApp.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@
A5629AE02876CC6E00094373 /* InviteListRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5629ADB2876CC6E00094373 /* InviteListRouter.swift */; };
A5629AE12876CC6E00094373 /* InviteListInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5629ADC2876CC6E00094373 /* InviteListInteractor.swift */; };
A5629AE22876CC6E00094373 /* InviteListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5629ADD2876CC6E00094373 /* InviteListView.swift */; };
A5629AE42876E6D200094373 /* ThreadViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5629AE32876E6D200094373 /* ThreadViewModel.swift */; };
A5629AE828772A0100094373 /* InviteViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5629AE728772A0100094373 /* InviteViewModel.swift */; };
A578FA322873036400AA7720 /* InputView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A578FA312873036400AA7720 /* InputView.swift */; };
A578FA35287304A300AA7720 /* Color.swift in Sources */ = {isa = PBXBuildFile; fileRef = A578FA34287304A300AA7720 /* Color.swift */; };
A578FA372873D8EE00AA7720 /* UIColor.swift in Sources */ = {isa = PBXBuildFile; fileRef = A578FA362873D8EE00AA7720 /* UIColor.swift */; };
Expand Down Expand Up @@ -195,6 +197,8 @@
A5629ADB2876CC6E00094373 /* InviteListRouter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InviteListRouter.swift; sourceTree = "<group>"; };
A5629ADC2876CC6E00094373 /* InviteListInteractor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InviteListInteractor.swift; sourceTree = "<group>"; };
A5629ADD2876CC6E00094373 /* InviteListView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InviteListView.swift; sourceTree = "<group>"; };
A5629AE32876E6D200094373 /* ThreadViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThreadViewModel.swift; sourceTree = "<group>"; };
A5629AE728772A0100094373 /* InviteViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InviteViewModel.swift; sourceTree = "<group>"; };
A578FA312873036400AA7720 /* InputView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InputView.swift; sourceTree = "<group>"; };
A578FA34287304A300AA7720 /* Color.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Color.swift; sourceTree = "<group>"; };
A578FA362873D8EE00AA7720 /* UIColor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIColor.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -474,6 +478,7 @@
A5629AB72876CBA700094373 /* ChatList */ = {
isa = PBXGroup;
children = (
A5629AE5287729EF00094373 /* Models */,
A5629AB82876CBC000094373 /* ChatListModule.swift */,
A5629AB92876CBC000094373 /* ChatListPresenter.swift */,
A5629ABA2876CBC000094373 /* ChatListRouter.swift */,
Expand All @@ -498,6 +503,7 @@
A5629AD82876CC5B00094373 /* InviteList */ = {
isa = PBXGroup;
children = (
A5629AE6287729F800094373 /* Models */,
A5629AD92876CC6E00094373 /* InviteListModule.swift */,
A5629ADA2876CC6E00094373 /* InviteListPresenter.swift */,
A5629ADB2876CC6E00094373 /* InviteListRouter.swift */,
Expand All @@ -507,6 +513,22 @@
path = InviteList;
sourceTree = "<group>";
};
A5629AE5287729EF00094373 /* Models */ = {
isa = PBXGroup;
children = (
A5629AE32876E6D200094373 /* ThreadViewModel.swift */,
);
path = Models;
sourceTree = "<group>";
};
A5629AE6287729F800094373 /* Models */ = {
isa = PBXGroup;
children = (
A5629AE728772A0100094373 /* InviteViewModel.swift */,
);
path = Models;
sourceTree = "<group>";
};
A578FA332873049400AA7720 /* Style */ = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -1042,12 +1064,14 @@
A578FA35287304A300AA7720 /* Color.swift in Sources */,
A5629ADE2876CC6E00094373 /* InviteListModule.swift in Sources */,
A578FA322873036400AA7720 /* InputView.swift in Sources */,
A5629AE42876E6D200094373 /* ThreadViewModel.swift in Sources */,
A58E7D0C2872A45B0082D443 /* MainModule.swift in Sources */,
A58E7D0D2872A45B0082D443 /* MainPresenter.swift in Sources */,
A5629AD62876CC5700094373 /* InviteInteractor.swift in Sources */,
A5629AE12876CC6E00094373 /* InviteListInteractor.swift in Sources */,
A58E7CED28729F550082D443 /* SceneDelegate.swift in Sources */,
A578FA372873D8EE00AA7720 /* UIColor.swift in Sources */,
A5629AE828772A0100094373 /* InviteViewModel.swift in Sources */,
A5629AA92876A23100094373 /* ChatService.swift in Sources */,
A5629AC02876CBC000094373 /* ChatListInteractor.swift in Sources */,
A5629AE22876CC6E00094373 /* InviteListView.swift in Sources */,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,14 @@ import UIKit
struct AppearanceConfigurator: Configurator {

func configure() {
let appearance = UINavigationBarAppearance()
appearance.titleTextAttributes = [
.foregroundColor: UIColor.w_foreground
]

UINavigationBar.appearance().standardAppearance = appearance
UINavigationBar.appearance().scrollEdgeAppearance = appearance
UINavigationBar.appearance().compactAppearance = appearance

}
}
42 changes: 36 additions & 6 deletions Example/Showcase/Classes/DomainLayer/ChatService.swift
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import Foundation
import Combine

typealias MessageStream = AsyncPublisher<AnyPublisher<[Message], Never>>
typealias Stream<T> = AsyncPublisher<AnyPublisher<T, Never>>

final class ChatService {

static let authorAccount: String = "TODO"

private let messagesSubject: CurrentValueSubject<[Message], Never> = {
return CurrentValueSubject([
Message(message: "✨gm", authorAccount: "2", timestamp: 0),
Expand All @@ -19,21 +21,49 @@ final class ChatService {
])
}()

func getMessages(topic: String) -> MessageStream {
private let threadsSubject: CurrentValueSubject<[Thread], Never> = {
return CurrentValueSubject([
Thread(topic: "topic1"),
Thread(topic: "topic2")
])
}()

private let invitesSubject: CurrentValueSubject<[Invite], Never> = {
return CurrentValueSubject([
Invite(message: "In a few minutes, bitch.", pubKey: "slava.eth")
])
}()

func getMessages(topic: String) -> Stream<[Message]> {
return messagesSubject.eraseToAnyPublisher().values
}

func getAuthorAccount() async -> String {
return "1"
func getThreads() -> Stream<[Thread]> {
return threadsSubject.eraseToAnyPublisher().values
}

func getInvites() -> Stream<[Invite]> {
return invitesSubject.eraseToAnyPublisher().values
}

func sendMessage(text: String) async throws {
let authorAccount = await getAuthorAccount()
let message = Message(
message: text,
authorAccount: authorAccount,
authorAccount: ChatService.authorAccount,
timestamp: Int64(Date().timeIntervalSince1970)
)
messagesSubject.send(messagesSubject.value + [message])
}

func accept(invite: Invite) async throws {

}

func reject(invite: Invite) async throws {

}

func invite(account: String) async throws {

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,7 @@ final class ChatInteractor {
self.chatService = chatService
}

func getCurrentAccount() async -> String {
return await chatService.getAuthorAccount()
}

func getMessages(topic: String) -> MessageStream {
func getMessages(topic: String) -> Stream<[Message]> {
return chatService.getMessages(topic: topic)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ import SwiftUI
final class ChatModule {

@discardableResult
static func create(app: Application) -> UIViewController {
static func create(topic: String, app: Application) -> UIViewController {
let router = ChatRouter(app: app)
let interactor = ChatInteractor(chatService: app.chatService)
let presenter = ChatPresenter(topic: "", interactor: interactor, router: router)
let presenter = ChatPresenter(topic: topic, interactor: interactor, router: router)
let view = ChatView().environmentObject(presenter)
let viewController = SceneViewController(viewModel: presenter, content: view)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,10 @@ final class ChatPresenter: ObservableObject {

@MainActor
func setupInitialState() async {
let account = await interactor.getCurrentAccount()

for await messages in interactor.getMessages(topic: topic) {
self.messages = messages
.sorted(by: { $0.timestamp < $1.timestamp })
.map { MessageViewModel(message: $0, currentAccount: account) }
.map { MessageViewModel(message: $0, currentAccount: "TODO") }
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import Foundation

// TODO: After Chat SDK integration
// TODO: Delete after Chat SDK integration
struct Message: Codable, Equatable {
let message: String
let authorAccount: String
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
final class ChatListInteractor {

private let chatService: ChatService

init(chatService: ChatService) {
self.chatService = chatService
}

func getThreads() -> Stream<[Thread]> {
return chatService.getThreads()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ final class ChatListModule {
@discardableResult
static func create(app: Application) -> UIViewController {
let router = ChatListRouter(app: app)
let interactor = ChatListInteractor()
let interactor = ChatListInteractor(chatService: app.chatService)
let presenter = ChatListPresenter(interactor: interactor, router: router)
let view = ChatListView().environmentObject(presenter)
let viewController = SceneViewController(viewModel: presenter, content: view)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,24 @@ final class ChatListPresenter: ObservableObject {
private let router: ChatListRouter
private var disposeBag = Set<AnyCancellable>()

@Published var threads: [ThreadViewModel] = []

init(interactor: ChatListInteractor, router: ChatListRouter) {
self.interactor = interactor
self.router = router
}

@MainActor
func setupInitialState() async {
for await threads in interactor.getThreads() {
self.threads = threads
.sorted(by: { $0.topic < $1.topic })
.map { ThreadViewModel(thread: $0) }
}
}

func didPressThread(_ thread: ThreadViewModel) {
router.presentChat(topic: thread.topic)
}

func didPressChatRequests() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,16 @@ final class ChatListRouter {
}

func presentInvite() {
InviteModule.create(app: app).push(from: viewController)
InviteModule.create(app: app)
.wrapToNavigationController()
.present(from: viewController)
}

func presentInviteList() {
InviteListModule.create(app: app).push(from: viewController)
}

func presentChat(topic: String) {
ChatModule.create(topic: topic, app: app).push(from: viewController)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,55 @@ struct ChatListView: View {
@EnvironmentObject var presenter: ChatListPresenter

var body: some View {
VStack {
Spacer()
ScrollView {
VStack {
Button(action: {
presenter.didPressChatRequests()
}) {
HStack(spacing: 8.0) {
Text("1")
.frame(width: 24.0, height: 24.0)
.background(Color.w_greenForground)
.foregroundColor(.w_greenBackground)
.font(.system(size: 17.0, weight: .bold))
.clipShape(Circle())

Button("Chat Requests") {
presenter.didPressChatRequests()
Text("Chat Requests")
.foregroundColor(.w_greenForground)
.font(.system(size: 17.0, weight: .bold))
}
}
.frame(height: 44.0)
.frame(maxWidth: .infinity)
.background(Color.w_greenBackground)
.clipShape(Capsule())
.padding(16.0)

ForEach(presenter.threads) { thread in
Button(action: {
presenter.didPressThread(thread)
}) {
HStack(spacing: 16.0) {
Image("avatar")
.resizable()
.frame(width: 64.0, height: 64.0)

VStack(alignment: .leading) {
Text(thread.title)
.font(.title3)
.foregroundColor(.w_foreground)
.lineLimit(1)

Text(thread.subtitle)
.font(.subheadline)
.foregroundColor(.w_secondaryForeground)
.multilineTextAlignment(.leading)
}
}
.frame(height: 64.0)
}
}
.padding(16.0)
}
}
.task {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import Foundation

// TODO: Delete after Chat SDK integration
struct Thread: Codable {
let topic: String
}

struct ThreadViewModel: Identifiable {
private let thread: Thread

init(thread: Thread) {
self.thread = thread
}

var topic: String {
return thread.topic
}

var id: String {
return thread.topic
}

var title: String {
return thread.topic
}

var subtitle: String {
return "Chicken, Peter, you’re just a little chicken. Cheep, cheep, cheep, cheep…"
}
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
final class InviteInteractor {
private let chatService: ChatService

init(chatService: ChatService) {
self.chatService = chatService
}

func invite(account: String) async {
try! await chatService.invite(account: account)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ final class InviteModule {
@discardableResult
static func create(app: Application) -> UIViewController {
let router = InviteRouter(app: app)
let interactor = InviteInteractor()
let interactor = InviteInteractor(chatService: app.chatService)
let presenter = InvitePresenter(interactor: interactor, router: router)
let view = InviteView().environmentObject(presenter)
let viewController = SceneViewController(viewModel: presenter, content: view)
Expand Down
Loading