mirror of
https://github.com/vector-im/element-ios.git
synced 2024-09-29 07:42:40 +00:00
Create UserSessionsOverview screen.
This commit is contained in:
parent
2f2bc831e0
commit
3e30a19dcd
5 changed files with 178 additions and 12 deletions
|
@ -31,6 +31,9 @@ final class UserSessionsOverviewCoordinator: Coordinator, Presentable {
|
||||||
private let userSessionsOverviewHostingController: UIViewController
|
private let userSessionsOverviewHostingController: UIViewController
|
||||||
private var userSessionsOverviewViewModel: UserSessionsOverviewViewModelProtocol
|
private var userSessionsOverviewViewModel: UserSessionsOverviewViewModelProtocol
|
||||||
|
|
||||||
|
private var indicatorPresenter: UserIndicatorTypePresenterProtocol
|
||||||
|
private var loadingIndicator: UserIndicator?
|
||||||
|
|
||||||
// MARK: Public
|
// MARK: Public
|
||||||
|
|
||||||
// Must be used only internally
|
// Must be used only internally
|
||||||
|
@ -41,10 +44,15 @@ final class UserSessionsOverviewCoordinator: Coordinator, Presentable {
|
||||||
|
|
||||||
init(parameters: UserSessionsOverviewCoordinatorParameters) {
|
init(parameters: UserSessionsOverviewCoordinatorParameters) {
|
||||||
self.parameters = parameters
|
self.parameters = parameters
|
||||||
let viewModel = UserSessionsOverviewViewModel(userSessionsOverviewService: UserSessionsOverviewService())
|
let viewModel = UserSessionsOverviewViewModel(userSessionsOverviewService: UserSessionsOverviewService(mxSession: parameters.session))
|
||||||
let view = UserSessionsOverview(viewModel: viewModel.context)
|
let view = UserSessionsOverview(viewModel: viewModel.context)
|
||||||
userSessionsOverviewViewModel = viewModel
|
userSessionsOverviewViewModel = viewModel
|
||||||
userSessionsOverviewHostingController = VectorHostingController(rootView: view)
|
|
||||||
|
let hostingViewController = VectorHostingController(rootView: view)
|
||||||
|
|
||||||
|
userSessionsOverviewHostingController = hostingViewController
|
||||||
|
|
||||||
|
indicatorPresenter = UserIndicatorTypePresenter(presentingViewController: hostingViewController)
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Public
|
// MARK: - Public
|
||||||
|
@ -55,8 +63,22 @@ final class UserSessionsOverviewCoordinator: Coordinator, Presentable {
|
||||||
guard let self = self else { return }
|
guard let self = self else { return }
|
||||||
MXLog.debug("[UserSessionsOverviewCoordinator] UserSessionsOverviewViewModel did complete with result: \(result).")
|
MXLog.debug("[UserSessionsOverviewCoordinator] UserSessionsOverviewViewModel did complete with result: \(result).")
|
||||||
switch result {
|
switch result {
|
||||||
case .done:
|
case .cancel:
|
||||||
self.completion?()
|
self.completion?()
|
||||||
|
case .loadData:
|
||||||
|
self.loadData()
|
||||||
|
case .showAllUnverifiedSessions:
|
||||||
|
self.showAllUnverifiedSessions()
|
||||||
|
case .showAllInactiveSessions:
|
||||||
|
self.showAllInactiveSessions()
|
||||||
|
case .verifyCurrentSession:
|
||||||
|
self.startVerifyCurrentSession()
|
||||||
|
case .showCurrentSessionDetails:
|
||||||
|
self.showCurrentSessionDetails()
|
||||||
|
case .showAllOtherSessions:
|
||||||
|
self.showAllOtherSessions()
|
||||||
|
case .showUserSessionDetails(let sessionId):
|
||||||
|
self.showUserSessionDetails(sessionId: sessionId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -64,4 +86,47 @@ final class UserSessionsOverviewCoordinator: Coordinator, Presentable {
|
||||||
func toPresentable() -> UIViewController {
|
func toPresentable() -> UIViewController {
|
||||||
return self.userSessionsOverviewHostingController
|
return self.userSessionsOverviewHostingController
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MARK: - Private
|
||||||
|
|
||||||
|
/// Show an activity indicator whilst loading.
|
||||||
|
/// - Parameters:
|
||||||
|
/// - label: The label to show on the indicator.
|
||||||
|
/// - isInteractionBlocking: Whether the indicator should block any user interaction.
|
||||||
|
private func startLoading(label: String = VectorL10n.loading, isInteractionBlocking: Bool = true) {
|
||||||
|
loadingIndicator = indicatorPresenter.present(.loading(label: label, isInteractionBlocking: isInteractionBlocking))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Hide the currently displayed activity indicator.
|
||||||
|
private func stopLoading() {
|
||||||
|
loadingIndicator = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
private func loadData() {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
private func showAllUnverifiedSessions() {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
private func showAllInactiveSessions() {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
private func startVerifyCurrentSession() {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
private func showCurrentSessionDetails() {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
private func showUserSessionDetails(sessionId: String) {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
private func showAllOtherSessions() {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,18 +21,37 @@ import Foundation
|
||||||
// MARK: View model
|
// MARK: View model
|
||||||
|
|
||||||
enum UserSessionsOverviewViewModelResult {
|
enum UserSessionsOverviewViewModelResult {
|
||||||
case done
|
case cancel
|
||||||
|
case loadData
|
||||||
|
case showAllUnverifiedSessions
|
||||||
|
case showAllInactiveSessions
|
||||||
|
case verifyCurrentSession
|
||||||
|
case showCurrentSessionDetails
|
||||||
|
case showAllOtherSessions
|
||||||
|
case showUserSessionDetails(_ sessionId: String)
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: View
|
// MARK: View
|
||||||
|
|
||||||
struct UserSessionsOverviewViewState: BindableState {
|
struct UserSessionsOverviewViewState: BindableState {
|
||||||
|
|
||||||
|
var unverifiedSessionsViewData: [UserSessionListItemViewData]
|
||||||
|
|
||||||
|
var inactiveSessionsViewData: [UserSessionListItemViewData]
|
||||||
|
|
||||||
|
var currentSessionViewData: UserSessionListItemViewData?
|
||||||
|
|
||||||
|
var otherSessionsViewData: [UserSessionListItemViewData]
|
||||||
|
|
||||||
|
var showLoadingIndicator: Bool = false
|
||||||
}
|
}
|
||||||
|
|
||||||
enum UserSessionsOverviewViewAction {
|
enum UserSessionsOverviewViewAction {
|
||||||
|
case viewAppeared
|
||||||
case verifyCurrentSession
|
case verifyCurrentSession
|
||||||
case viewCurrentSessionDetails
|
case viewCurrentSessionDetails
|
||||||
case viewAllUnverifiedSessions
|
case viewAllUnverifiedSessions
|
||||||
case viewAllInactiveSessions
|
case viewAllInactiveSessions
|
||||||
case viewAllOtherSessions
|
case viewAllOtherSessions
|
||||||
|
case tapUserSession(_ sessionId: String)
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,25 +37,80 @@ class UserSessionsOverviewViewModel: UserSessionsOverviewViewModelType, UserSess
|
||||||
init(userSessionsOverviewService: UserSessionsOverviewServiceProtocol) {
|
init(userSessionsOverviewService: UserSessionsOverviewServiceProtocol) {
|
||||||
self.userSessionsOverviewService = userSessionsOverviewService
|
self.userSessionsOverviewService = userSessionsOverviewService
|
||||||
|
|
||||||
let viewState = UserSessionsOverviewViewState()
|
let viewState = UserSessionsOverviewViewState(unverifiedSessionsViewData: [], inactiveSessionsViewData: [], currentSessionViewData: nil, otherSessionsViewData: [])
|
||||||
|
|
||||||
super.init(initialViewState: viewState)
|
super.init(initialViewState: viewState)
|
||||||
|
|
||||||
|
self.updateViewState(with: userSessionsOverviewService.lastOverviewData)
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Public
|
// MARK: - Public
|
||||||
|
|
||||||
override func process(viewAction: UserSessionsOverviewViewAction) {
|
override func process(viewAction: UserSessionsOverviewViewAction) {
|
||||||
switch viewAction {
|
switch viewAction {
|
||||||
|
case .viewAppeared:
|
||||||
|
self.loadData()
|
||||||
case .verifyCurrentSession:
|
case .verifyCurrentSession:
|
||||||
break
|
self.completion?(.verifyCurrentSession)
|
||||||
case .viewCurrentSessionDetails:
|
case .viewCurrentSessionDetails:
|
||||||
break
|
self.completion?(.showCurrentSessionDetails)
|
||||||
case .viewAllUnverifiedSessions:
|
case .viewAllUnverifiedSessions:
|
||||||
break
|
self.completion?(.showAllUnverifiedSessions)
|
||||||
case .viewAllInactiveSessions:
|
case .viewAllInactiveSessions:
|
||||||
break
|
self.completion?(.showAllInactiveSessions)
|
||||||
case .viewAllOtherSessions:
|
case .viewAllOtherSessions:
|
||||||
break
|
self.completion?(.showAllOtherSessions)
|
||||||
|
case .tapUserSession(let sessionId):
|
||||||
|
self.completion?(.showUserSessionDetails(sessionId))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Private
|
||||||
|
|
||||||
|
private func updateViewState(with userSessionsViewData: UserSessionsOverviewData) {
|
||||||
|
|
||||||
|
let unverifiedSessionsViewData = self.userSessionListItemViewDataList(from: userSessionsViewData.unverifiedSessionsInfo)
|
||||||
|
let inactiveSessionsViewData = self.userSessionListItemViewDataList(from: userSessionsViewData.inactiveSessionsInfo)
|
||||||
|
|
||||||
|
var currentSessionViewData: UserSessionListItemViewData?
|
||||||
|
|
||||||
|
let otherSessionsViewData = self.userSessionListItemViewDataList(from: userSessionsViewData.otherSessionsInfo)
|
||||||
|
|
||||||
|
|
||||||
|
if let currentSessionInfo = userSessionsViewData.currentSessionInfo {
|
||||||
|
currentSessionViewData = UserSessionListItemViewData(userSessionInfo: currentSessionInfo)
|
||||||
|
}
|
||||||
|
|
||||||
|
self.state.unverifiedSessionsViewData = unverifiedSessionsViewData
|
||||||
|
self.state.inactiveSessionsViewData = inactiveSessionsViewData
|
||||||
|
self.state.currentSessionViewData = currentSessionViewData
|
||||||
|
self.state.otherSessionsViewData = otherSessionsViewData
|
||||||
|
}
|
||||||
|
|
||||||
|
private func userSessionListItemViewDataList(from userSessionInfoList: [UserSessionInfo]) -> [UserSessionListItemViewData] {
|
||||||
|
return userSessionInfoList.map {
|
||||||
|
return UserSessionListItemViewData(userSessionInfo: $0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func loadData() {
|
||||||
|
|
||||||
|
self.state.showLoadingIndicator = true
|
||||||
|
|
||||||
|
self.userSessionsOverviewService.fetchUserSessionsOverviewData { [weak self] result in
|
||||||
|
guard let self = self else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
self.state.showLoadingIndicator = false
|
||||||
|
|
||||||
|
switch result {
|
||||||
|
case .success(let overViewData):
|
||||||
|
self.updateViewState(with: overViewData)
|
||||||
|
case .failure(let error):
|
||||||
|
// TODO
|
||||||
|
break
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,7 +51,7 @@ struct UserSessionListItem: View {
|
||||||
lastActivityDateString = self.lastActivityDateString(from: lastActivityDate)
|
lastActivityDateString = self.lastActivityDateString(from: lastActivityDate)
|
||||||
}
|
}
|
||||||
|
|
||||||
if let lastActivityDateString = lastActivityDateString {
|
if let lastActivityDateString = lastActivityDateString, lastActivityDateString.isEmpty == false {
|
||||||
sessionDetailsString = VectorL10n.userSessionItemDetails(sessionStatusText, lastActivityDateString)
|
sessionDetailsString = VectorL10n.userSessionItemDetails(sessionStatusText, lastActivityDateString)
|
||||||
} else {
|
} else {
|
||||||
sessionDetailsString = sessionStatusText
|
sessionDetailsString = sessionStatusText
|
||||||
|
|
|
@ -29,11 +29,38 @@ struct UserSessionsOverview: View {
|
||||||
@ObservedObject var viewModel: UserSessionsOverviewViewModel.Context
|
@ObservedObject var viewModel: UserSessionsOverviewViewModel.Context
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
VStack {
|
ScrollView {
|
||||||
|
|
||||||
|
// Security recommendations section
|
||||||
|
if viewModel.viewState.unverifiedSessionsViewData.isEmpty == false || viewModel.viewState.inactiveSessionsViewData.isEmpty == false {
|
||||||
|
|
||||||
|
// TODO:
|
||||||
|
}
|
||||||
|
|
||||||
|
// Current session section
|
||||||
|
if let currentSessionViewData = viewModel.viewState.currentSessionViewData {
|
||||||
|
// TODO:
|
||||||
|
}
|
||||||
|
|
||||||
|
// Other sessions section
|
||||||
|
if viewModel.viewState.otherSessionsViewData.isEmpty == false {
|
||||||
|
|
||||||
|
VStack(spacing: 15) {
|
||||||
|
ForEach(viewModel.viewState.otherSessionsViewData) { viewData in
|
||||||
|
UserSessionListItem(viewData: viewData, onBackgroundTap: { sessionId in
|
||||||
|
viewModel.send(viewAction: .tapUserSession(sessionId))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.background(theme.colors.background)
|
.background(theme.colors.background)
|
||||||
.frame(maxHeight: .infinity)
|
.frame(maxHeight: .infinity)
|
||||||
.navigationTitle(VectorL10n.userSessionsOverviewTitle)
|
.navigationTitle(VectorL10n.userSessionsOverviewTitle)
|
||||||
|
.activityIndicator(show: viewModel.viewState.showLoadingIndicator)
|
||||||
|
.onAppear() {
|
||||||
|
viewModel.send(viewAction: .viewAppeared)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue