Skip to content
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 FakeNFT.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,10 @@
79D0C7562DE3973200D53241 /* TabBarView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 79D0C7552DE3973200D53241 /* TabBarView.swift */; };
79D0C7592DE39C3800D53241 /* NavigationBarStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 79D0C7582DE39C3800D53241 /* NavigationBarStyle.swift */; };
79D0C75D2DE39F5900D53241 /* LoadingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 79D0C75C2DE39F5900D53241 /* LoadingView.swift */; };
79D9E0402DF0316F005D5DB1 /* ShowWebViewButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 79D9E03F2DF0316F005D5DB1 /* ShowWebViewButton.swift */; };
79D9E0422DF03260005D5DB1 /* ShowCollectionButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 79D9E0412DF03260005D5DB1 /* ShowCollectionButton.swift */; };
79D9E0442DF03392005D5DB1 /* UserCardViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 79D9E0432DF03392005D5DB1 /* UserCardViewModel.swift */; };
79D9E0472DF03E41005D5DB1 /* UserCollectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 79D9E0462DF03E41005D5DB1 /* UserCollectionView.swift */; };
E1CD40DC2A96BECC00BE7FE8 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = E1CD40DB2A96BECC00BE7FE8 /* Localizable.strings */; };
/* End PBXBuildFile section */

Expand Down Expand Up @@ -110,6 +114,10 @@
79D0C7552DE3973200D53241 /* TabBarView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabBarView.swift; sourceTree = "<group>"; };
79D0C7582DE39C3800D53241 /* NavigationBarStyle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationBarStyle.swift; sourceTree = "<group>"; };
79D0C75C2DE39F5900D53241 /* LoadingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoadingView.swift; sourceTree = "<group>"; };
79D9E03F2DF0316F005D5DB1 /* ShowWebViewButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShowWebViewButton.swift; sourceTree = "<group>"; };
79D9E0412DF03260005D5DB1 /* ShowCollectionButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShowCollectionButton.swift; sourceTree = "<group>"; };
79D9E0432DF03392005D5DB1 /* UserCardViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = UserCardViewModel.swift; path = FakeNFT/UserCardViewModel.swift; sourceTree = SOURCE_ROOT; };
79D9E0462DF03E41005D5DB1 /* UserCollectionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserCollectionView.swift; sourceTree = "<group>"; };
E1CD40DB2A96BECC00BE7FE8 /* Localizable.strings */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; path = Localizable.strings; sourceTree = "<group>"; };
/* End PBXFileReference section */

Expand Down Expand Up @@ -316,6 +324,7 @@
children = (
793BCC9A2DEF1BC500DF1252 /* RatingView */,
79641C262DEF292A004C970D /* UserCardView */,
79D9E0452DF03E34005D5DB1 /* UserCollectionView */,
79641C192DEF1D63004C970D /* Common */,
);
path = Statistics;
Expand All @@ -335,6 +344,8 @@
79641C1F2DEF1ECB004C970D /* List */,
79641C1A2DEF1DF4004C970D /* Row */,
79641C1D2DEF1E63004C970D /* UserAvatar.swift */,
79D9E03F2DF0316F005D5DB1 /* ShowWebViewButton.swift */,
79D9E0412DF03260005D5DB1 /* ShowCollectionButton.swift */,
);
path = Common;
sourceTree = "<group>";
Expand Down Expand Up @@ -376,6 +387,7 @@
isa = PBXGroup;
children = (
79641C222DEF2081004C970D /* RatingViewModel.swift */,
79D9E0432DF03392005D5DB1 /* UserCardViewModel.swift */,
);
path = ViewModels;
sourceTree = "<group>";
Expand Down Expand Up @@ -420,6 +432,14 @@
path = LoadingView;
sourceTree = "<group>";
};
79D9E0452DF03E34005D5DB1 /* UserCollectionView */ = {
isa = PBXGroup;
children = (
79D9E0462DF03E41005D5DB1 /* UserCollectionView.swift */,
);
path = UserCollectionView;
sourceTree = "<group>";
};
E1CD40DA2A96BE9B00BE7FE8 /* Resources */ = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -582,8 +602,10 @@
79D0C75D2DE39F5900D53241 /* LoadingView.swift in Sources */,
797AAE8A2DEF316100745B0D /* UsersRequest.swift in Sources */,
0CF2C2DD2A783CE600FDC837 /* ErrorView.swift in Sources */,
79D9E0402DF0316F005D5DB1 /* ShowWebViewButton.swift in Sources */,
79641C212DEF1ED7004C970D /* RatingList.swift in Sources */,
5019A4CE2DE1E899009A5AF8 /* FakeNftApp.swift in Sources */,
79D9E0442DF03392005D5DB1 /* UserCardViewModel.swift in Sources */,
79641C1C2DEF1E17004C970D /* RatingRow.swift in Sources */,
79641C282DEF293A004C970D /* UserCardView.swift in Sources */,
0CFCB7402A78002A0009A829 /* ExamplePutService.swift in Sources */,
Expand All @@ -596,8 +618,10 @@
0CFCB74E2A7817DC0009A829 /* NftStorage.swift in Sources */,
3FC8C39129D2453B0081F015 /* ExamplePutRequest.swift in Sources */,
5019A4D02DE1E8E0009A5AF8 /* ContentView.swift in Sources */,
79D9E0422DF03260005D5DB1 /* ShowCollectionButton.swift in Sources */,
79641C232DEF2081004C970D /* RatingViewModel.swift in Sources */,
0C79EE612A76DCD600EE90EA /* NftByIdRequest.swift in Sources */,
79D9E0472DF03E41005D5DB1 /* UserCollectionView.swift in Sources */,
3F6806D329CBBE9600B4F915 /* NetworkRequest.swift in Sources */,
3F6806D129CBBE6B00B4F915 /* NetworkClient.swift in Sources */,
79D0C7562DE3973200D53241 /* TabBarView.swift in Sources */,
Expand Down
12 changes: 6 additions & 6 deletions FakeNFT/Docs/Statistics.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,14 @@
## Модуль 2:

#### Верстка
- Экран информации о пользователе (аватар, имя, описание) (est: 30 минут; fact: x часов).
- Кнопка перехода на сайт пользователя (est: 30 минут; fact: x часов).
- Кнопка перехода на экран коллекции пользователя (est: 30 минут; fact: x часов).
- Создать WebView (est: 1 час; fact: x часов).
- Экран информации о пользователе (аватар, имя, описание) (est: 30 минут; fact: 30 минут).
- Кнопка перехода на сайт пользователя (est: 30 минут; fact: 20 минут).
- Кнопка перехода на экран коллекции пользователя (est: 30 минут; fact: 30 минут).
- Создать WebView (est: 1 час; fact: 1 час).

#### Логика
- Открытие сайта пользователя в WebView (est: 30 минут; fact: x часов).
- Навигация на экран коллекции пользователя (est: 20 минут; fact: x часов).
- Открытие сайта пользователя в WebView (est: 30 минут; fact: 10 минут).
- Навигация на экран коллекции пользователя (est: 20 минут; fact: 15 минут).

## Module 3:

Expand Down
31 changes: 31 additions & 0 deletions FakeNFT/Scenes /Statistics/Common/ShowCollectionButton.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
//
// ShowCollectionButton.swift
// FakeNFT
//
// Created by Anastasia on 04.06.2025.
//

import SwiftUI

struct ShowCollectionButton: View {

let nftsCount: Int

var body: some View {
HStack {
Group {
Text("Коллекция NFT")
Text("(\(nftsCount))")
Spacer()
Image(systemName: "chevron.forward")
}
.font(.bold17)
.foregroundColor(Color.blackDay)
}
.frame(height: StatisticsConstants.buttonHeightLarge)
}
}

#Preview {
ShowCollectionButton(nftsCount: 122)
}
41 changes: 41 additions & 0 deletions FakeNFT/Scenes /Statistics/Common/ShowWebViewButton.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
//
// ShowWebViewButton.swift
// FakeNFT
//
// Created by Anastasia on 04.06.2025.
//

import SwiftUI

struct ShowWebViewButton: View {

let url: String

var body: some View {
NavigationLink(
destination: WebView(url: URL(string: url))
Comment thread
anastkrp marked this conversation as resolved.
.toolbar(.hidden, for: .tabBar)
) {
Text("Перейти на сайт пользователя")
Comment thread
anastkrp marked this conversation as resolved.
.font(.regular15)
.foregroundStyle(Color.blackDay)
.frame(
maxWidth: .infinity,
maxHeight: StatisticsConstants.buttonHeightMedium
)
.background(
RoundedRectangle(cornerRadius: StatisticsConstants.cornerRadiusMedium)
.stroke(
Color.blackDay,
lineWidth: StatisticsConstants.borderLineWidth
)
)
}
}
}

#Preview {
NavigationStack {
ShowWebViewButton(url: "")
}
}
5 changes: 4 additions & 1 deletion FakeNFT/Scenes /Statistics/RatingView/RatingView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,10 @@ struct RatingView: View {
VStack(spacing: .zero) {
RatingList(isLoading: viewModel.isLoading) {
ForEach(viewModel.filteredUsers) { user in
NavigationLink(destination: UserCardView(isTabBarHidden: $isTabBarHidden)) {
NavigationLink(destination: UserCardView(
user: user,
isTabBarHidden: $isTabBarHidden
)) {
RatingRow(user: user)
}
}
Expand Down
80 changes: 67 additions & 13 deletions FakeNFT/Scenes /Statistics/UserCardView/UserCardView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,29 +9,83 @@ import SwiftUI

struct UserCardView: View {

// MARK: - Properties

@Binding var isTabBarHidden: Bool
@ObservedObject var viewModel: UserCardViewModel

// MARK: - Initializers

// TODO: 2/3 Statistics
init(user: User, isTabBarHidden: Binding<Bool>) {
self.viewModel = UserCardViewModel(user: user)
self._isTabBarHidden = isTabBarHidden
}

// MARK: - Content

var body: some View {
VStack {
Text("Hello, World!")
content
.modifier(NavigationBarStyle(
title: nil,
backButtonHidden: false,
filterButtonHidden: true,
isTabBarHidden: $isTabBarHidden,
filterButtonTapHandler: { }
))
.onAppear {
isTabBarHidden = true
}
}

// MARK: - View

private var content: some View {
VStack(alignment: .leading) {
userInfo
Text(viewModel.user.description ?? "")
.font(.footnote)
.foregroundStyle(Color.blackDay)
.padding(.top, StatisticsConstants.topAnchorSmall)
ShowWebViewButton(url: viewModel.user.website)
.padding(.top, StatisticsConstants.topAnchorMedium)
NavigationLink(destination: UserCollectionView()) {
ShowCollectionButton(nftsCount: viewModel.user.nfts.count)
.padding(.top, StatisticsConstants.topAnchorLarge)
}
Spacer()
}
.modifier(NavigationBarStyle(
title: nil,
backButtonHidden: false,
filterButtonHidden: true,
isTabBarHidden: $isTabBarHidden,
filterButtonTapHandler: { }
))
.onAppear {
isTabBarHidden = true
.padding(.top, StatisticsConstants.topAnchorSmall)
.padding(.horizontal)
}

private var userInfo: some View {
HStack(spacing: .zero) {
UserAvatar(
url: viewModel.user.avatar,
size: StatisticsConstants.avatarSizeLarge
)
Text(viewModel.user.name)
.font(.bold22)
.foregroundStyle(Color.blackDay)
.padding(.leading)
.frame(maxWidth: .infinity, alignment: .leading)
}
}
}

#Preview {
let userTest = User(id: "1",
name: "Joaquin Phoenix",
avatar: "",
description: "Дизайнер из Казани, люблю цифровое искусство и бейглы. В моей коллекции уже 100+ NFT, и еще больше — на моём сайте. Открыт к коллаборациям.",
website: "",
nfts: ["1", "2", "3", "3", "3", "3"],
rating: "1"
)
NavigationView {
UserCardView(isTabBarHidden: .constant(true))
UserCardView(
user: userTest,
isTabBarHidden: .constant(true)
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
//
// UserCollectionView.swift
// FakeNFT
//
// Created by Anastasia on 04.06.2025.
//

import SwiftUI

struct UserCollectionView: View {

// TODO: 3/3 Statistics

var body: some View {
VStack {
Text("Hello, World!")
}
.modifier(NavigationBarStyle(
title: "Коллекция NFT",
backButtonHidden: false,
filterButtonHidden: true,
filterButtonTapHandler: { }
))
.toolbar(.hidden, for: .tabBar)
}
}

#Preview {
NavigationStack {
UserCollectionView()
}
}
3 changes: 3 additions & 0 deletions FakeNFT/StatisticsConstants.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,7 @@ struct StatisticsConstants {
static let avatarSizeSmall: CGFloat = 28.0
static let avatarSizeLarge: CGFloat = 70.0
static let ratingLabelWidth: CGFloat = 27.0
static let buttonHeightMedium: CGFloat = 40.0
static let buttonHeightLarge: CGFloat = 54.0
static let borderLineWidth: CGFloat = 1.0
}
17 changes: 17 additions & 0 deletions FakeNFT/UserCardViewModel.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
//
// UserCardViewModel.swift
// FakeNFT
//
// Created by Anastasia on 04.06.2025.
//

import Foundation

@MainActor
final class UserCardViewModel: ObservableObject {
@Published var user: User

init(user: User) {
self.user = user
}
}