Published on

SwiftUI crypto app — foydalanuvchi portfelini boshqarish uchun view yaratish

Authors

SwiftUI crypto app — foydalanuvchi portfelini boshqarish uchun view yaratish

Kursimiz yarmiga yaqinlashib qoldik! Bu darsda foydalanuvchilar o'z portfellarini tahrirlashi uchun yangi ekran yaratamiz. U plus tugmasi bosilganda sheet sifatida paydo bo'ladi va unda tangalar ro'yxati, miqdor kiritish va saqlash imkoniyati bo'ladi.


1. PortfolioView yaratish va sheet-ga ulash

home/views papkasida PortfolioView.swift faylini yaratamiz. Keyin HomeView-da tugmaga sheet bog'laymiz:

// HomeView yuqorida:
@State private var showPortfolio: Bool = false   // o'ngga animatsiya
@State private var showPortfolioView: Bool = false  // yangi sheet

// Tugma ichida:
.onTapGesture {
    if showPortfolio {
        showPortfolioView.toggle()
    }
}

// Background-ga sheet:
.sheet(isPresented: $showPortfolioView) {
    PortfolioView()
        .environmentObject(vm)  // HomeViewModel-ni yangi muhitga uzatamiz
}

Muhim: .sheet yangi SwiftUI muhit (environment) hosil qiladi. vm-ni u yerga uzatmasak, PortfolioView ViewModel-ga kira olmaydi.


2. NavigationView va XmarkButton

PortfolioView-da o'z NavigationView-ini yaratishimiz kerak, chunki sheet — alohida muhit:

struct PortfolioView: View {

    @EnvironmentObject private var vm: HomeViewModel
    @Environment(\.presentationMode) var presentationMode

    var body: some View {
        NavigationView {
            ScrollView {
                VStack(alignment: .leading, spacing: 0) {
                    Text("Hi")
                }
            }
            .navigationTitle("Portfelni tahrirlash")
            .toolbar {
                ToolbarItem(placement: .navigationBarLeading) {
                    XMarkButton()  // Qayta ishlatiladigan yopish tugmasi
                }
                ToolbarItem(placement: .navigationBarTrailing) {
                    trailingNavBarButtons
                }
            }
        }
    }
}

XMarkButton — alohida komponent:

struct XMarkButton: View {
    @Environment(\.presentationMode) var presentationMode

    var body: some View {
        Button {
            presentationMode.wrappedValue.dismiss()
        } label: {
            Image(systemName: "xmark")
                .font(.headline)
        }
    }
}

3. CoinLogoView — tanga belgisi komponenti

Har bir tanganing rasmini, belgisini va nomini ko'rsatuvchi kichik komponent:

struct CoinLogoView: View {
    let coin: CoinModel

    var body: some View {
        VStack {
            // Tanganing rasmi (CoinImageView oldindan yaratilgan)
            CoinImageView(coin: coin)
                .frame(width: 50, height: 50)

            // Tanga belgisi (masalan: BTC, ETH)
            Text(coin.symbol.uppercased())
                .font(.headline)
                .foregroundColor(Color.theme.accent)
                .lineLimit(1)
                .minimumScaleFactor(0.5)  // kichik bo'lsa — shrink qiladi

            // Tanga nomi (masalan: Bitcoin)
            Text(coin.name)
                .font(.caption)
                .foregroundColor(Color.theme.secondaryText)
                .lineLimit(2)
                .minimumScaleFactor(0.5)
                .multilineTextAlignment(.center)
        }
    }
}

4. Gorizontal tangalar ro'yxati

Qidiruv maydoni va tangalar ro'yxatini PortfolioView-ga qo'shamiz:

// Extension ichida:
private var coinLogoList: some View {
    ScrollView(.horizontal, showsIndicators: false) {
        LazyHStack(spacing: 10) {
            ForEach(vm.allCoins) { coin in
                CoinLogoView(coin: coin)
                    .frame(width: 75)
                    .padding(4)
                    .onTapGesture {
                        withAnimation(.easeIn) {
                            selectedCoin = coin
                        }
                    }
                    .background(
                        RoundedRectangle(cornerRadius: 10)
                            .stroke(
                                // Tanlangan tanga — yashil chegara, boshqalar shaffof
                                selectedCoin?.id == coin.id ?
                                    Color.theme.green : Color.clear,
                                lineWidth: 1
                            )
                    )
            }
        }
        .padding(.vertical, 4)
        .padding(.leading)
    }
}
// View ichida holatlar:
@State private var selectedCoin: CoinModel? = nil
@State private var quantityText: String = ""
@State private var showCheckmark: Bool = false

5. Miqdor kiritish va joriy qiymat hisoblash

Tanga tanlanganda pastda qo'shimcha ma'lumot ko'rsatamiz:

private var portfolioInputSection: some View {
    VStack(spacing: 20) {
        HStack {
            Text("Joriy narx:")
            Spacer()
            Text(selectedCoin?.currentPrice.asCurrencyWith6Decimals() ?? "")
        }

        Divider()

        HStack {
            Text("Portfelda mavjud miqdor:")
            Spacer()
            TextField("Masalan: 1.4", text: $quantityText)
                .multilineTextAlignment(.trailing)
                .keyboardType(.decimalPad)  // Faqat raqamlar klaviaturasi
        }

        Divider()

        HStack {
            Text("Joriy qiymat:")
            Spacer()
            Text(getCurrentValue().asCurrencyWith2Decimals())
        }
    }
    .animation(.none)
    .padding()
    .font(.headline)
}

// Miqdor × narx = joriy qiymat
private func getCurrentValue() -> Double {
    if let quantity = Double(quantityText) {
        return quantity * (selectedCoin?.currentPrice ?? 0)
    }
    return 0
}

6. Saqlash tugmasi (Save)

Faqat miqdor o'zgarganda ko'rinadigan saqlash tugmasi:

private var trailingNavBarButtons: some View {
    HStack(spacing: 10) {
        Image(systemName: "checkmark")
            .opacity(showCheckmark ? 1.0 : 0.0)  // saqlanganda ko'rinadi

        Button("SAQLASH") {
            saveButtonPressed()
        }
        // Faqat tanlangan tanga va miqdor o'zgarganda ko'rinadi
        .opacity(
            selectedCoin != nil &&
            selectedCoin?.currentHoldings != Double(quantityText) ?
            1.0 : 0.0
        )
    }
    .font(.headline)
}

private func saveButtonPressed() {
    guard let coin = selectedCoin else { return }
    // Core Data ga saqlash logikasi keyingi darsda
    withAnimation(.easeIn) {
        showCheckmark = true
        removeSelectedCoin()
    }
    UIApplication.shared.endEditing()  // Klaviaturani yopish
    // 2 soniyadan keyin checkmark-ni yashiramiz
    DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
        withAnimation(.easeOut) {
            showCheckmark = false
        }
    }
}

private func removeSelectedCoin() {
    selectedCoin = nil
    vm.searchText = ""
}

7. NavigationBar sarlavha rangini o'zgartirish

Ilovaning asosiy faylida (SwiftfulCryptoApp.swift) init ichida NavigationBar rangini belgilaymiz:

init() {
    // Katta sarlavha rangi
    UINavigationBar.appearance().largeTitleTextAttributes = [
        .foregroundColor: UIColor(Color.theme.accent)
    ]
    // Oddiy sarlavha rangi
    UINavigationBar.appearance().titleTextAttributes = [
        .foregroundColor: UIColor(Color.theme.accent)
    ]
}

Natija

Simulatorda ilovani ishga tushiring:

  1. Portfel tabiga o'ting → plus tugmasini bosing
  2. Yangi sheet ochiladi — tangalar gorizontal ro'yxatda
  3. Biror tangani bosing — yashil chegara paydo bo'ladi
  4. Miqdor kiriting — SAQLASH tugmasi paydo bo'ladi
  5. Saqlash bosilganda ✓ belgisi chiqib, 2 soniyada g'oyib bo'ladi

Keyingi darsda Core Data yordamida portfelni haqiqatda saqlaymiz! 🚀

Buy mea coffee