-
Notifications
You must be signed in to change notification settings - Fork 259
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Initial (not completed) implementation of CoinPage module in SwiftUI
- Loading branch information
Showing
9 changed files
with
251 additions
and
30 deletions.
There are no files selected for viewing
24 changes: 24 additions & 0 deletions
24
UnstoppableWallet/UnstoppableWallet.xcodeproj/project.pbxproj
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
23 changes: 19 additions & 4 deletions
23
UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinMarkets/CoinMarketsModule.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,19 +1,34 @@ | ||
import UIKit | ||
import MarketKit | ||
import SwiftUI | ||
import UIKit | ||
|
||
struct CoinMarketsModule { | ||
static func view(coin: Coin) -> some View { | ||
CoinMarketsView(coin: coin) | ||
} | ||
|
||
static func viewController(coin: Coin) -> CoinMarketsViewController { | ||
let service = CoinMarketsService( | ||
coin: coin, | ||
marketKit: App.shared.marketKit, | ||
currencyKit: App.shared.currencyKit | ||
coin: coin, | ||
marketKit: App.shared.marketKit, | ||
currencyKit: App.shared.currencyKit | ||
) | ||
|
||
let viewModel = CoinMarketsViewModel(service: service) | ||
let headerViewModel = MarketSingleSortHeaderViewModel(service: service, decorator: viewModel) | ||
|
||
return CoinMarketsViewController(viewModel: viewModel, headerViewModel: headerViewModel, urlManager: UrlManager(inApp: false)) | ||
} | ||
} | ||
|
||
struct CoinMarketsView: UIViewControllerRepresentable { | ||
typealias UIViewControllerType = UIViewController | ||
|
||
let coin: Coin | ||
|
||
func makeUIViewController(context _: Context) -> UIViewController { | ||
CoinMarketsModule.viewController(coin: coin) | ||
} | ||
|
||
func updateUIViewController(_: UIViewController, context _: Context) {} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
68 changes: 68 additions & 0 deletions
68
UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinPageView.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
import SwiftUI | ||
|
||
struct CoinPageView<Overview: View, Analytics: View, Markets: View>: View { | ||
@ObservedObject var viewModel: CoinPageViewModelNew | ||
|
||
@ViewBuilder let overviewView: Overview | ||
@ViewBuilder let analyticsView: Analytics | ||
@ViewBuilder let marketsView: Markets | ||
|
||
@Environment(\.presentationMode) private var presentationMode | ||
@State private var currentTabIndex: Int = Tab.overview.rawValue | ||
|
||
var body: some View { | ||
ThemeNavigationView { | ||
ThemeView { | ||
VStack(spacing: 0) { | ||
TabHeaderView( | ||
tabs: Tab.allCases.map { $0.title }, | ||
currentTabIndex: $currentTabIndex | ||
) | ||
|
||
TabView(selection: $currentTabIndex) { | ||
overviewView.tag(Tab.overview.rawValue) | ||
analyticsView.tag(Tab.analytics.rawValue) | ||
marketsView.tag(Tab.markets.rawValue) | ||
} | ||
.tabViewStyle(.page(indexDisplayMode: .never)) | ||
.ignoresSafeArea(edges: .bottom) | ||
} | ||
} | ||
.navigationTitle(viewModel.fullCoin.coin.code) | ||
.navigationBarTitleDisplayMode(.large) | ||
.toolbar { | ||
ToolbarItem(placement: .navigationBarLeading) { | ||
Button("button.close".localized) { | ||
presentationMode.wrappedValue.dismiss() | ||
} | ||
} | ||
|
||
ToolbarItem(placement: .navigationBarTrailing) { | ||
Button(action: { | ||
viewModel.isFavorite.toggle() | ||
}) { | ||
Image(viewModel.isFavorite ? "filled_star_24" : "star_24") | ||
.renderingMode(.template) | ||
.foregroundColor(viewModel.isFavorite ? .themeJacob : .themeGray) | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
||
extension CoinPageView { | ||
enum Tab: Int, CaseIterable { | ||
case overview | ||
case analytics | ||
case markets | ||
|
||
var title: String { | ||
switch self { | ||
case .overview: return "coin_page.overview".localized | ||
case .analytics: return "coin_page.analytics".localized | ||
case .markets: return "coin_page.markets".localized | ||
} | ||
} | ||
} | ||
} |
24 changes: 24 additions & 0 deletions
24
UnstoppableWallet/UnstoppableWallet/Modules/Coin/CoinPageViewModelNew.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
import Combine | ||
import MarketKit | ||
|
||
class CoinPageViewModelNew: ObservableObject { | ||
let fullCoin: FullCoin | ||
private let favoritesManager: FavoritesManager | ||
|
||
@Published var isFavorite: Bool { | ||
didSet { | ||
if isFavorite { | ||
favoritesManager.add(coinUid: fullCoin.coin.uid) | ||
} else { | ||
favoritesManager.remove(coinUid: fullCoin.coin.uid) | ||
} | ||
} | ||
} | ||
|
||
init(fullCoin: FullCoin, favoritesManager: FavoritesManager) { | ||
self.fullCoin = fullCoin | ||
self.favoritesManager = favoritesManager | ||
|
||
isFavorite = favoritesManager.isFavorite(coinUid: fullCoin.coin.uid) | ||
} | ||
} |
13 changes: 13 additions & 0 deletions
13
UnstoppableWallet/UnstoppableWallet/UserInterface/TabButtonStyle.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
import SwiftUI | ||
|
||
struct TabButtonStyle: ButtonStyle { | ||
let isActive: Bool | ||
|
||
func makeBody(configuration: Configuration) -> some View { | ||
configuration.label | ||
.frame(maxWidth: .infinity, maxHeight: .infinity) | ||
.font(.themeSubhead1) | ||
.foregroundColor(isActive ? .themeLeah : .themeGray) | ||
.contentShape(Rectangle()) | ||
} | ||
} |
48 changes: 48 additions & 0 deletions
48
UnstoppableWallet/UnstoppableWallet/UserInterface/TabHeaderView.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
import SwiftUI | ||
|
||
struct TabHeaderView: View { | ||
let tabs: [String] | ||
|
||
@Binding var currentTabIndex: Int | ||
@State private var offset: CGFloat = 0 | ||
|
||
var body: some View { | ||
ZStack(alignment: .bottom) { | ||
Rectangle() | ||
.fill(Color.themeSteel10) | ||
.frame(maxWidth: .infinity) | ||
.frame(height: 1) | ||
|
||
ZStack(alignment: .bottom) { | ||
HStack(spacing: 0) { | ||
ForEach(tabs.indices, id: \.self) { index in | ||
Button(action: { | ||
currentTabIndex = index | ||
}) { | ||
Text(tabs[index]) | ||
} | ||
.buttonStyle(TabButtonStyle(isActive: index == currentTabIndex)) | ||
} | ||
} | ||
.frame(maxWidth: .infinity) | ||
|
||
GeometryReader { geo in | ||
RoundedRectangle(cornerRadius: 2, style: .continuous) | ||
.fill(Color.themeJacob) | ||
.frame(height: 4) | ||
.frame(width: geo.size.width / CGFloat(tabs.count)) | ||
.offset(x: offset, y: 0) | ||
.onChange(of: currentTabIndex) { index in | ||
withAnimation(.spring().speed(1.5)) { | ||
offset = geo.size.width / CGFloat(tabs.count) * CGFloat(index) | ||
} | ||
} | ||
} | ||
.frame(height: 2) | ||
} | ||
.padding(.horizontal, .margin12) | ||
} | ||
.frame(height: 44) | ||
.clipped() | ||
} | ||
} |