# SnapKit 15: Amaliyot — 30 ta Vizual UI Topshiriq (Zero to Hero Challenge)

> **Holat:** Ushbu qo'llanma 2026-yil oktabr holatiga ko'ra SnapKit 5.7+ va Swift 6 talablari asosida tayyorlangan. Barcha kodlar zamonaviy `@MainActor`, UIKit Auto Layout va SwiftUI ekvivalentlari bilan boyitilgan.

Auto Layout va SnapKit bo'yicha nazariy bilimlarni o'rganish — bu yo'lning atigi 30% qismi. Haqiqiy mahorat faqat va faqat **amaliyot** orqali shakllanadi. Professional iOS dasturchisi dizayner chizgan har qanday UI sxemani ko'rishi bilanoq miyasida constraint'lar zanjirini qurishi, qaysi element qaysi biriga bog'lanishini, qaysi biri qisqarib qaysi biri cho'zilishini darhol his qila olishi zarur.

Ushbu amaliy darsda siz uchun **30 ta maxsus vizual topshiriq** tayyorlandi. Ular oddiy poydevordan boshlanib, real App Store ilovalaridagi eng murakkab interfeyslargacha (ProfileView, HomeView, Chat, Fintech, Food Delivery, Crypto, App Store Today, Fitness, Checkout, Full Podcast Player) bosqichma-bosqich qiyinlashib boradi.

---

## 🧭 Mashg'ulot Qoidalari va Tavsiyalar

1. **Avval mustaqil bajaring:** Har bir topshiriqdagi grafik sxemani (rasmni) va texnik talablarni diqqat bilan o'rganing. Yechimni ochishdan oldin yangi Xcode Playground yoki loyihada kod yozib ko'ring.
2. **Kodni tekshiring:** Agar yechimni topishda qiyinchilikka duch kelsangiz yoki o'z kodingizni eng toza arxitektura bilan solishtirmoqchi bo'lsangiz, **"💡 Kodni ko'rish"** tugmasini bosing.
3. **Uchala texnologiyani taqqoslang:** Har bir vazifada sizga 3 xil yechim taqdim etiladi:
   - **SnapKit (Asosiy maqsadimiz):** Minimal, o'qilishi oson va qulay DSL.
   - **Klassik UIKit (NSLayoutConstraint):** Nativ Anchor tizimi (SnapKit qanchalik mehnatni tejashini ko'rish uchun).
   - **SwiftUI ekvivalenti:** Zamonaviy deklarativ yondashuv (dunyoqarashni kengaytirish uchun).
4. **Pro Tip va arxitektura xulosalariga e'tibor bering:** Har bir yechim ostidagi professional maslahatlar sizni intervyularda yoki katta loyihalarda uchraydigan constraint buzilishlaridan asraydi.

---

## 📊 Qiyinchilik Darajalari

| Daraja | Vazifalar | Qamrab Olingan Mavzular |
| :--- | :--- | :--- |
| 🟢 **Oson (Easy)** | 01 – 05 | Center, Edges Inset, Vertical Spacing, Safe Area, Avatar & Label |
| 🟡 **O'rta (Medium)** | 06 – 11 | Aspect Ratio (16:9), Overlapping Badge, Dynamic Width (Chat Bubble), 3 Equal Columns, Hugging/Compression Priority, Notification Banner |
| 🟠 **Qiyin (Hard)** | 12 – 16 | E-Commerce Product Card, Floating Action Button (FAB), Dynamic Self-Sizing Cell, UIScrollView va ContentView, Segmented Moving Indicator |
| 🔴 **Qahramon (Hero)** | 17 – 20 | Apple Music/Spotify Mini-Player, Instagram Stories Concentric Rings, Bank Card (1.586 ratio), Modern Paywall Subscription Card |
| 👑 **Titan (Real-World Screens)** | 21 – 30 | Instagram Profile, E-Commerce Home Feed, Telegram Chat Room, Fintech Banking, Food Delivery Detail, Crypto Order Book, App Store Today, Fitness Dashboard, Checkout Summary, Full Podcast Player |

---

## 🟢 Topshiriq 01: Markazdagi Kvadrat (Center Square)

> **Daraja:** `Oson (Easy)` | **Maqsad:** Ekran markazida o'zgarmas 120x120 o'lchamli kvadrat shaklidagi view'ni joylashtirish.

Ushbu topshiriq SnapKit'dagi eng asosiy poydevor tushunchalar: `center` (markazlashtirish) va `size` (aniq o'lcham belgilash) bilan ishlashni mustahkamlaydi.

### Vizual Sxema (UI Mockup)

![Topshiriq 01: Markazdagi Kvadrat (Center Square)](/lessons/images/snapkit/task_01.svg)

### 📋 Texnik Talablar va Cheklovlar

- Kvadrat kengligi (width) va balandligi (height) aynan 120 pt bo'lishi kerak.
- Kvadrat ota-ona (superview) ekranning gorizontal va vertikal markazida bo'lishi shart.
- Burchaklar radiusi (cornerRadius): 16 pt.

<details>
<summary>💡 Kodni ko'rish (SnapKit, UIKit va SwiftUI yechimlari)</summary>

#### 1. SnapKit Yechimi (Asosiy)

```swift
import UIKit
import SnapKit

final class Task01View: UIView {
    private let blueBox: UIView = {
        let view = UIView()
        view.backgroundColor = .systemBlue
        view.layer.cornerRadius = 16
        view.clipsToBounds = true
        return view
    }()

    override init(frame: CGRect) {
        super.init(frame: frame)
        setupUI()
    }

    required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") }

    private func setupUI() {
        backgroundColor = UIColor(white: 0.1, alpha: 1.0)
        addSubview(blueBox)

        blueBox.snp.makeConstraints { make in
            make.center.equalToSuperview()
            make.size.equalTo(120) // make.width.height.equalTo(120) bilan bir xil
        }
    }
}
```

#### 2. Klassik UIKit (NSLayoutConstraint) Taqqoslash

```swift
import UIKit

final class Task01UIKitView: UIView {
    private let blueBox: UIView = {
        let view = UIView()
        view.backgroundColor = .systemBlue
        view.layer.cornerRadius = 16
        view.clipsToBounds = true
        view.translatesAutoresizingMaskIntoConstraints = false
        return view
    }()

    override init(frame: CGRect) {
        super.init(frame: frame)
        backgroundColor = UIColor(white: 0.1, alpha: 1.0)
        addSubview(blueBox)

        NSLayoutConstraint.activate([
            blueBox.centerXAnchor.constraint(equalTo: centerXAnchor),
            blueBox.centerYAnchor.constraint(equalTo: centerYAnchor),
            blueBox.widthAnchor.constraint(equalToConstant: 120),
            blueBox.heightAnchor.constraint(equalToConstant: 120)
        ])
    }

    required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") }
}
```

#### 3. SwiftUI Ekvivalenti

```swift
import SwiftUI

struct Task01SwiftUIView: View {
    var body: some View {
        ZStack {
            Color(white: 0.1).ignoresSafeArea()
            
            RoundedRectangle(cornerRadius: 16)
                .fill(Color.blue)
                .frame(width: 120, height: 120)
        }
    }
}
```

> 💡 **Pro Tip & Arxitektura siri:**
> SnapKit'da `make.size.equalTo(120)` deb yozish `make.width.equalTo(120)` va `make.height.equalTo(120)` o'rnini bosadi. Agar eni va bo'yi har xil bo'lsa, `make.size.equalTo(CGSize(width: 120, height: 80))` formatida berish mumkin.

</details>

---

## 🟢 Topshiriq 02: Chetlaridan Bir Xil Masofadagi Card (Edges Inset)

> **Daraja:** `Oson (Easy)` | **Maqsad:** Ekranning to'rtta chetidan ham 20 pt masofa (padding) tashlab, to'liq cho'ziluvchi kartani hosil qilish.

To'rtta chetni (`top`, `bottom`, `leading`, `trailing`) alohida yozish o'rniga SnapKit'ning kuchli `edges` va `inset` sintaksisidan foydalanish ko'nikmasi.

### Vizual Sxema (UI Mockup)

![Topshiriq 02: Chetlaridan Bir Xil Masofadagi Card (Edges Inset)](/lessons/images/snapkit/task_02.svg)

### 📋 Texnik Talablar va Cheklovlar

- Karta ota-onaning barcha 4 tomoniga (top, bottom, leading, trailing) bog'lanishi kerak.
- Har bir chetdan aynan 20 pt ichkariga (inset) siljishi lozim.
- Burchaklar radiusi: 14 pt, fon rangi: binafsha (systemPurple).

<details>
<summary>💡 Kodni ko'rish (SnapKit, UIKit va SwiftUI yechimlari)</summary>

#### 1. SnapKit Yechimi (Asosiy)

```swift
import UIKit
import SnapKit

final class Task02View: UIView {
    private let contentCard: UIView = {
        let view = UIView()
        view.backgroundColor = .systemPurple
        view.layer.cornerRadius = 14
        return view
    }()

    override init(frame: CGRect) {
        super.init(frame: frame)
        setupUI()
    }

    required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") }

    private func setupUI() {
        backgroundColor = UIColor(white: 0.1, alpha: 1.0)
        addSubview(contentCard)

        contentCard.snp.makeConstraints { make in
            // Barcha 4 tomonni bir qatorda 20 pt ichkariga siljitish:
            make.edges.equalToSuperview().inset(20)
            
            // Yoki alohida insets:
            // make.edges.equalToSuperview().inset(UIEdgeInsets(top: 20, left: 20, bottom: 20, right: 20))
        }
    }
}
```

#### 2. Klassik UIKit (NSLayoutConstraint) Taqqoslash

```swift
import UIKit

final class Task02UIKitView: UIView {
    private let contentCard: UIView = {
        let view = UIView()
        view.backgroundColor = .systemPurple
        view.layer.cornerRadius = 14
        view.translatesAutoresizingMaskIntoConstraints = false
        return view
    }()

    override init(frame: CGRect) {
        super.init(frame: frame)
        backgroundColor = UIColor(white: 0.1, alpha: 1.0)
        addSubview(contentCard)

        NSLayoutConstraint.activate([
            contentCard.topAnchor.constraint(equalTo: topAnchor, constant: 20),
            contentCard.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 20),
            contentCard.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -20),
            contentCard.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -20)
        ])
    }

    required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") }
}
```

#### 3. SwiftUI Ekvivalenti

```swift
import SwiftUI

struct Task02SwiftUIView: View {
    var body: some View {
        ZStack {
            Color(white: 0.1).ignoresSafeArea()
            
            RoundedRectangle(cornerRadius: 14)
                .fill(Color.purple)
                .padding(20)
        }
    }
}
```

> 💡 **Pro Tip & Arxitektura siri:**
> Farqiga e'tibor bering: `inset(20)` deb yozganda SnapKit `trailing` va `bottom` uchun avtomatik ravishda manfiy ishora (`-20`) qo'llaydi. Agar siz `offset(20)` ishlatganingizda edi, pastki va o'ng chegaralar ekrandan tashqariga chiqib ketardi!

</details>

---

## 🟢 Topshiriq 03: Ketma-ket Ikkita Vertikal Karta (Spacing)

> **Daraja:** `Oson (Easy)` | **Maqsad:** Biri ikkinchisining ostida joylashgan, orasi 16 pt bo'lgan ikkita kartani bog'lash.

Elementlar orasidagi munosabat: ikkinchi elementning yuqori qismini (`top`) birinchi elementning pastki qismiga (`bottom`) bog'lash amaliyoti.

### Vizual Sxema (UI Mockup)

![Topshiriq 03: Ketma-ket Ikkita Vertikal Karta (Spacing)](/lessons/images/snapkit/task_03.svg)

### 📋 Texnik Talablar va Cheklovlar

- Ikkala karta kengligi ota-onaning yonlaridan 24 pt masofada bo'lsin.
- Har bir kartaning balandligi aynan 85 pt.
- Birinchi karta ota-onaning tepasidan 35 pt masofada.
- Ikkinchi karta birinchi kartaning tagidan 16 pt oraliq bilan joylashsin.

<details>
<summary>💡 Kodni ko'rish (SnapKit, UIKit va SwiftUI yechimlari)</summary>

#### 1. SnapKit Yechimi (Asosiy)

```swift
import UIKit
import SnapKit

final class Task03View: UIView {
    private let topCard: UIView = {
        let v = UIView()
        v.backgroundColor = .systemBlue
        v.layer.cornerRadius = 12
        return v
    }()

    private let bottomCard: UIView = {
        let v = UIView()
        v.backgroundColor = .systemPurple
        v.layer.cornerRadius = 12
        return v
    }()

    override init(frame: CGRect) {
        super.init(frame: frame)
        setupUI()
    }

    required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") }

    private func setupUI() {
        backgroundColor = UIColor(white: 0.1, alpha: 1.0)
        addSubview(topCard)
        addSubview(bottomCard)

        topCard.snp.makeConstraints { make in
            make.top.equalToSuperview().offset(35)
            make.leading.trailing.equalToSuperview().inset(24)
            make.height.equalTo(85)
        }

        bottomCard.snp.makeConstraints { make in
            make.top.equalTo(topCard.snp.bottom).offset(16)
            make.leading.trailing.equalTo(topCard) // topCard bilan bir xil kenglik
            make.height.equalTo(85)
        }
    }
}
```

#### 2. Klassik UIKit (NSLayoutConstraint) Taqqoslash

```swift
import UIKit

final class Task03UIKitView: UIView {
    private let topCard: UIView = {
        let v = UIView()
        v.backgroundColor = .systemBlue
        v.layer.cornerRadius = 12
        v.translatesAutoresizingMaskIntoConstraints = false
        return v
    }()

    private let bottomCard: UIView = {
        let v = UIView()
        v.backgroundColor = .systemPurple
        v.layer.cornerRadius = 12
        v.translatesAutoresizingMaskIntoConstraints = false
        return v
    }()

    override init(frame: CGRect) {
        super.init(frame: frame)
        backgroundColor = UIColor(white: 0.1, alpha: 1.0)
        addSubview(topCard)
        addSubview(bottomCard)

        NSLayoutConstraint.activate([
            topCard.topAnchor.constraint(equalTo: topAnchor, constant: 35),
            topCard.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 24),
            topCard.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -24),
            topCard.heightAnchor.constraint(equalToConstant: 85),

            bottomCard.topAnchor.constraint(equalTo: topCard.bottomAnchor, constant: 16),
            bottomCard.leadingAnchor.constraint(equalTo: topCard.leadingAnchor),
            bottomCard.trailingAnchor.constraint(equalTo: topCard.trailingAnchor),
            bottomCard.heightAnchor.constraint(equalToConstant: 85)
        ])
    }

    required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") }
}
```

#### 3. SwiftUI Ekvivalenti

```swift
import SwiftUI

struct Task03SwiftUIView: View {
    var body: some View {
        VStack(spacing: 16) {
            RoundedRectangle(cornerRadius: 12)
                .fill(Color.blue)
                .frame(height: 85)

            RoundedRectangle(cornerRadius: 12)
                .fill(Color.purple)
                .frame(height: 85)
            
            Spacer()
        }
        .padding(.horizontal, 24)
        .padding(.top, 35)
        .background(Color(white: 0.1).ignoresSafeArea())
    }
}
```

> 💡 **Pro Tip & Arxitektura siri:**
> SnapKit'da `make.leading.trailing.equalTo(topCard)` deb yozish bir yo'la ikkita chetni bir xil qilib bog'laydi. Bu kodni ixchamlashtiradi va kelajakda `topCard` ning marginlari o'zgarsa, `bottomCard` ham avtomatik ergashadi.

</details>

---

## 🟢 Topshiriq 04: Bosh Banner va Pastki Qadalgan Tugma (Safe Area)

> **Daraja:** `Oson (Easy)` | **Maqsad:** Yuqoridagi bannerni Safe Area tepasiga, pastki tugmani esa Safe Area pastki chegarasiga mustahkamlash.

iPhone'dagi Dynamic Island, Notch va pastki Home Bar tugmalari bilan to'qnash kelmaslik uchun `safeAreaLayoutGuide` bilan to'g'ri ishlash.

### Vizual Sxema (UI Mockup)

![Topshiriq 04: Bosh Banner va Pastki Qadalgan Tugma (Safe Area)](/lessons/images/snapkit/task_04.svg)

### 📋 Texnik Talablar va Cheklovlar

- Header banner Safe Area tepasidan 8 pt pastda, balandligi 56 pt.
- Bottom action button Safe Area ostidan 8 pt tepada, balandligi 48 pt, burchaklari 24 pt (pill shape).
- Ikkala element ham yondan 16 pt masofada bo'lsin.

<details>
<summary>💡 Kodni ko'rish (SnapKit, UIKit va SwiftUI yechimlari)</summary>

#### 1. SnapKit Yechimi (Asosiy)

```swift
import UIKit
import SnapKit

final class Task04ViewController: UIViewController {
    private let headerBanner: UIView = {
        let v = UIView()
        v.backgroundColor = UIColor(white: 0.2, alpha: 1.0)
        v.layer.cornerRadius = 10
        return v
    }()

    private let continueButton: UIButton = {
        let btn = UIButton(type: .system)
        btn.setTitle("Davom etish", for: .normal)
        btn.setTitleColor(.white, for: .normal)
        btn.titleLabel?.font = .systemFont(ofSize: 15, weight: .bold)
        btn.backgroundColor = .systemBlue
        btn.layer.cornerRadius = 24
        return btn
    }()

    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = UIColor(white: 0.08, alpha: 1.0)
        view.addSubview(headerBanner)
        view.addSubview(continueButton)

        headerBanner.snp.makeConstraints { make in
            make.top.equalTo(view.safeAreaLayoutGuide.snp.top).offset(8)
            make.leading.trailing.equalToSuperview().inset(16)
            make.height.equalTo(56)
        }

        continueButton.snp.makeConstraints { make in
            make.bottom.equalTo(view.safeAreaLayoutGuide.snp.bottom).offset(-8)
            make.leading.trailing.equalToSuperview().inset(16)
            make.height.equalTo(48)
        }
    }
}
```

#### 2. Klassik UIKit (NSLayoutConstraint) Taqqoslash

```swift
import UIKit

final class Task04UIKitViewController: UIViewController {
    private let headerBanner: UIView = {
        let v = UIView()
        v.backgroundColor = UIColor(white: 0.2, alpha: 1.0)
        v.layer.cornerRadius = 10
        v.translatesAutoresizingMaskIntoConstraints = false
        return v
    }()

    private let continueButton: UIButton = {
        let btn = UIButton(type: .system)
        btn.setTitle("Davom etish", for: .normal)
        btn.setTitleColor(.white, for: .normal)
        btn.backgroundColor = .systemBlue
        btn.layer.cornerRadius = 24
        btn.translatesAutoresizingMaskIntoConstraints = false
        return btn
    }()

    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = UIColor(white: 0.08, alpha: 1.0)
        view.addSubview(headerBanner)
        view.addSubview(continueButton)

        let safe = view.safeAreaLayoutGuide
        NSLayoutConstraint.activate([
            headerBanner.topAnchor.constraint(equalTo: safe.topAnchor, constant: 8),
            headerBanner.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 16),
            headerBanner.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -16),
            headerBanner.heightAnchor.constraint(equalToConstant: 56),

            continueButton.bottomAnchor.constraint(equalTo: safe.bottomAnchor, constant: -8),
            continueButton.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 16),
            continueButton.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -16),
            continueButton.heightAnchor.constraint(equalToConstant: 48)
        ])
    }
}
```

#### 3. SwiftUI Ekvivalenti

```swift
import SwiftUI

struct Task04SwiftUIView: View {
    var body: some View {
        VStack {
            RoundedRectangle(cornerRadius: 10)
                .fill(Color(white: 0.2))
                .frame(height: 56)
                .padding(.top, 8)
                .padding(.horizontal, 16)

            Spacer()

            Button(action: {}) {
                Text("Davom etish")
                    .font(.headline)
                    .foregroundColor(.white)
                    .frame(maxWidth: .infinity)
                    .frame(height: 48)
                    .background(Color.blue)
                    .clipShape(Capsule())
            }
            .padding(.bottom, 8)
            .padding(.horizontal, 16)
        }
        .background(Color(white: 0.08).ignoresSafeArea())
    }
}
```

> 💡 **Pro Tip & Arxitektura siri:**
> SnapKit'da `view.safeAreaLayoutGuide.snp.top` orqali to'g'ridan-to'g'ri bog'lanish eng xavfsiz yo'ldir. Hech qachon ekranning mutlaq `top` chegarasiga fiksatsiyalangan raqam bermang, chunki iPhone SE (notch yo'q), iPhone 13 (notch bor) va iPhone 15/16 (Dynamic Island) har xil balandlikka ega!

</details>

---

## 🟢 Topshiriq 05: Doiraviy Profil Rasmi va Yonidagi Matn

> **Daraja:** `Oson (Easy)` | **Maqsad:** Chap tomonda 64x64 doiraviy avatar, uning o'ng tomonida esa vertikal markazlashgan Title va Subtitle yozuvlarini hosil qilish.

Gorizontal zanjir (Avatar -> Text) va matnlar guruhini umumiy konteyner yoki avatarga nisbatan vertikal markazlashtirish usuli.

### Vizual Sxema (UI Mockup)

![Topshiriq 05: Doiraviy Profil Rasmi va Yonidagi Matn](/lessons/images/snapkit/task_05.svg)

### 📋 Texnik Talablar va Cheklovlar

- Avatar: 64x64 pt, burchak radiusi 32 pt (to'liq doira), chapdan 16 pt.
- Matnlar avatardan 12 pt o'ngda boshlansin.
- Title: qalin 15 pt matn. Subtitle: och 12 pt matn, title'dan 4 pt pastda.
- Title va Subtitle juftligi avatarga nisbatan vertikal markazlashgan bo'lsin.

<details>
<summary>💡 Kodni ko'rish (SnapKit, UIKit va SwiftUI yechimlari)</summary>

#### 1. SnapKit Yechimi (Asosiy)

```swift
import UIKit
import SnapKit

final class Task05View: UIView {
    private let avatarImageView: UIImageView = {
        let iv = UIImageView()
        iv.backgroundColor = .systemBlue
        iv.layer.cornerRadius = 32
        iv.clipsToBounds = true
        return iv
    }()

    private let titleLabel: UILabel = {
        let l = UILabel()
        l.text = "Azimjon Pulatov"
        l.textColor = .white
        l.font = .systemFont(ofSize: 15, weight: .bold)
        return l
    }()

    private let subtitleLabel: UILabel = {
        let l = UILabel()
        l.text = "iOS Software Engineer"
        l.textColor = .systemGray
        l.font = .systemFont(ofSize: 12, weight: .regular)
        return l
    }()

    override init(frame: CGRect) {
        super.init(frame: frame)
        setupUI()
    }

    required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") }

    private func setupUI() {
        backgroundColor = UIColor(white: 0.1, alpha: 1.0)
        addSubview(avatarImageView)
        addSubview(titleLabel)
        addSubview(subtitleLabel)

        avatarImageView.snp.makeConstraints { make in
            make.centerY.equalToSuperview()
            make.leading.equalToSuperview().offset(16)
            make.size.equalTo(64)
        }

        titleLabel.snp.makeConstraints { make in
            make.leading.equalTo(avatarImageView.snp.trailing).offset(12)
            make.trailing.lessThanOrEqualToSuperview().offset(-16)
            make.bottom.equalTo(avatarImageView.snp.centerY).offset(-2)
        }

        subtitleLabel.snp.makeConstraints { make in
            make.leading.equalTo(titleLabel)
            make.trailing.lessThanOrEqualToSuperview().offset(-16)
            make.top.equalTo(avatarImageView.snp.centerY).offset(2)
        }
    }
}
```

#### 2. Klassik UIKit (NSLayoutConstraint) Taqqoslash

```swift
import UIKit

final class Task05UIKitView: UIView {
    private let avatarImageView: UIImageView = {
        let iv = UIImageView()
        iv.backgroundColor = .systemBlue
        iv.layer.cornerRadius = 32
        iv.clipsToBounds = true
        iv.translatesAutoresizingMaskIntoConstraints = false
        return iv
    }()

    private let titleLabel: UILabel = {
        let l = UILabel()
        l.text = "Azimjon Pulatov"
        l.textColor = .white
        l.font = .systemFont(ofSize: 15, weight: .bold)
        l.translatesAutoresizingMaskIntoConstraints = false
        return l
    }()

    private let subtitleLabel: UILabel = {
        let l = UILabel()
        l.text = "iOS Software Engineer"
        l.textColor = .systemGray
        l.font = .systemFont(ofSize: 12, weight: .regular)
        l.translatesAutoresizingMaskIntoConstraints = false
        return l
    }()

    override init(frame: CGRect) {
        super.init(frame: frame)
        backgroundColor = UIColor(white: 0.1, alpha: 1.0)
        addSubview(avatarImageView)
        addSubview(titleLabel)
        addSubview(subtitleLabel)

        NSLayoutConstraint.activate([
            avatarImageView.centerYAnchor.constraint(equalTo: centerYAnchor),
            avatarImageView.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 16),
            avatarImageView.widthAnchor.constraint(equalToConstant: 64),
            avatarImageView.heightAnchor.constraint(equalToConstant: 64),

            titleLabel.leadingAnchor.constraint(equalTo: avatarImageView.trailingAnchor, constant: 12),
            titleLabel.bottomAnchor.constraint(equalTo: avatarImageView.centerYAnchor, constant: -2),

            subtitleLabel.leadingAnchor.constraint(equalTo: titleLabel.leadingAnchor),
            subtitleLabel.topAnchor.constraint(equalTo: avatarImageView.centerYAnchor, constant: 2)
        ])
    }

    required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") }
}
```

#### 3. SwiftUI Ekvivalenti

```swift
import SwiftUI

struct Task05SwiftUIView: View {
    var body: some View {
        HStack(spacing: 12) {
            Circle()
                .fill(Color.blue)
                .frame(width: 64, height: 64)

            VStack(alignment: .leading, spacing: 4) {
                Text("Azimjon Pulatov")
                    .font(.system(size: 15, weight: .bold))
                    .foregroundColor(.white)

                Text("iOS Software Engineer")
                    .font(.system(size: 12))
                    .foregroundColor(.gray)
            }

            Spacer()
        }
        .padding(.horizontal, 16)
        .frame(height: 96)
        .background(Color(white: 0.1).ignoresSafeArea())
    }
}
```

> 💡 **Pro Tip & Arxitektura siri:**
> Ikkita satrli matnni vertikal markazlashtirishning ajoyib usuli: `titleLabel.bottom` ni markaz chizig'iga (`centerY.offset(-2)`), `subtitleLabel.top` ni esa markaz chizig'iga (`centerY.offset(2)`) bog'lashdir. Bu hech qanday qo'shimcha container view talab qilmaydi!

</details>

---

## 🟡 Topshiriq 06: 16:9 Nisbatdagi Video Player Karta

> **Daraja:** `O'rta (Medium)` | **Maqsad:** Ekran kengligiga moslashuvchan, balandligi esa har doim 16:9 nisbatda avtomatik saqlanib turuvchi video player container yaratish.

SnapKit'dagi `multipliedBy` yordamida ekranning har qanday kengligida (iPhone, iPad, Landscape) to'g'ri proporsiyani saqlash texnikasi.

### Vizual Sxema (UI Mockup)

![Topshiriq 06: 16:9 Nisbatdagi Video Player Karta](/lessons/images/snapkit/task_06.svg)

### 📋 Texnik Talablar va Cheklovlar

- Video kartasi yonlardan 24 pt masofa bilan ota-onaga bog'lansin.
- Balandlik (height) kenglikka (width) nisbatan qat'iy 9/16 (0.5625) ko'paytuvchisi bilan o'rnatilsin.
- Karta markazida 48x48 o'lchamdagi play tugmasi doirasi bo'lsin.

<details>
<summary>💡 Kodni ko'rish (SnapKit, UIKit va SwiftUI yechimlari)</summary>

#### 1. SnapKit Yechimi (Asosiy)

```swift
import UIKit
import SnapKit

final class Task06View: UIView {
    private let videoPlayerCard: UIView = {
        let v = UIView()
        v.backgroundColor = UIColor(white: 0.15, alpha: 1.0)
        v.layer.cornerRadius = 12
        v.layer.borderWidth = 1.5
        v.layer.borderColor = UIColor.systemGreen.cgColor
        return v
    }()

    private let playButton: UIButton = {
        let btn = UIButton(type: .system)
        let config = UIImage.SymbolConfiguration(pointSize: 22, weight: .bold)
        btn.setImage(UIImage(systemName: "play.fill", withConfiguration: config), for: .normal)
        btn.tintColor = .white
        btn.backgroundColor = .systemGreen
        btn.layer.cornerRadius = 24
        return btn
    }()

    override init(frame: CGRect) {
        super.init(frame: frame)
        setupUI()
    }

    required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") }

    private func setupUI() {
        backgroundColor = UIColor(white: 0.08, alpha: 1.0)
        addSubview(videoPlayerCard)
        videoPlayerCard.addSubview(playButton)

        videoPlayerCard.snp.makeConstraints { make in
            make.centerY.equalToSuperview()
            make.leading.trailing.equalToSuperview().inset(24)
            // 16:9 Aspect Ratio: balandlik = kenglik * (9.0 / 16.0)
            make.height.equalTo(videoPlayerCard.snp.width).multipliedBy(9.0 / 16.0)
        }

        playButton.snp.makeConstraints { make in
            make.center.equalToSuperview()
            make.size.equalTo(48)
        }
    }
}
```

#### 2. Klassik UIKit (NSLayoutConstraint) Taqqoslash

```swift
import UIKit

final class Task06UIKitView: UIView {
    private let videoPlayerCard: UIView = {
        let v = UIView()
        v.backgroundColor = UIColor(white: 0.15, alpha: 1.0)
        v.layer.cornerRadius = 12
        v.translatesAutoresizingMaskIntoConstraints = false
        return v
    }()

    override init(frame: CGRect) {
        super.init(frame: frame)
        backgroundColor = UIColor(white: 0.08, alpha: 1.0)
        addSubview(videoPlayerCard)

        NSLayoutConstraint.activate([
            videoPlayerCard.centerYAnchor.constraint(equalTo: centerYAnchor),
            videoPlayerCard.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 24),
            videoPlayerCard.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -24),
            // UIKit'da multiplier yordamida aspect ratio:
            videoPlayerCard.heightAnchor.constraint(
                equalTo: videoPlayerCard.widthAnchor,
                multiplier: 9.0 / 16.0
            )
        ])
    }

    required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") }
}
```

#### 3. SwiftUI Ekvivalenti

```swift
import SwiftUI

struct Task06SwiftUIView: View {
    var body: some View {
        ZStack {
            Color(white: 0.08).ignoresSafeArea()

            ZStack {
                RoundedRectangle(cornerRadius: 12)
                    .fill(Color(white: 0.15))
                    .aspectRatio(16/9, contentMode: .fit)

                Circle()
                    .fill(Color.green)
                    .frame(width: 48, height: 48)
                    .overlay(
                        Image(systemName: "play.fill")
                            .foregroundColor(.white)
                    )
            }
            .padding(.horizontal, 24)
        }
    }
}
```

> 💡 **Pro Tip & Arxitektura siri:**
> Nisbat belgilashda Swift'dagi bo'lish amalini ehtiyotkorlik bilan yozing: `9 / 16` butun sonli bo'lish bo'lgani uchun natija 0 bo'lib qoladi! Doimo float formatda `9.0 / 16.0` yozishni unutmang.

</details>

---

## 🟡 Topshiriq 07: Profil Rasmi Burchagidagi Online Status Dot

> **Daraja:** `O'rta (Medium)` | **Maqsad:** 80x80 profil rasmining pastki o'ng burchagida qisman chiqib turuvchi 24x24 online status nishonini (badge) joylashtirish.

Elementlarni bir-birining ustiga (overlap) qadash va burchak koordinatalarini nozik offset bilan surish amaliyoti.

### Vizual Sxema (UI Mockup)

![Topshiriq 07: Profil Rasmi Burchagidagi Online Status Dot](/lessons/images/snapkit/task_07.svg)

### 📋 Texnik Talablar va Cheklovlar

- Avatar: 80x80 pt o'lcham, burchak radiusi 40 pt.
- Status badge: 24x24 pt, yashil rang, oq yoki to'q chegara (border: 3 pt).
- Status badge markazi avatarning pastki o'ng chetidan 2 pt tashqariga siljisin.

<details>
<summary>💡 Kodni ko'rish (SnapKit, UIKit va SwiftUI yechimlari)</summary>

#### 1. SnapKit Yechimi (Asosiy)

```swift
import UIKit
import SnapKit

final class Task07View: UIView {
    private let avatarImageView: UIImageView = {
        let iv = UIImageView()
        iv.backgroundColor = .systemPurple
        iv.layer.cornerRadius = 40
        iv.clipsToBounds = true
        return iv
    }()

    private let statusDot: UIView = {
        let v = UIView()
        v.backgroundColor = .systemGreen
        v.layer.cornerRadius = 12
        v.layer.borderWidth = 3
        v.layer.borderColor = UIColor(white: 0.1, alpha: 1.0).cgColor
        return v
    }()

    override init(frame: CGRect) {
        super.init(frame: frame)
        setupUI()
    }

    required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") }

    private func setupUI() {
        backgroundColor = UIColor(white: 0.1, alpha: 1.0)
        addSubview(avatarImageView)
        addSubview(statusDot) // statusDot avatardan ustun turishi uchun keyin qo'shiladi

        avatarImageView.snp.makeConstraints { make in
            make.center.equalToSuperview()
            make.size.equalTo(80)
        }

        statusDot.snp.makeConstraints { make in
            make.size.equalTo(24)
            // Avatarning pastki-o'ng burchagiga mahkamlash:
            make.bottom.equalTo(avatarImageView.snp.bottom).offset(2)
            make.trailing.equalTo(avatarImageView.snp.trailing).offset(2)
        }
    }
}
```

#### 2. Klassik UIKit (NSLayoutConstraint) Taqqoslash

```swift
import UIKit

final class Task07UIKitView: UIView {
    private let avatarImageView: UIImageView = {
        let iv = UIImageView()
        iv.backgroundColor = .systemPurple
        iv.layer.cornerRadius = 40
        iv.clipsToBounds = true
        iv.translatesAutoresizingMaskIntoConstraints = false
        return iv
    }()

    private let statusDot: UIView = {
        let v = UIView()
        v.backgroundColor = .systemGreen
        v.layer.cornerRadius = 12
        v.layer.borderWidth = 3
        v.layer.borderColor = UIColor(white: 0.1, alpha: 1.0).cgColor
        v.translatesAutoresizingMaskIntoConstraints = false
        return v
    }()

    override init(frame: CGRect) {
        super.init(frame: frame)
        backgroundColor = UIColor(white: 0.1, alpha: 1.0)
        addSubview(avatarImageView)
        addSubview(statusDot)

        NSLayoutConstraint.activate([
            avatarImageView.centerXAnchor.constraint(equalTo: centerXAnchor),
            avatarImageView.centerYAnchor.constraint(equalTo: centerYAnchor),
            avatarImageView.widthAnchor.constraint(equalToConstant: 80),
            avatarImageView.heightAnchor.constraint(equalToConstant: 80),

            statusDot.widthAnchor.constraint(equalToConstant: 24),
            statusDot.heightAnchor.constraint(equalToConstant: 24),
            statusDot.bottomAnchor.constraint(equalTo: avatarImageView.bottomAnchor, constant: 2),
            statusDot.trailingAnchor.constraint(equalTo: avatarImageView.trailingAnchor, constant: 2)
        ])
    }

    required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") }
}
```

#### 3. SwiftUI Ekvivalenti

```swift
import SwiftUI

struct Task07SwiftUIView: View {
    var body: some View {
        ZStack {
            Color(white: 0.1).ignoresSafeArea()

            Circle()
                .fill(Color.purple)
                .frame(width: 80, height: 80)
                .overlay(
                    Circle()
                        .fill(Color.green)
                        .frame(width: 24, height: 24)
                        .overlay(Circle().stroke(Color(white: 0.1), lineWidth: 3))
                        .offset(x: 2, y: 2),
                    alignment: .bottomTrailing
                )
        }
    }
}
```

> 💡 **Pro Tip & Arxitektura siri:**
> Agar `avatarImageView.clipsToBounds = true` bo'lsa va siz `statusDot` ni uning ichiga (`avatarImageView.addSubview(statusDot)`) qo'shsangiz, chetdan chiqib turgan qismi qirqilib ketadi! Shu sababli doimo badge'larni tashqi umumiy view'ga qo'shib, keyin avatarga bog'lang.

</details>

---

## 🟡 Topshiriq 08: Moslashuvchan Xabar Pufakchasi (Chat Bubble)

> **Daraja:** `O'rta (Medium)` | **Maqsad:** Telegram yoki iMessage kabi dinamik chat pufakchasini yaratish: qisqa matnda kichrayishi, lekin eng ko'p cho'zilganida ham ekran kengligining 75% idan oshmasligi kerak.

Tengsizliklar (`greaterThanOrEqualTo` va `lessThanOrEqualTo`) bilan ishlash mahorati.

### Vizual Sxema (UI Mockup)

![Topshiriq 08: Moslashuvchan Xabar Pufakchasi (Chat Bubble)](/lessons/images/snapkit/task_08.svg)

### 📋 Texnik Talablar va Cheklovlar

- Pufakcha chap chetdan 16 pt masofada.
- Minimal kenglik: 60 pt (`greaterThanOrEqualTo`).
- Maksimal kenglik: ota-ona kengligining 75% qismi (`lessThanOrEqualToSuperview().multipliedBy(0.75)`).
- Matn ko'p qatorli bo'lishi mumkin (`numberOfLines = 0`), pufakcha ichidagi padding 12 pt.

<details>
<summary>💡 Kodni ko'rish (SnapKit, UIKit va SwiftUI yechimlari)</summary>

#### 1. SnapKit Yechimi (Asosiy)

```swift
import UIKit
import SnapKit

final class Task08View: UIView {
    private let bubbleView: UIView = {
        let v = UIView()
        v.backgroundColor = .systemBlue
        v.layer.cornerRadius = 16
        return v
    }()

    private let messageLabel: UILabel = {
        let l = UILabel()
        l.text = "SnapKit yordamida Auto Layout yozish juda qulay va kod hajmini 3 baravar qisqartiradi!"
        l.textColor = .white
        l.font = .systemFont(ofSize: 15)
        l.numberOfLines = 0
        return l
    }()

    override init(frame: CGRect) {
        super.init(frame: frame)
        setupUI()
    }

    required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") }

    private func setupUI() {
        backgroundColor = UIColor(white: 0.08, alpha: 1.0)
        addSubview(bubbleView)
        bubbleView.addSubview(messageLabel)

        bubbleView.snp.makeConstraints { make in
            make.top.equalToSuperview().offset(60)
            make.leading.equalToSuperview().offset(16)
            // Cheklovlar:
            make.width.greaterThanOrEqualTo(60)
            make.width.lessThanOrEqualToSuperview().multipliedBy(0.75)
        }

        messageLabel.snp.makeConstraints { make in
            make.edges.equalToSuperview().inset(12)
        }
    }
}
```

#### 2. Klassik UIKit (NSLayoutConstraint) Taqqoslash

```swift
import UIKit

final class Task08UIKitView: UIView {
    private let bubbleView: UIView = {
        let v = UIView()
        v.backgroundColor = .systemBlue
        v.layer.cornerRadius = 16
        v.translatesAutoresizingMaskIntoConstraints = false
        return v
    }()

    private let messageLabel: UILabel = {
        let l = UILabel()
        l.text = "SnapKit yordamida Auto Layout yozish juda qulay va kod hajmini 3 baravar qisqartiradi!"
        l.textColor = .white
        l.font = .systemFont(ofSize: 15)
        l.numberOfLines = 0
        l.translatesAutoresizingMaskIntoConstraints = false
        return l
    }()

    override init(frame: CGRect) {
        super.init(frame: frame)
        backgroundColor = UIColor(white: 0.08, alpha: 1.0)
        addSubview(bubbleView)
        bubbleView.addSubview(messageLabel)

        let maxConstraint = bubbleView.widthAnchor.constraint(
            lessThanOrEqualTo: widthAnchor,
            multiplier: 0.75
        )

        NSLayoutConstraint.activate([
            bubbleView.topAnchor.constraint(equalTo: topAnchor, constant: 60),
            bubbleView.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 16),
            bubbleView.widthAnchor.constraint(greaterThanOrEqualToConstant: 60),
            maxConstraint,

            messageLabel.topAnchor.constraint(equalTo: bubbleView.topAnchor, constant: 12),
            messageLabel.bottomAnchor.constraint(equalTo: bubbleView.bottomAnchor, constant: -12),
            messageLabel.leadingAnchor.constraint(equalTo: bubbleView.leadingAnchor, constant: 12),
            messageLabel.trailingAnchor.constraint(equalTo: bubbleView.trailingAnchor, constant: -12)
        ])
    }

    required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") }
}
```

#### 3. SwiftUI Ekvivalenti

```swift
import SwiftUI

struct Task08SwiftUIView: View {
    var body: some View {
        GeometryReader { proxy in
            VStack(alignment: .leading) {
                Text("SnapKit yordamida Auto Layout yozish juda qulay va kod hajmini 3 baravar qisqartiradi!")
                    .font(.system(size: 15))
                    .foregroundColor(.white)
                    .padding(12)
                    .background(Color.blue)
                    .clipShape(RoundedRectangle(cornerRadius: 16))
                    .frame(
                        minWidth: 60,
                        maxWidth: proxy.size.width * 0.75,
                        alignment: .leading
                    )
            }
            .padding(.horizontal, 16)
            .padding(.top, 60)
        }
        .background(Color(white: 0.08).ignoresSafeArea())
    }
}
```

> 💡 **Pro Tip & Arxitektura siri:**
> Matn bir necha qator bo'lishi uchun `numberOfLines = 0` bo'lishi shart. UILabel o'zining tabiiy o'lchamini (intrinsicContentSize) hisoblab chiqaradi va faqatgina 75% limitga urilgandagina keyingi satrga o'tadi.

</details>

---

## 🟡 Topshiriq 09: Uchta Teng Ustun (Three Equal Columns)

> **Daraja:** `O'rta (Medium)` | **Maqsad:** Gorizontal ravishda yonma-yon joylashgan, kengligi bir-biriga mutlaqo teng bo'lgan va orasi 16 pt dan bo'lgan 3 ta kartani hosil qilish.

Teng kengliklarni zanjir usulida bir-biriga tenglash (`make.width.equalTo(card1)`) va chekka chegaralarni to'g'ri yopish.

### Vizual Sxema (UI Mockup)

![Topshiriq 09: Uchta Teng Ustun (Three Equal Columns)](/lessons/images/snapkit/task_09.svg)

### 📋 Texnik Talablar va Cheklovlar

- 3 ta karta ekranning chap va o'ng chegarasidan 16 pt oraliqda bo'lsin.
- Kartalar orasidagi masofa aynan 16 pt.
- Har bir kartaning kengligi bir xil bo'lishi va balandligi 120 pt bo'lishi shart.

<details>
<summary>💡 Kodni ko'rish (SnapKit, UIKit va SwiftUI yechimlari)</summary>

#### 1. SnapKit Yechimi (Asosiy)

```swift
import UIKit
import SnapKit

final class Task09View: UIView {
    private let card1 = UIView()
    private let card2 = UIView()
    private let card3 = UIView()

    override init(frame: CGRect) {
        super.init(frame: frame)
        setupUI()
    }

    required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") }

    private func setupUI() {
        backgroundColor = UIColor(white: 0.08, alpha: 1.0)
        [card1, card2, card3].enumerated().forEach { index, card in
            card.backgroundColor = [UIColor.systemBlue, UIColor.systemPurple, UIColor.systemGreen][index]
            card.layer.cornerRadius = 12
            addSubview(card)
        }

        card1.snp.makeConstraints { make in
            make.centerY.equalToSuperview()
            make.leading.equalToSuperview().offset(16)
            make.height.equalTo(120)
        }

        card2.snp.makeConstraints { make in
            make.centerY.equalToSuperview()
            make.leading.equalTo(card1.snp.trailing).offset(16)
            make.width.equalTo(card1) // 1-karta bilan teng kenglik
            make.height.equalTo(120)
        }

        card3.snp.makeConstraints { make in
            make.centerY.equalToSuperview()
            make.leading.equalTo(card2.snp.trailing).offset(16)
            make.trailing.equalToSuperview().offset(-16) // o'ng tomonga qadaladi
            make.width.equalTo(card1) // 1-karta bilan teng kenglik
            make.height.equalTo(120)
        }
    }
}
```

#### 2. Klassik UIKit (NSLayoutConstraint) Taqqoslash

```swift
import UIKit

final class Task09UIKitView: UIView {
    private let card1 = UIView()
    private let card2 = UIView()
    private let card3 = UIView()

    override init(frame: CGRect) {
        super.init(frame: frame)
        backgroundColor = UIColor(white: 0.08, alpha: 1.0)

        [card1, card2, card3].enumerated().forEach { index, card in
            card.backgroundColor = [UIColor.systemBlue, UIColor.systemPurple, UIColor.systemGreen][index]
            card.layer.cornerRadius = 12
            card.translatesAutoresizingMaskIntoConstraints = false
            addSubview(card)
        }

        NSLayoutConstraint.activate([
            card1.centerYAnchor.constraint(equalTo: centerYAnchor),
            card1.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 16),
            card1.heightAnchor.constraint(equalToConstant: 120),

            card2.centerYAnchor.constraint(equalTo: centerYAnchor),
            card2.leadingAnchor.constraint(equalTo: card1.trailingAnchor, constant: 16),
            card2.widthAnchor.constraint(equalTo: card1.widthAnchor),
            card2.heightAnchor.constraint(equalToConstant: 120),

            card3.centerYAnchor.constraint(equalTo: centerYAnchor),
            card3.leadingAnchor.constraint(equalTo: card2.trailingAnchor, constant: 16),
            card3.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -16),
            card3.widthAnchor.constraint(equalTo: card1.widthAnchor),
            card3.heightAnchor.constraint(equalToConstant: 120)
        ])
    }

    required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") }
}
```

#### 3. SwiftUI Ekvivalenti

```swift
import SwiftUI

struct Task09SwiftUIView: View {
    var body: some View {
        HStack(spacing: 16) {
            RoundedRectangle(cornerRadius: 12)
                .fill(Color.blue)
                .frame(height: 120)

            RoundedRectangle(cornerRadius: 12)
                .fill(Color.purple)
                .frame(height: 120)

            RoundedRectangle(cornerRadius: 12)
                .fill(Color.green)
                .frame(height: 120)
        }
        .padding(.horizontal, 16)
        .background(Color(white: 0.08).ignoresSafeArea())
    }
}
```

> 💡 **Pro Tip & Arxitektura siri:**
> Matematik formulaga e'tibor bering: 3 ta karta va 4 ta masofa (chap, 2 ta o'rtadagi, o'ng) berildi va oxirgi karta `trailing` ga qadalgach, Auto Layout har bir kartaning kengligini har qanday qurilma o'lchamida mustaqil hisoblab beradi.

</details>

---

## 🟡 Topshiriq 10: Sarlavha va Sana: Content Compression Resistance Priority

> **Daraja:** `O'rta (Medium)` | **Maqsad:** Bitta qatorda chapda sarlavha, o'ngda sana. Agar sarlavha matni haddan tashqari uzun bo'lib ketsa ham, sana hech qachon siqilib qisqarmasligi, aksincha sarlavha '...' (truncate) bo'lishi kerak.

Constraint Priority, Content Compression Resistance va Content Hugging tushunchalarini amalda hal qilish.

### Vizual Sxema (UI Mockup)

![Topshiriq 10: Sarlavha va Sana: Content Compression Resistance Priority](/lessons/images/snapkit/task_10.svg)

### 📋 Texnik Talablar va Cheklovlar

- titleLabel: chapda, uzayganda sig'may qolsa uch nuqta bo'lsin (`.byTruncatingTail`).
- dateLabel: o'ngda, hech qachon qisqarmasin va matni to'liq ko'rinsin.
- dateLabel'ning `contentCompressionResistancePriority` darajasi `.required` (1000) ga ko'tarilsin, titleLabel'niki esa `.defaultLow` (250) bo'lsin.

<details>
<summary>💡 Kodni ko'rish (SnapKit, UIKit va SwiftUI yechimlari)</summary>

#### 1. SnapKit Yechimi (Asosiy)

```swift
import UIKit
import SnapKit

final class Task10View: UIView {
    private let titleLabel: UILabel = {
        let l = UILabel()
        l.text = "Juda uzun topshiriq sarlavhasi: SnapKit va UIKit Auto Layout arxitekturasini o'rganish"
        l.textColor = .white
        l.font = .systemFont(ofSize: 15, weight: .semibold)
        l.lineBreakMode = .byTruncatingTail
        return l
    }()

    private let dateLabel: UILabel = {
        let l = UILabel()
        l.text = "Bugun, 18:30"
        l.textColor = .systemBlue
        l.font = .systemFont(ofSize: 13, weight: .bold)
        return l
    }()

    override init(frame: CGRect) {
        super.init(frame: frame)
        setupUI()
    }

    required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") }

    private func setupUI() {
        backgroundColor = UIColor(white: 0.1, alpha: 1.0)
        addSubview(titleLabel)
        addSubview(dateLabel)

        // Sanani siqilishdan qutqaruvchi kalit qator:
        dateLabel.setContentCompressionResistancePriority(.required, for: .horizontal)
        titleLabel.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)

        titleLabel.snp.makeConstraints { make in
            make.centerY.equalToSuperview()
            make.leading.equalToSuperview().offset(16)
            make.trailing.lessThanOrEqualTo(dateLabel.snp.leading).offset(-12)
        }

        dateLabel.snp.makeConstraints { make in
            make.centerY.equalToSuperview()
            make.trailing.equalToSuperview().offset(-16)
        }
    }
}
```

#### 2. Klassik UIKit (NSLayoutConstraint) Taqqoslash

```swift
import UIKit

final class Task10UIKitView: UIView {
    private let titleLabel: UILabel = {
        let l = UILabel()
        l.text = "Juda uzun topshiriq sarlavhasi: SnapKit va UIKit Auto Layout arxitekturasini o'rganish"
        l.textColor = .white
        l.font = .systemFont(ofSize: 15, weight: .semibold)
        l.lineBreakMode = .byTruncatingTail
        l.translatesAutoresizingMaskIntoConstraints = false
        return l
    }()

    private let dateLabel: UILabel = {
        let l = UILabel()
        l.text = "Bugun, 18:30"
        l.textColor = .systemBlue
        l.font = .systemFont(ofSize: 13, weight: .bold)
        l.translatesAutoresizingMaskIntoConstraints = false
        return l
    }()

    override init(frame: CGRect) {
        super.init(frame: frame)
        backgroundColor = UIColor(white: 0.1, alpha: 1.0)
        addSubview(titleLabel)
        addSubview(dateLabel)

        dateLabel.setContentCompressionResistancePriority(.required, for: .horizontal)
        titleLabel.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)

        NSLayoutConstraint.activate([
            titleLabel.centerYAnchor.constraint(equalTo: centerYAnchor),
            titleLabel.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 16),
            titleLabel.trailingAnchor.constraint(lessThanOrEqualTo: dateLabel.leadingAnchor, constant: -12),

            dateLabel.centerYAnchor.constraint(equalTo: centerYAnchor),
            dateLabel.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -16)
        ])
    }

    required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") }
}
```

#### 3. SwiftUI Ekvivalenti

```swift
import SwiftUI

struct Task10SwiftUIView: View {
    var body: some View {
        HStack(spacing: 12) {
            Text("Juda uzun topshiriq sarlavhasi: SnapKit va UIKit Auto Layout arxitekturasini o'rganish")
                .font(.system(size: 15, weight: .semibold))
                .foregroundColor(.white)
                .lineLimit(1)
                .truncationMode(.tail)

            Text("Bugun, 18:30")
                .font(.system(size: 13, weight: .bold))
                .foregroundColor(.blue)
                .fixedSize(horizontal: true, vertical: false) // Siqilishdan himoya
        }
        .padding(.horizontal, 16)
        .frame(height: 60)
        .background(Color(white: 0.1).ignoresSafeArea())
    }
}
```

> 💡 **Pro Tip & Arxitektura siri:**
> Intervyularda eng ko'p beriladigan savol: 'Ikki label yonma-yon turganda qaysi biri qisqarishini qanday boshqarasiz?' Javob: `setContentCompressionResistancePriority` orqali. Qaysi view'ning priority'si kichik bo'lsa (250), o'sha view birinchi bo'lib qisqaradi!

</details>

---

## 🟡 Topshiriq 11: Bildirishnoma Kartasi va Yopish Tugmasi

> **Daraja:** `O'rta (Medium)` | **Maqsad:** Ekranning yuqorisida bildirishnoma banneri: chapda 36x36 icon, o'rtada 2 qatorli xabar matni, o'ngda esa 28x28 yopish tugmasi ('✕').

Uchta elementdan iborat gorizontal zanjir (Icon -> Flexible Text Stack -> Action Button) va ularni to'g'ri oraliqlar bilan joylashtirish.

### Vizual Sxema (UI Mockup)

![Topshiriq 11: Bildirishnoma Kartasi va Yopish Tugmasi](/lessons/images/snapkit/task_11.svg)

### 📋 Texnik Talablar va Cheklovlar

- Banner: balandligi 80 pt, chetlaridan 16 pt oraliq, burchaklar radiusi 14 pt.
- IconView: 36x36 pt, chapdan 16 pt, vertikal markazda.
- CloseButton: 28x28 pt, o'ngdan 16 pt, vertikal markazda.
- Matnlar maydoni Icon va CloseButton oralig'ini to'liq egallasin (orasi 12 pt dan).

<details>
<summary>💡 Kodni ko'rish (SnapKit, UIKit va SwiftUI yechimlari)</summary>

#### 1. SnapKit Yechimi (Asosiy)

```swift
import UIKit
import SnapKit

final class Task11View: UIView {
    private let bannerCard: UIView = {
        let v = UIView()
        v.backgroundColor = UIColor(white: 0.15, alpha: 1.0)
        v.layer.cornerRadius = 14
        v.layer.borderWidth = 1
        v.layer.borderColor = UIColor.systemSky?.cgColor ?? UIColor.systemBlue.cgColor
        return v
    }()

    private let iconImageView: UIImageView = {
        let iv = UIImageView()
        iv.image = UIImage(systemName: "bell.badge.fill")
        iv.tintColor = .systemSky ?? .systemBlue
        iv.contentMode = .scaleAspectFit
        return iv
    }()

    private let titleLabel: UILabel = {
        let l = UILabel()
        l.text = "Yangi topshiriq tayyor"
        l.textColor = .white
        l.font = .systemFont(ofSize: 14, weight: .bold)
        return l
    }()

    private let bodyLabel: UILabel = {
        let l = UILabel()
        l.text = "SnapKit kursidan 20 ta amaliy vazifani boshlang."
        l.textColor = .systemGray
        l.font = .systemFont(ofSize: 11)
        l.numberOfLines = 2
        return l
    }()

    private let closeButton: UIButton = {
        let btn = UIButton(type: .system)
        btn.setTitle("✕", for: .normal)
        btn.setTitleColor(.white, for: .normal)
        btn.titleLabel?.font = .systemFont(ofSize: 13, weight: .bold)
        btn.backgroundColor = UIColor(white: 0.25, alpha: 1.0)
        btn.layer.cornerRadius = 14
        return btn
    }()

    override init(frame: CGRect) {
        super.init(frame: frame)
        setupUI()
    }

    required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") }

    private func setupUI() {
        backgroundColor = UIColor(white: 0.08, alpha: 1.0)
        addSubview(bannerCard)
        bannerCard.addSubview(iconImageView)
        bannerCard.addSubview(titleLabel)
        bannerCard.addSubview(bodyLabel)
        bannerCard.addSubview(closeButton)

        bannerCard.snp.makeConstraints { make in
            make.top.equalToSuperview().offset(60)
            make.leading.trailing.equalToSuperview().inset(16)
            make.height.equalTo(80)
        }

        iconImageView.snp.makeConstraints { make in
            make.centerY.equalToSuperview()
            make.leading.equalToSuperview().offset(16)
            make.size.equalTo(36)
        }

        closeButton.snp.makeConstraints { make in
            make.centerY.equalToSuperview()
            make.trailing.equalToSuperview().offset(-16)
            make.size.equalTo(28)
        }

        titleLabel.snp.makeConstraints { make in
            make.top.equalToSuperview().offset(16)
            make.leading.equalTo(iconImageView.snp.trailing).offset(12)
            make.trailing.equalTo(closeButton.snp.leading).offset(-12)
        }

        bodyLabel.snp.makeConstraints { make in
            make.top.equalTo(titleLabel.snp.bottom).offset(4)
            make.leading.trailing.equalTo(titleLabel)
        }
    }
}

private extension UIColor {
    static var systemSky: UIColor? { UIColor(red: 0.22, green: 0.74, blue: 0.97, alpha: 1.0) }
}
```

#### 2. Klassik UIKit (NSLayoutConstraint) Taqqoslash

```swift
import UIKit

final class Task11UIKitView: UIView {
    private let bannerCard: UIView = {
        let v = UIView()
        v.backgroundColor = UIColor(white: 0.15, alpha: 1.0)
        v.layer.cornerRadius = 14
        v.translatesAutoresizingMaskIntoConstraints = false
        return v
    }()

    private let iconImageView: UIImageView = {
        let iv = UIImageView()
        iv.image = UIImage(systemName: "bell.badge.fill")
        iv.tintColor = .systemBlue
        iv.translatesAutoresizingMaskIntoConstraints = false
        return iv
    }()

    private let titleLabel: UILabel = {
        let l = UILabel()
        l.text = "Yangi topshiriq tayyor"
        l.textColor = .white
        l.font = .systemFont(ofSize: 14, weight: .bold)
        l.translatesAutoresizingMaskIntoConstraints = false
        return l
    }()

    private let closeButton: UIButton = {
        let btn = UIButton(type: .system)
        btn.setTitle("✕", for: .normal)
        btn.backgroundColor = UIColor(white: 0.25, alpha: 1.0)
        btn.layer.cornerRadius = 14
        btn.translatesAutoresizingMaskIntoConstraints = false
        return btn
    }()

    override init(frame: CGRect) {
        super.init(frame: frame)
        backgroundColor = UIColor(white: 0.08, alpha: 1.0)
        addSubview(bannerCard)
        bannerCard.addSubview(iconImageView)
        bannerCard.addSubview(titleLabel)
        bannerCard.addSubview(closeButton)

        NSLayoutConstraint.activate([
            bannerCard.topAnchor.constraint(equalTo: topAnchor, constant: 60),
            bannerCard.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 16),
            bannerCard.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -16),
            bannerCard.heightAnchor.constraint(equalToConstant: 80),

            iconImageView.centerYAnchor.constraint(equalTo: bannerCard.centerYAnchor),
            iconImageView.leadingAnchor.constraint(equalTo: bannerCard.leadingAnchor, constant: 16),
            iconImageView.widthAnchor.constraint(equalToConstant: 36),
            iconImageView.heightAnchor.constraint(equalToConstant: 36),

            closeButton.centerYAnchor.constraint(equalTo: bannerCard.centerYAnchor),
            closeButton.trailingAnchor.constraint(equalTo: bannerCard.trailingAnchor, constant: -16),
            closeButton.widthAnchor.constraint(equalToConstant: 28),
            closeButton.heightAnchor.constraint(equalToConstant: 28),

            titleLabel.centerYAnchor.constraint(equalTo: bannerCard.centerYAnchor),
            titleLabel.leadingAnchor.constraint(equalTo: iconImageView.trailingAnchor, constant: 12),
            titleLabel.trailingAnchor.constraint(equalTo: closeButton.leadingAnchor, constant: -12)
        ])
    }

    required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") }
}
```

#### 3. SwiftUI Ekvivalenti

```swift
import SwiftUI

struct Task11SwiftUIView: View {
    var body: some View {
        HStack(spacing: 12) {
            Image(systemName: "bell.badge.fill")
                .font(.system(size: 20))
                .foregroundColor(.blue)
                .frame(width: 36, height: 36)

            VStack(alignment: .leading, spacing: 4) {
                Text("Yangi topshiriq tayyor")
                    .font(.system(size: 14, weight: .bold))
                    .foregroundColor(.white)

                Text("SnapKit kursidan 20 ta amaliy vazifani boshlang.")
                    .font(.system(size: 11))
                    .foregroundColor(.gray)
                    .lineLimit(2)
            }

            Spacer()

            Button(action: {}) {
                Text("✕")
                    .font(.system(size: 13, weight: .bold))
                    .foregroundColor(.white)
                    .frame(width: 28, height: 28)
                    .background(Color(white: 0.25))
                    .clipShape(Circle())
            }
        }
        .padding(16)
        .frame(height: 80)
        .background(Color(white: 0.15))
        .clipShape(RoundedRectangle(cornerRadius: 14))
        .padding(.horizontal, 16)
        .padding(.top, 60)
        .background(Color(white: 0.08).ignoresSafeArea())
    }
}
```

> 💡 **Pro Tip & Arxitektura siri:**
> Matn maydonining o'ng tomonini qat'iy ravishda `closeButton.snp.leading` ga bog'lang. Bu orqali xabar matni har qancha uzun bo'lsa ham yopish tugmasining ustiga chiqib ketmaydi.

</details>

---

## 🟠 Topshiriq 12: Do'kon Mahsulot Kartasi (Product Grid Card)

> **Daraja:** `Qiyin (Hard)` | **Maqsad:** Zamonaviy e-commerce kartasi: rasm, uning burchagidagi chegarma nishoni, sarlavha, narx va pastki o'ngdagi dumaloq qo'shish tugmasi ('+').

Murakkab vizual ierarxiya, elementlararo bog'lanish va nisbatlarni toza boshqarish.

### Vizual Sxema (UI Mockup)

![Topshiriq 12: Do'kon Mahsulot Kartasi (Product Grid Card)](/lessons/images/snapkit/task_12.svg)

### 📋 Texnik Talablar va Cheklovlar

- Karta: kengligi 220 pt, burchak radiusi 16 pt, fon to'q rangda.
- Mahsulot rasmi: kartaning yuqori qismida, balandligi 110 pt, ichki margin 12 pt.
- Chegarma nishoni (-25%): rasmining yuqori-chap burchagida 8 pt oraliqda.
- Title va Category rasmdan pastda.
- Pastda yashil narx ($249) va uning o'ng tomonida 36x36 o'lchamli dumaloq sariq '+' tugmasi.

<details>
<summary>💡 Kodni ko'rish (SnapKit, UIKit va SwiftUI yechimlari)</summary>

#### 1. SnapKit Yechimi (Asosiy)

```swift
import UIKit
import SnapKit

final class Task12ProductCardView: UIView {
    private let productImageView: UIImageView = {
        let iv = UIImageView()
        iv.backgroundColor = UIColor(white: 0.1, alpha: 1.0)
        iv.layer.cornerRadius = 10
        iv.clipsToBounds = true
        return iv
    }()

    private let discountBadge: UILabel = {
        let l = UILabel()
        l.text = "-25%"
        l.textColor = .white
        l.font = .systemFont(ofSize: 10, weight: .heavy)
        l.backgroundColor = .systemPink
        l.textAlignment = .center
        l.layer.cornerRadius = 4
        l.clipsToBounds = true
        return l
    }()

    private let titleLabel: UILabel = {
        let l = UILabel()
        l.text = "AirPods Pro 2"
        l.textColor = .white
        l.font = .systemFont(ofSize: 14, weight: .bold)
        return l
    }()

    private let subtitleLabel: UILabel = {
        let l = UILabel()
        l.text = "Noise Cancellation"
        l.textColor = .systemGray
        l.font = .systemFont(ofSize: 10)
        return l
    }()

    private let priceLabel: UILabel = {
        let l = UILabel()
        l.text = "$249"
        l.textColor = .systemGreen
        l.font = .systemFont(ofSize: 16, weight: .heavy)
        return l
    }()

    private let addButton: UIButton = {
        let btn = UIButton(type: .system)
        btn.setTitle("+", for: .normal)
        btn.setTitleColor(.white, for: .normal)
        btn.titleLabel?.font = .systemFont(ofSize: 20, weight: .bold)
        btn.backgroundColor = .systemOrange
        btn.layer.cornerRadius = 18
        return btn
    }()

    override init(frame: CGRect) {
        super.init(frame: frame)
        setupUI()
    }

    required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") }

    private func setupUI() {
        backgroundColor = UIColor(white: 0.16, alpha: 1.0)
        layer.cornerRadius = 16
        layer.borderWidth = 1.5
        layer.borderColor = UIColor.systemOrange.cgColor

        addSubview(productImageView)
        addSubview(discountBadge)
        addSubview(titleLabel)
        addSubview(subtitleLabel)
        addSubview(priceLabel)
        addSubview(addButton)

        productImageView.snp.makeConstraints { make in
            make.top.leading.trailing.equalToSuperview().inset(12)
            make.height.equalTo(110)
        }

        discountBadge.snp.makeConstraints { make in
            make.top.leading.equalTo(productImageView).offset(8)
            make.size.equalTo(CGSize(width: 44, height: 20))
        }

        titleLabel.snp.makeConstraints { make in
            make.top.equalTo(productImageView.snp.bottom).offset(10)
            make.leading.trailing.equalToSuperview().inset(12)
        }

        subtitleLabel.snp.makeConstraints { make in
            make.top.equalTo(titleLabel.snp.bottom).offset(2)
            make.leading.trailing.equalTo(titleLabel)
        }

        addButton.snp.makeConstraints { make in
            make.trailing.bottom.equalToSuperview().inset(12)
            make.size.equalTo(36)
        }

        priceLabel.snp.makeConstraints { make in
            make.centerY.equalTo(addButton)
            make.leading.equalToSuperview().offset(12)
            make.trailing.lessThanOrEqualTo(addButton.snp.leading).offset(-8)
        }
    }
}
```

#### 2. Klassik UIKit (NSLayoutConstraint) Taqqoslash

```swift
import UIKit

final class Task12UIKitProductCardView: UIView {
    // UI elementlari translatesAutoresizingMaskIntoConstraints = false bilan
    private let productImageView = UIView()
    private let titleLabel = UILabel()
    private let priceLabel = UILabel()
    private let addButton = UIButton(type: .system)

    override init(frame: CGRect) {
        super.init(frame: frame)
        backgroundColor = UIColor(white: 0.16, alpha: 1.0)
        layer.cornerRadius = 16

        [productImageView, titleLabel, priceLabel, addButton].forEach {
            $0.translatesAutoresizingMaskIntoConstraints = false
            addSubview($0)
        }

        NSLayoutConstraint.activate([
            productImageView.topAnchor.constraint(equalTo: topAnchor, constant: 12),
            productImageView.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 12),
            productImageView.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -12),
            productImageView.heightAnchor.constraint(equalToConstant: 110),

            titleLabel.topAnchor.constraint(equalTo: productImageView.bottomAnchor, constant: 10),
            titleLabel.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 12),
            titleLabel.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -12),

            addButton.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -12),
            addButton.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -12),
            addButton.widthAnchor.constraint(equalToConstant: 36),
            addButton.heightAnchor.constraint(equalToConstant: 36),

            priceLabel.centerYAnchor.constraint(equalTo: addButton.centerYAnchor),
            priceLabel.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 12),
            priceLabel.trailingAnchor.constraint(lessThanOrEqualTo: addButton.leadingAnchor, constant: -8)
        ])
    }

    required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") }
}
```

#### 3. SwiftUI Ekvivalenti

```swift
import SwiftUI

struct Task12SwiftUIView: View {
    var body: some View {
        VStack(alignment: .leading, spacing: 8) {
            ZStack(alignment: .topLeading) {
                RoundedRectangle(cornerRadius: 10)
                    .fill(Color(white: 0.1))
                    .frame(height: 110)

                Text("-25%")
                    .font(.system(size: 10, weight: .heavy))
                    .foregroundColor(.white)
                    .padding(.horizontal, 6)
                    .padding(.vertical, 3)
                    .background(Color.pink)
                    .clipShape(RoundedRectangle(cornerRadius: 4))
                    .padding(8)
            }

            Text("AirPods Pro 2")
                .font(.system(size: 14, weight: .bold))
                .foregroundColor(.white)

            Text("Noise Cancellation")
                .font(.system(size: 10))
                .foregroundColor(.gray)

            HStack {
                Text("$249")
                    .font(.system(size: 16, weight: .heavy))
                    .foregroundColor(.green)

                Spacer()

                Button(action: {}) {
                    Image(systemName: "plus")
                        .font(.system(size: 14, weight: .bold))
                        .foregroundColor(.white)
                        .frame(width: 36, height: 36)
                        .background(Color.orange)
                        .clipShape(Circle())
                }
            }
        }
        .padding(12)
        .frame(width: 220)
        .background(Color(white: 0.16))
        .clipShape(RoundedRectangle(cornerRadius: 16))
    }
}
```

> 💡 **Pro Tip & Arxitektura siri:**
> Tugma va narxni joylashtirishda `priceLabel.centerY.equalTo(addButton)` deb belgilash mukammal vertikal simmetriyani kafolatlaydi. Shuningdek, `addButton.trailing.bottom.equalToSuperview().inset(12)` kartaning pastki chegarasini ushlab turadi.

</details>

---

## 🟠 Topshiriq 13: Floating Action Button (Yarim Chiqib Turgan Tugma)

> **Daraja:** `Qiyin (Hard)` | **Maqsad:** Ekranning pastki panelidan (Bottom Tab Bar) tepaga teng yarmi chiqib turgan dumaloq Floating Action Button (FAB) yaratish.

Markazlashtirish o'qini boshqa view'ning yuqori qirrasiga (`make.centerY.equalTo(bottomBar.snp.top)`) bog'lash sir-asrori.

### Vizual Sxema (UI Mockup)

![Topshiriq 13: Floating Action Button (Yarim Chiqib Turgan Tugma)](/lessons/images/snapkit/task_13.svg)

### 📋 Texnik Talablar va Cheklovlar

- Bottom bar ekranning eng pastiga yopishsin, balandligi 70 pt.
- FAB tugmasi 56x56 pt o'lchamda, to'liq doira (radius: 28 pt).
- FAB tugmasining vertikal markazi aynan bottom bar'ning ustki chizig'iga (`top`) to'g'ri kelsin.
- FAB gorizontal tomondan butun ekranning markazida bo'lsin.

<details>
<summary>💡 Kodni ko'rish (SnapKit, UIKit va SwiftUI yechimlari)</summary>

#### 1. SnapKit Yechimi (Asosiy)

```swift
import UIKit
import SnapKit

final class Task13View: UIView {
    private let bottomBar: UIView = {
        let v = UIView()
        v.backgroundColor = UIColor(white: 0.15, alpha: 1.0)
        v.layer.borderWidth = 1
        v.layer.borderColor = UIColor(white: 0.25, alpha: 1.0).cgColor
        return v
    }()

    private let fabButton: UIButton = {
        let btn = UIButton(type: .system)
        btn.setTitle("+", for: .normal)
        btn.setTitleColor(.white, for: .normal)
        btn.titleLabel?.font = .systemFont(ofSize: 28, weight: .medium)
        btn.backgroundColor = .systemBlue
        btn.layer.cornerRadius = 28
        btn.layer.shadowColor = UIColor.systemBlue.cgColor
        btn.layer.shadowOpacity = 0.5
        btn.layer.shadowOffset = CGSize(width: 0, height: 4)
        btn.layer.shadowRadius = 8
        return btn
    }()

    override init(frame: CGRect) {
        super.init(frame: frame)
        setupUI()
    }

    required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") }

    private func setupUI() {
        backgroundColor = UIColor(white: 0.08, alpha: 1.0)
        addSubview(bottomBar)
        addSubview(fabButton) // FAB barchasidan ustun turishi shart!

        bottomBar.snp.makeConstraints { make in
            make.leading.trailing.bottom.equalToSuperview()
            make.height.equalTo(70)
        }

        fabButton.snp.makeConstraints { make in
            make.centerX.equalToSuperview()
            // Eng asosiy sir: markazni bottomBar ustiga bog'lash:
            make.centerY.equalTo(bottomBar.snp.top)
            make.size.equalTo(56)
        }
    }
}
```

#### 2. Klassik UIKit (NSLayoutConstraint) Taqqoslash

```swift
import UIKit

final class Task13UIKitView: UIView {
    private let bottomBar = UIView()
    private let fabButton = UIButton(type: .system)

    override init(frame: CGRect) {
        super.init(frame: frame)
        backgroundColor = UIColor(white: 0.08, alpha: 1.0)
        bottomBar.backgroundColor = UIColor(white: 0.15, alpha: 1.0)
        fabButton.backgroundColor = .systemBlue
        fabButton.layer.cornerRadius = 28

        [bottomBar, fabButton].forEach {
            $0.translatesAutoresizingMaskIntoConstraints = false
            addSubview($0)
        }

        NSLayoutConstraint.activate([
            bottomBar.leadingAnchor.constraint(equalTo: leadingAnchor),
            bottomBar.trailingAnchor.constraint(equalTo: trailingAnchor),
            bottomBar.bottomAnchor.constraint(equalTo: bottomAnchor),
            bottomBar.heightAnchor.constraint(equalToConstant: 70),

            fabButton.centerXAnchor.constraint(equalTo: centerXAnchor),
            // Fab markazi bottomBar ning ustki chegarasiga teng:
            fabButton.centerYAnchor.constraint(equalTo: bottomBar.topAnchor),
            fabButton.widthAnchor.constraint(equalToConstant: 56),
            fabButton.heightAnchor.constraint(equalToConstant: 56)
        ])
    }

    required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") }
}
```

#### 3. SwiftUI Ekvivalenti

```swift
import SwiftUI

struct Task13SwiftUIView: View {
    var body: some View {
        ZStack(alignment: .bottom) {
            Color(white: 0.08).ignoresSafeArea()

            // Bottom Bar
            Rectangle()
                .fill(Color(white: 0.15))
                .frame(height: 70)
                .overlay(
                    // FAB Floating Center
                    Button(action: {}) {
                        Image(systemName: "plus")
                            .font(.system(size: 24, weight: .bold))
                            .foregroundColor(.white)
                            .frame(width: 56, height: 56)
                            .background(Color.blue)
                            .clipShape(Circle())
                            .shadow(color: .blue.opacity(0.5), radius: 8, y: 4)
                    }
                    .offset(y: -28), // Yarmi (56/2) tepaga chiqadi
                    alignment: .top
                )
        }
    }
}
```

> 💡 **Pro Tip & Arxitektura siri:**
> Agar siz `fabButton` ni `bottomBar.addSubview(fabButton)` qilsangiz va `bottomBar.clipsToBounds = true` bo'lsa, chiqib turgan tepa qismi qirqiladi. Har doim FAB'ni ota-ona view'ga (`view.addSubview(fabButton)`) qo'shing!

</details>

---

## 🟠 Topshiriq 14: O'zgaruvchan Matnli Izoh Qatori (Self-Sizing Cell)

> **Daraja:** `Qiyin (Hard)` | **Maqsad:** UITableViewCell ichida izoh matni qancha uzun yoki qisqa bo'lishidan qat'i nazar, katak balandligi avtomatik ravishda moslashuvchi (self-sizing) qilish.

Auto Layout'ning eng muhim oltin qoidasi: 'Tepadan boshlab eng pastki elementgacha uzluksiz zanjir bog'lanishi va oxirgi element pastki qirra (`bottom.equalToSuperview()`) bilan tugashi shart!'.

### Vizual Sxema (UI Mockup)

![Topshiriq 14: O'zgaruvchan Matnli Izoh Qatori (Self-Sizing Cell)](/lessons/images/snapkit/task_14.svg)

### 📋 Texnik Talablar va Cheklovlar

- Avatar: 36x36 pt, burchakda.
- Muallif ismi va sanasi tepada.
- Izoh matni (`commentLabel`): `numberOfLines = 0`.
- Hujayraning balandligi statik raqamsiz, faqat matn hajmiga ko'ra avtomatik hisoblanishi kerak.

<details>
<summary>💡 Kodni ko'rish (SnapKit, UIKit va SwiftUI yechimlari)</summary>

#### 1. SnapKit Yechimi (Asosiy)

```swift
import UIKit
import SnapKit

final class CommentTableViewCell: UITableViewCell {
    private let avatarImageView: UIImageView = {
        let iv = UIImageView()
        iv.backgroundColor = .systemPurple
        iv.layer.cornerRadius = 18
        iv.clipsToBounds = true
        return iv
    }()

    private let authorLabel: UILabel = {
        let l = UILabel()
        l.textColor = .white
        l.font = .systemFont(ofSize: 14, weight: .bold)
        return l
    }()

    private let timeLabel: UILabel = {
        let l = UILabel()
        l.textColor = .systemGray
        l.font = .systemFont(ofSize: 11)
        return l
    }()

    private let commentLabel: UILabel = {
        let l = UILabel()
        l.textColor = UIColor(white: 0.9, alpha: 1.0)
        l.font = .systemFont(ofSize: 13)
        l.numberOfLines = 0 // Majburiy!
        return l
    }()

    override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)
        setupUI()
    }

    required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") }

    private func setupUI() {
        backgroundColor = .clear
        contentView.backgroundColor = UIColor(white: 0.12, alpha: 1.0)

        contentView.addSubview(avatarImageView)
        contentView.addSubview(authorLabel)
        contentView.addSubview(timeLabel)
        contentView.addSubview(commentLabel)

        avatarImageView.snp.makeConstraints { make in
            make.top.leading.equalToSuperview().offset(16)
            make.size.equalTo(36)
        }

        authorLabel.snp.makeConstraints { make in
            make.top.equalTo(avatarImageView)
            make.leading.equalTo(avatarImageView.snp.trailing).offset(12)
        }

        timeLabel.snp.makeConstraints { make in
            make.centerY.equalTo(authorLabel)
            make.leading.equalTo(authorLabel.snp.trailing).offset(8)
            make.trailing.lessThanOrEqualToSuperview().offset(-16)
        }

        commentLabel.snp.makeConstraints { make in
            make.top.equalTo(authorLabel.snp.bottom).offset(8)
            make.leading.equalTo(authorLabel)
            make.trailing.equalToSuperview().offset(-16)
            // Oltin qoida: pastki element contentView.bottom ga bog'lanishi SHART:
            make.bottom.equalToSuperview().offset(-16)
        }
    }
}
```

#### 2. Klassik UIKit (NSLayoutConstraint) Taqqoslash

```swift
import UIKit

final class CommentTableViewUIKitCell: UITableViewCell {
    private let commentLabel: UILabel = {
        let l = UILabel()
        l.numberOfLines = 0
        l.translatesAutoresizingMaskIntoConstraints = false
        return l
    }()

    override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)
        contentView.addSubview(commentLabel)

        NSLayoutConstraint.activate([
            commentLabel.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 16),
            commentLabel.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 16),
            commentLabel.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -16),
            // Cell self-sizing uchun bottom anchor:
            commentLabel.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -16)
        ])
    }

    required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") }
}
```

#### 3. SwiftUI Ekvivalenti

```swift
import SwiftUI

struct CommentRowSwiftUIView: View {
    let author: String
    let time: String
    let text: String

    var body: some View {
        HStack(alignment: .top, spacing: 12) {
            Circle()
                .fill(Color.purple)
                .frame(width: 36, height: 36)

            VStack(alignment: .leading, spacing: 6) {
                HStack(spacing: 8) {
                    Text(author)
                        .font(.system(size: 14, weight: .bold))
                        .foregroundColor(.white)
                    Text(time)
                        .font(.system(size: 11))
                        .foregroundColor(.gray)
                }

                Text(text)
                    .font(.system(size: 13))
                    .foregroundColor(Color(white: 0.9))
                    .fixedSize(horizontal: false, vertical: true)
            }
        }
        .padding(16)
        .background(Color(white: 0.12))
    }
}
```

> 💡 **Pro Tip & Arxitektura siri:**
> Agar cell balandligi hisoblanmay qolsa yoki xatolar paydo bo'lsa, tekshiring: 1) `commentLabel.numberOfLines = 0` qilinganmi? 2) Oxirgi element `contentView.snp.bottom` ga bog'langanmi? 3) `tableView.rowHeight = UITableView.automaticDimension` deb belgilanganmi?

</details>

---

## 🟠 Topshiriq 15: UIScrollView va ContentView Qoidalari

> **Daraja:** `Qiyin (Hard)` | **Maqsad:** Auto Layout bilan UIScrollView'ni to'g'ri sozlash va vertikal scroll'ni mukammal ishlashini ta'minlash.

UIScrollView'da ko'pchilik qiynaladigan 'Ambiguous scrollable content size' xatosini bartaraf etuvchi 3 ta majburiy qoida.

### Vizual Sxema (UI Mockup)

![Topshiriq 15: UIScrollView va ContentView Qoidalari](/lessons/images/snapkit/task_15.svg)

### 📋 Texnik Talablar va Cheklovlar

- scrollView ekranni to'liq qoplasin (`edges.equalToSuperview()`).
- Ichki `contentView` scrollView'ning barcha chetlariga qadalsin va uning kengligi `scrollView.snp.width` bilan tenglashtirilsin.
- Oxirgi elementning pastki qirrasi `contentView.snp.bottom` ga bog'lanishi shart.

<details>
<summary>💡 Kodni ko'rish (SnapKit, UIKit va SwiftUI yechimlari)</summary>

#### 1. SnapKit Yechimi (Asosiy)

```swift
import UIKit
import SnapKit

final class Task15ScrollViewVC: UIViewController {
    private let scrollView = UIScrollView()
    private let contentView = UIView()

    private let block1 = UIView()
    private let block2 = UIView()
    private let block3 = UIView()

    override func viewDidLoad() {
        super.viewDidLoad()
        setupUI()
    }

    private func setupUI() {
        view.backgroundColor = UIColor(white: 0.08, alpha: 1.0)
        view.addSubview(scrollView)
        scrollView.addSubview(contentView)

        // 1. ScrollView ekranga to'liq ulanadi:
        scrollView.snp.makeConstraints { make in
            make.edges.equalTo(view.safeAreaLayoutGuide)
        }

        // 2. ContentView: Qat'iy 2 qoida!
        contentView.snp.makeConstraints { make in
            make.edges.equalToSuperview() // ScrollView contentLayoutGuide ga ulanadi
            make.width.equalToSuperview() // Faqat vertikal scroll bo'lishi uchun eni tenglashtiriladi!
        }

        // 3. Kontent bloklari
        [block1, block2, block3].enumerated().forEach { index, b in
            b.backgroundColor = [UIColor.systemBlue, UIColor.systemIndigo, UIColor.systemTeal][index]
            b.layer.cornerRadius = 14
            contentView.addSubview(b)
        }

        block1.snp.makeConstraints { make in
            make.top.equalToSuperview().offset(20)
            make.leading.trailing.equalToSuperview().inset(16)
            make.height.equalTo(200)
        }

        block2.snp.makeConstraints { make in
            make.top.equalTo(block1.snp.bottom).offset(20)
            make.leading.trailing.equalToSuperview().inset(16)
            make.height.equalTo(300)
        }

        block3.snp.makeConstraints { make in
            make.top.equalTo(block2.snp.bottom).offset(20)
            make.leading.trailing.equalToSuperview().inset(16)
            make.height.equalTo(400)
            // 3-qoida: Eng oxirgi view contentView bottom'iga bog'lanishi SHART!
            make.bottom.equalToSuperview().offset(-20)
        }
    }
}
```

#### 2. Klassik UIKit (NSLayoutConstraint) Taqqoslash

```swift
import UIKit

final class Task15ScrollUIKitVC: UIViewController {
    private let scrollView = UIScrollView()
    private let contentView = UIView()

    override func viewDidLoad() {
        super.viewDidLoad()
        [scrollView, contentView].forEach { $0.translatesAutoresizingMaskIntoConstraints = false }
        view.addSubview(scrollView)
        scrollView.addSubview(contentView)

        let safe = view.safeAreaLayoutGuide
        NSLayoutConstraint.activate([
            scrollView.topAnchor.constraint(equalTo: safe.topAnchor),
            scrollView.bottomAnchor.constraint(equalTo: safe.bottomAnchor),
            scrollView.leadingAnchor.constraint(equalTo: safe.leadingAnchor),
            scrollView.trailingAnchor.constraint(equalTo: safe.trailingAnchor),

            // ContentView edges to ScrollView Content Layout Guide
            contentView.topAnchor.constraint(equalTo: scrollView.contentLayoutGuide.topAnchor),
            contentView.bottomAnchor.constraint(equalTo: scrollView.contentLayoutGuide.bottomAnchor),
            contentView.leadingAnchor.constraint(equalTo: scrollView.contentLayoutGuide.leadingAnchor),
            contentView.trailingAnchor.constraint(equalTo: scrollView.contentLayoutGuide.trailingAnchor),

            // Faqat vertikal scroll uchun kenglikni Frame Layout Guide ga tenglash:
            contentView.widthAnchor.constraint(equalTo: scrollView.frameLayoutGuide.widthAnchor)
        ])
    }
}
```

#### 3. SwiftUI Ekvivalenti

```swift
import SwiftUI

struct Task15SwiftUIView: View {
    var body: some View {
        ScrollView {
            VStack(spacing: 20) {
                RoundedRectangle(cornerRadius: 14)
                    .fill(Color.blue)
                    .frame(height: 200)

                RoundedRectangle(cornerRadius: 14)
                    .fill(Color.indigo)
                    .frame(height: 300)

                RoundedRectangle(cornerRadius: 14)
                    .fill(Color.teal)
                    .frame(height: 400)
            }
            .padding(16)
        }
        .background(Color(white: 0.08).ignoresSafeArea())
    }
}
```

> 💡 **Pro Tip & Arxitektura siri:**
> UIScrollView bilan ishlaganda eng katta sir: `contentView.width.equalToSuperview()`. Bu gorizontal silkinish (horizontal bouncing) xatosini butunlay yo'qotadi va `contentSize` ni avtomatik balandlikka moslaydi.

</details>

---

## 🟠 Topshiriq 16: Segmented Tab va Harakatlanuvchi Chiziq (Indicator)

> **Daraja:** `Qiyin (Hard)` | **Maqsad:** Yuqorida 3 ta tab (Asosiy, Vazifalar, Profil) va ularning ostida foydalanuvchi bosgan tabga qarab sirpanuvchi (animatsion) ingichka ko'k chiziq (indicator).

Constraint reference saqlash yoki `remakeConstraints` yordamida dinamik animatsiyalar yaratish.

### Vizual Sxema (UI Mockup)

![Topshiriq 16: Segmented Tab va Harakatlanuvchi Chiziq (Indicator)](/lessons/images/snapkit/task_16.svg)

### 📋 Texnik Talablar va Cheklovlar

- 3 ta teng kenglikdagi tab tugmalari.
- Indicator chizig'i: balandligi 3 pt, kengligi aynan bitta tab kengligiga teng.
- Chiziqning `leading` qirrasi tanlangan tab tugmasining `leading` qirrasiga bog'lansin.
- Tab bosilganda `layoutIfNeeded()` bilan 0.3 soniyali silliq animatsiya bo'lsin.

<details>
<summary>💡 Kodni ko'rish (SnapKit, UIKit va SwiftUI yechimlari)</summary>

#### 1. SnapKit Yechimi (Asosiy)

```swift
import UIKit
import SnapKit

final class Task16TabBarView: UIView {
    private let tab1 = UIButton(type: .system)
    private let tab2 = UIButton(type: .system)
    private let tab3 = UIButton(type: .system)
    private let indicatorLine = UIView()

    override init(frame: CGRect) {
        super.init(frame: frame)
        setupUI()
    }

    required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") }

    private func setupUI() {
        backgroundColor = UIColor(white: 0.12, alpha: 1.0)
        layer.cornerRadius = 10

        let tabs = [tab1, tab2, tab3]
        let titles = ["Asosiy", "Vazifalar", "Profil"]

        for (i, btn) in tabs.enumerated() {
            btn.setTitle(titles[i], for: .normal)
            btn.setTitleColor(i == 0 ? .systemSky : .gray, for: .normal)
            btn.titleLabel?.font = .systemFont(ofSize: 14, weight: .bold)
            addSubview(btn)
        }

        indicatorLine.backgroundColor = .systemSky
        addSubview(indicatorLine)

        tab1.snp.makeConstraints { make in
            make.top.bottom.leading.equalToSuperview()
        }

        tab2.snp.makeConstraints { make in
            make.top.bottom.equalToSuperview()
            make.leading.equalTo(tab1.snp.trailing)
            make.width.equalTo(tab1)
        }

        tab3.snp.makeConstraints { make in
            make.top.bottom.equalToSuperview()
            make.leading.equalTo(tab2.snp.trailing)
            make.trailing.equalToSuperview()
            make.width.equalTo(tab1)
        }

        // Boshlang'ich indicator pozitsiyasi:
        indicatorLine.snp.makeConstraints { make in
            make.bottom.equalToSuperview()
            make.height.equalTo(3)
            make.leading.equalTo(tab1.snp.leading)
            make.width.equalTo(tab1.snp.width)
        }
    }

    func selectTab(_ index: Int) {
        let targetTab = [tab1, tab2, tab3][index]

        // Harakatlantirish animatsiyasi:
        indicatorLine.snp.remakeConstraints { make in
            make.bottom.equalToSuperview()
            make.height.equalTo(3)
            make.leading.equalTo(targetTab.snp.leading)
            make.width.equalTo(targetTab.snp.width)
        }

        UIView.animate(withDuration: 0.3) {
            self.layoutIfNeeded()
        }
    }
}

private extension UIColor {
    static var systemSky: UIColor { UIColor(red: 0.22, green: 0.74, blue: 0.97, alpha: 1.0) }
}
```

#### 2. Klassik UIKit (NSLayoutConstraint) Taqqoslash

```swift
import UIKit

final class Task16UIKitTabBarView: UIView {
    private var indicatorLeadingConstraint: NSLayoutConstraint?
    private let indicatorLine = UIView()

    func moveIndicator(to targetView: UIView) {
        indicatorLeadingConstraint?.isActive = false
        indicatorLeadingConstraint = indicatorLine.leadingAnchor.constraint(equalTo: targetView.leadingAnchor)
        indicatorLeadingConstraint?.isActive = true

        UIView.animate(withDuration: 0.3) {
            self.layoutIfNeeded()
        }
    }
}
```

#### 3. SwiftUI Ekvivalenti

```swift
import SwiftUI

struct Task16SwiftUIView: View {
    @State private var selectedIndex = 0
    @Namespace private var animationNamespace

    let tabs = ["Asosiy", "Vazifalar", "Profil"]

    var body: some View {
        HStack(spacing: 0) {
            ForEach(0..<tabs.count, id: \.self) { index in
                Button(action: {
                    withAnimation(.spring(response: 0.3, dampingFraction: 0.7)) {
                        selectedIndex = index
                    }
                }) {
                    VStack(spacing: 8) {
                        Text(tabs[index])
                            .font(.system(size: 14, weight: .bold))
                            .foregroundColor(selectedIndex == index ? .blue : .gray)

                        if selectedIndex == index {
                            Rectangle()
                                .fill(Color.blue)
                                .frame(height: 3)
                                .matchedGeometryEffect(id: "indicator", in: animationNamespace)
                        } else {
                            Rectangle()
                                .fill(Color.clear)
                                .frame(height: 3)
                        }
                    }
                }
                .frame(maxWidth: .infinity)
            }
        }
        .padding(.top, 8)
        .background(Color(white: 0.12))
    }
}
```

> 💡 **Pro Tip & Arxitektura siri:**
> Animatsiya paytida `remakeConstraints` chaqirilgandan so'ng, `UIView.animate` bloki ichida aynan ota-ona view'ning `self.layoutIfNeeded()` metodini chaqirish shart. Busiz Auto Layout o'zgarishni darhol emas, keyingi render siklida sakrab (sakrash effekti bilan) o'tkazib yuboradi.

</details>

---

## 🔴 Topshiriq 17: Spotify / Apple Music Mini-Player Paneli

> **Daraja:** `Qahramon (Hero)` | **Maqsad:** Ekranning pastida suzuvchi (floating) ixcham mini-audio player: albom rasmi (48x48), trek nomi, ijrochi, play/pause va keyingi trek tugmalari hamda eng pastida 2 pt lik ingichka audio progress bar.

App Store'dagi eng mashhur ilovalarning murakkab va nafis pastki paneli arxitekturasi.

### Vizual Sxema (UI Mockup)

![Topshiriq 17: Spotify / Apple Music Mini-Player Paneli](/lessons/images/snapkit/task_17.svg)

### 📋 Texnik Talablar va Cheklovlar

- Mini-player: pastdan 8 pt, yonlardan 12 pt, balandligi 64 pt, burchak radiusi 16 pt.
- Cover rasmi: 48x48 pt, chapdan 8 pt masofa.
- Trek nomi va artist: cover rasmidan 12 pt o'ngda, boshqaruv tugmalariga yetmasdan qisqarishi kerak.
- Play tugmasi (32x32) va Next tugmasi (28x28) o'ng tomonda joylashsin.
- Playerning eng pastki qismida 2 pt balandlikdagi progress chizig'i (50% ijro qilingan).

<details>
<summary>💡 Kodni ko'rish (SnapKit, UIKit va SwiftUI yechimlari)</summary>

#### 1. SnapKit Yechimi (Asosiy)

```swift
import UIKit
import SnapKit

final class Task17MiniPlayerView: UIView {
    private let coverImageView: UIImageView = {
        let iv = UIImageView()
        iv.backgroundColor = .systemPurple
        iv.layer.cornerRadius = 8
        iv.clipsToBounds = true
        return iv
    }()

    private let titleLabel: UILabel = {
        let l = UILabel()
        l.text = "Starboy"
        l.textColor = .white
        l.font = .systemFont(ofSize: 13, weight: .bold)
        return l
    }()

    private let artistLabel: UILabel = {
        let l = UILabel()
        l.text = "The Weeknd, Daft Punk"
        l.textColor = .systemGray
        l.font = .systemFont(ofSize: 11)
        return l
    }()

    private let playButton: UIButton = {
        let btn = UIButton(type: .system)
        let config = UIImage.SymbolConfiguration(pointSize: 16, weight: .bold)
        btn.setImage(UIImage(systemName: "pause.fill", withConfiguration: config), for: .normal)
        btn.tintColor = .white
        return btn
    }()

    private let nextButton: UIButton = {
        let btn = UIButton(type: .system)
        let config = UIImage.SymbolConfiguration(pointSize: 14, weight: .bold)
        btn.setImage(UIImage(systemName: "forward.fill", withConfiguration: config), for: .normal)
        btn.tintColor = .systemGray
        return btn
    }()

    private let progressBarTrack = UIView()
    private let progressBarFill = UIView()

    override init(frame: CGRect) {
        super.init(frame: frame)
        setupUI()
    }

    required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") }

    private func setupUI() {
        backgroundColor = UIColor(white: 0.16, alpha: 1.0)
        layer.cornerRadius = 16
        clipsToBounds = true

        addSubview(coverImageView)
        addSubview(titleLabel)
        addSubview(artistLabel)
        addSubview(playButton)
        addSubview(nextButton)
        addSubview(progressBarTrack)
        progressBarTrack.addSubview(progressBarFill)

        progressBarTrack.backgroundColor = UIColor(white: 0.3, alpha: 1.0)
        progressBarFill.backgroundColor = .systemPink

        coverImageView.snp.makeConstraints { make in
            make.centerY.equalToSuperview()
            make.leading.equalToSuperview().offset(8)
            make.size.equalTo(48)
        }

        nextButton.snp.makeConstraints { make in
            make.centerY.equalToSuperview()
            make.trailing.equalToSuperview().offset(-12)
            make.size.equalTo(28)
        }

        playButton.snp.makeConstraints { make in
            make.centerY.equalToSuperview()
            make.trailing.equalTo(nextButton.snp.leading).offset(-8)
            make.size.equalTo(32)
        }

        titleLabel.snp.makeConstraints { make in
            make.top.equalTo(coverImageView).offset(6)
            make.leading.equalTo(coverImageView.snp.trailing).offset(10)
            make.trailing.lessThanOrEqualTo(playButton.snp.leading).offset(-8)
        }

        artistLabel.snp.makeConstraints { make in
            make.top.equalTo(titleLabel.snp.bottom).offset(2)
            make.leading.trailing.equalTo(titleLabel)
        }

        progressBarTrack.snp.makeConstraints { make in
            make.leading.trailing.bottom.equalToSuperview()
            make.height.equalTo(2)
        }

        progressBarFill.snp.makeConstraints { make in
            make.leading.top.bottom.equalToSuperview()
            make.width.equalToSuperview().multipliedBy(0.5) // 50% qo'shiq o'tdi
        }
    }
}
```

#### 2. Klassik UIKit (NSLayoutConstraint) Taqqoslash

```swift
import UIKit

final class Task17UIKitMiniPlayerView: UIView {
    // NSLayoutConstraint bilan MiniPlayer tuzilishi
    private let coverImageView = UIView()
    private let playButton = UIButton()
    private let progressBarFill = UIView()

    override init(frame: CGRect) {
        super.init(frame: frame)
        // ProgressBar multi-width UIKit misoli:
        progressBarFill.translatesAutoresizingMaskIntoConstraints = false
        addSubview(progressBarFill)

        NSLayoutConstraint.activate([
            progressBarFill.leadingAnchor.constraint(equalTo: leadingAnchor),
            progressBarFill.bottomAnchor.constraint(equalTo: bottomAnchor),
            progressBarFill.heightAnchor.constraint(equalToConstant: 2),
            progressBarFill.widthAnchor.constraint(equalTo: widthAnchor, multiplier: 0.5)
        ])
    }

    required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") }
}
```

#### 3. SwiftUI Ekvivalenti

```swift
import SwiftUI

struct Task17SwiftUIView: View {
    var body: some View {
        VStack(spacing: 0) {
            HStack(spacing: 10) {
                RoundedRectangle(cornerRadius: 8)
                    .fill(Color.purple)
                    .frame(width: 48, height: 48)

                VStack(alignment: .leading, spacing: 2) {
                    Text("Starboy")
                        .font(.system(size: 13, weight: .bold))
                        .foregroundColor(.white)
                    Text("The Weeknd, Daft Punk")
                        .font(.system(size: 11))
                        .foregroundColor(.gray)
                }

                Spacer()

                Button(action: {}) {
                    Image(systemName: "pause.fill")
                        .foregroundColor(.white)
                }

                Button(action: {}) {
                    Image(systemName: "forward.fill")
                        .foregroundColor(.gray)
                }
            }
            .padding(.horizontal, 10)
            .frame(height: 62)

            // Progress bar
            GeometryReader { proxy in
                ZStack(alignment: .leading) {
                    Rectangle().fill(Color(white: 0.3))
                    Rectangle().fill(Color.pink).frame(width: proxy.size.width * 0.5)
                }
            }
            .frame(height: 2)
        }
        .background(Color(white: 0.16))
        .clipShape(RoundedRectangle(cornerRadius: 16))
        .padding(.horizontal, 12)
    }
}
```

> 💡 **Pro Tip & Arxitektura siri:**
> Progress bar'ning `width` qiymatini `multipliedBy(currentProgress)` orqali bog'lash — pleer davomiyligini qat'iy piksellarsiz istalgan ekran hajmiga silliq moslashtirishning eng samarali yo'lidir.

</details>

---

## 🔴 Topshiriq 18: Instagram / Telegram Stories Elementi (Concentric Rings)

> **Daraja:** `Qahramon (Hero)` | **Maqsad:** Stories karuseli elementi: tashqi gradientli faol halqa (76x76), uning ichida 3 pt bo'shliq bilan joylashgan doiraviy avatar (64x64), avatar burchagida '+' qo'shish belgisi va pastda markazlashgan foydalanuvchi logini.

Bir markazda joylashgan konsentrik (concentric) aylanalarni o'zaro nisbatlar bilan bog'lash san'ati.

### Vizual Sxema (UI Mockup)

![Topshiriq 18: Instagram / Telegram Stories Elementi (Concentric Rings)](/lessons/images/snapkit/task_18.svg)

### 📋 Texnik Talablar va Cheklovlar

- Tashqi halqa (borderRing): 76x76 pt, to'liq doira, 2.5 pt rangli chegara.
- Avatar: 64x64 pt, aynan tashqi halqaning markazida (`center.equalTo(borderRing)`).
- Plus badge: 20x20 pt, avatarning pastki-o'ng chetiga qadaladi.
- Username label: halqadan 8 pt pastda, kengligi maksimal 75 pt, o'rtaga tekislangan.

<details>
<summary>💡 Kodni ko'rish (SnapKit, UIKit va SwiftUI yechimlari)</summary>

#### 1. SnapKit Yechimi (Asosiy)

```swift
import UIKit
import SnapKit

final class Task18StoryCellView: UIView {
    private let borderRingView: UIView = {
        let v = UIView()
        v.layer.cornerRadius = 38
        v.layer.borderWidth = 2.5
        v.layer.borderColor = UIColor.systemPink.cgColor
        return v
    }()

    private let avatarImageView: UIImageView = {
        let iv = UIImageView()
        iv.backgroundColor = .systemBlue
        iv.layer.cornerRadius = 32
        iv.clipsToBounds = true
        return iv
    }()

    private let addBadge: UIView = {
        let v = UIView()
        v.backgroundColor = .systemBlue
        v.layer.cornerRadius = 10
        v.layer.borderWidth = 2
        v.layer.borderColor = UIColor(white: 0.1, alpha: 1.0).cgColor

        let plusLabel = UILabel()
        plusLabel.text = "+"
        plusLabel.textColor = .white
        plusLabel.font = .systemFont(ofSize: 13, weight: .bold)
        plusLabel.textAlignment = .center
        v.addSubview(plusLabel)
        plusLabel.snp.makeConstraints { $0.center.equalToSuperview() }

        return v
    }()

    private let usernameLabel: UILabel = {
        let l = UILabel()
        l.text = "azimjon_dev"
        l.textColor = .white
        l.font = .systemFont(ofSize: 11, weight: .medium)
        l.textAlignment = .center
        return l
    }()

    override init(frame: CGRect) {
        super.init(frame: frame)
        setupUI()
    }

    required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") }

    private func setupUI() {
        addSubview(borderRingView)
        addSubview(avatarImageView)
        addSubview(addBadge)
        addSubview(usernameLabel)

        borderRingView.snp.makeConstraints { make in
            make.top.equalToSuperview().offset(6)
            make.centerX.equalToSuperview()
            make.size.equalTo(76)
        }

        // Konsentrik joylashuv — markazlar bir nuqtada:
        avatarImageView.snp.makeConstraints { make in
            make.center.equalTo(borderRingView)
            make.size.equalTo(64)
        }

        addBadge.snp.makeConstraints { make in
            make.size.equalTo(20)
            make.bottom.equalTo(avatarImageView.snp.bottom).offset(2)
            make.trailing.equalTo(avatarImageView.snp.trailing).offset(2)
        }

        usernameLabel.snp.makeConstraints { make in
            make.top.equalTo(borderRingView.snp.bottom).offset(6)
            make.centerX.equalToSuperview()
            make.leading.trailing.equalToSuperview().inset(4)
            make.bottom.lessThanOrEqualToSuperview().offset(-4)
        }
    }
}
```

#### 2. Klassik UIKit (NSLayoutConstraint) Taqqoslash

```swift
import UIKit

final class Task18UIKitStoryCellView: UIView {
    private let borderRingView = UIView()
    private let avatarImageView = UIView()

    override init(frame: CGRect) {
        super.init(frame: frame)
        [borderRingView, avatarImageView].forEach {
            $0.translatesAutoresizingMaskIntoConstraints = false
            addSubview($0)
        }

        NSLayoutConstraint.activate([
            borderRingView.centerXAnchor.constraint(equalTo: centerXAnchor),
            borderRingView.topAnchor.constraint(equalTo: topAnchor, constant: 6),
            borderRingView.widthAnchor.constraint(equalToConstant: 76),
            borderRingView.heightAnchor.constraint(equalToConstant: 76),

            // Markazlarni birlashtirish:
            avatarImageView.centerXAnchor.constraint(equalTo: borderRingView.centerXAnchor),
            avatarImageView.centerYAnchor.constraint(equalTo: borderRingView.centerYAnchor),
            avatarImageView.widthAnchor.constraint(equalToConstant: 64),
            avatarImageView.heightAnchor.constraint(equalToConstant: 64)
        ])
    }

    required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") }
}
```

#### 3. SwiftUI Ekvivalenti

```swift
import SwiftUI

struct Task18SwiftUIView: View {
    var body: some View {
        VStack(spacing: 6) {
            ZStack(alignment: .bottomTrailing) {
                // Outer ring
                Circle()
                    .stroke(Color.pink, lineWidth: 2.5)
                    .frame(width: 76, height: 76)

                // Avatar
                Circle()
                    .fill(Color.blue)
                    .frame(width: 64, height: 64)
                    .frame(width: 76, height: 76, alignment: .center)

                // Plus badge
                Circle()
                    .fill(Color.blue)
                    .frame(width: 20, height: 20)
                    .overlay(Text("+").font(.system(size: 13, weight: .bold)).foregroundColor(.white))
                    .overlay(Circle().stroke(Color(white: 0.1), lineWidth: 2))
                    .offset(x: 2, y: 2)
            }

            Text("azimjon_dev")
                .font(.system(size: 11, weight: .medium))
                .foregroundColor(.white)
                .lineLimit(1)
                .frame(maxWidth: 75)
        }
        .frame(width: 84)
    }
}
```

> 💡 **Pro Tip & Arxitektura siri:**
> Elementlarni ichma-ich joylashtirishda (`avatar.center.equalTo(borderRingView)`) orqali siz tashqi halqani animatsiya bilan kattalashtirganingizda yoki kichraytirganingizda ham avatar har doim geometrik markazda qolishini kafolatlaysiz.

</details>

---

## 🔴 Topshiriq 19: Bank Karta Layouti (Credit Card Ratio 1.586)

> **Daraja:** `Qiyin (Hard) / Qahramon (Hero)` | **Maqsad:** Haqiqiy xalqaro ISO/IEC 7810 standarti bo'yicha 1.586 tomonlar nisbatiga ega plastik bank kartasi maketini yaratish.

Yuqori chapda bank nomi, o'ngda kontaktsiz to'lov belgisi, markazda oltin rang EMV chip va 16 xonali karta raqami, pastda karta egasi va amal qilish muddati.

### Vizual Sxema (UI Mockup)

![Topshiriq 19: Bank Karta Layouti (Credit Card Ratio 1.586)](/lessons/images/snapkit/task_19.svg)

### 📋 Texnik Talablar va Cheklovlar

- Bank karta eni (width): yonlardan 20 pt masofada.
- Balandligi (height): eniga nisbatan bo'lingan `1.586` ko'paytuvchisi (`dividedBy(1.586)`).
- Burchaklar radiusi: 18 pt.
- EMV chip: 45x35 pt, burchaklari 6 pt.
- Karta raqami: harf oralig'i (kerning/letter spacing) kengaytirilgan 19 pt matn.

<details>
<summary>💡 Kodni ko'rish (SnapKit, UIKit va SwiftUI yechimlari)</summary>

#### 1. SnapKit Yechimi (Asosiy)

```swift
import UIKit
import SnapKit

final class Task19BankCardView: UIView {
    private let bankNameLabel: UILabel = {
        let l = UILabel()
        l.text = "APEX BANK"
        l.textColor = .white
        l.font = .systemFont(ofSize: 16, weight: .black)
        return l
    }()

    private let contactlessIcon: UILabel = {
        let l = UILabel()
        l.text = "📶"
        l.font = .systemFont(ofSize: 18)
        return l
    }()

    private let chipView: UIView = {
        let v = UIView()
        v.backgroundColor = UIColor(red: 0.95, green: 0.77, blue: 0.25, alpha: 1.0)
        v.layer.cornerRadius = 6
        v.layer.borderWidth = 1
        v.layer.borderColor = UIColor.brown.cgColor
        return v
    }()

    private let cardNumberLabel: UILabel = {
        let l = UILabel()
        l.text = "8600 •••• •••• 9012"
        l.textColor = .white
        l.font = .monospacedDigitSystemFont(ofSize: 20, weight: .bold)
        return l
    }()

    private let holderTitleLabel: UILabel = {
        let l = UILabel()
        l.text = "CARD HOLDER"
        l.textColor = UIColor(white: 0.75, alpha: 1.0)
        l.font = .systemFont(ofSize: 8, weight: .bold)
        return l
    }()

    private let holderNameLabel: UILabel = {
        let l = UILabel()
        l.text = "AZIMJON PULATOV"
        l.textColor = .white
        l.font = .systemFont(ofSize: 13, weight: .bold)
        return l
    }()

    private let expiryLabel: UILabel = {
        let l = UILabel()
        l.text = "12 / 29"
        l.textColor = .white
        l.font = .systemFont(ofSize: 13, weight: .bold)
        return l
    }()

    override init(frame: CGRect) {
        super.init(frame: frame)
        setupUI()
    }

    required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") }

    private func setupUI() {
        backgroundColor = UIColor(red: 0.1, green: 0.25, blue: 0.55, alpha: 1.0)
        layer.cornerRadius = 18
        layer.shadowColor = UIColor.black.cgColor
        layer.shadowOpacity = 0.4
        layer.shadowOffset = CGSize(width: 0, height: 8)
        layer.shadowRadius = 16

        addSubview(bankNameLabel)
        addSubview(contactlessIcon)
        addSubview(chipView)
        addSubview(cardNumberLabel)
        addSubview(holderTitleLabel)
        addSubview(holderNameLabel)
        addSubview(expiryLabel)

        // Dunyo bo'yicha bank kartalarining qat'iy 1.586 nisbati:
        snp.makeConstraints { make in
            make.height.equalTo(snp.width).dividedBy(1.586)
        }

        bankNameLabel.snp.makeConstraints { make in
            make.top.leading.equalToSuperview().offset(22)
        }

        contactlessIcon.snp.makeConstraints { make in
            make.top.equalToSuperview().offset(20)
            make.trailing.equalToSuperview().offset(-22)
        }

        chipView.snp.makeConstraints { make in
            make.top.equalTo(bankNameLabel.snp.bottom).offset(18)
            make.leading.equalToSuperview().offset(22)
            make.size.equalTo(CGSize(width: 45, height: 34))
        }

        cardNumberLabel.snp.makeConstraints { make in
            make.top.equalTo(chipView.snp.bottom).offset(18)
            make.leading.trailing.equalToSuperview().inset(22)
        }

        holderTitleLabel.snp.makeConstraints { make in
            make.leading.equalToSuperview().offset(22)
            make.bottom.equalTo(holderNameLabel.snp.top).offset(-2)
        }

        holderNameLabel.snp.makeConstraints { make in
            make.leading.equalToSuperview().offset(22)
            make.bottom.equalToSuperview().offset(-20)
        }

        expiryLabel.snp.makeConstraints { make in
            make.trailing.equalToSuperview().offset(-22)
            make.centerY.equalTo(holderNameLabel)
        }
    }
}
```

#### 2. Klassik UIKit (NSLayoutConstraint) Taqqoslash

```swift
import UIKit

final class Task19UIKitBankCardView: UIView {
    override init(frame: CGRect) {
        super.init(frame: frame)
        backgroundColor = .systemBlue
        layer.cornerRadius = 18

        // Aspect ratio constraint in UIKit:
        let ratioConstraint = heightAnchor.constraint(
            equalTo: widthAnchor,
            multiplier: 1.0 / 1.586
        )
        ratioConstraint.isActive = true
    }

    required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") }
}
```

#### 3. SwiftUI Ekvivalenti

```swift
import SwiftUI

struct Task19SwiftUIView: View {
    var body: some View {
        ZStack(alignment: .leading) {
            RoundedRectangle(cornerRadius: 18)
                .fill(LinearGradient(colors: [Color.blue, Color(red: 0.05, green: 0.15, blue: 0.4)], startPoint: .topLeading, endPoint: .bottomTrailing))
                .aspectRatio(1.586, contentMode: .fit)

            VStack(alignment: .leading, spacing: 0) {
                HStack {
                    Text("APEX BANK")
                        .font(.system(size: 16, weight: .black))
                        .foregroundColor(.white)
                    Spacer()
                    Text("📶")
                }

                Spacer()

                RoundedRectangle(cornerRadius: 6)
                    .fill(Color.yellow)
                    .frame(width: 45, height: 34)

                Spacer()

                Text("8600 •••• •••• 9012")
                    .font(.system(size: 20, weight: .bold, design: .monospaced))
                    .foregroundColor(.white)

                Spacer()

                HStack {
                    VStack(alignment: .leading, spacing: 2) {
                        Text("CARD HOLDER").font(.system(size: 8, weight: .bold)).foregroundColor(.gray)
                        Text("AZIMJON PULATOV").font(.system(size: 13, weight: .bold)).foregroundColor(.white)
                    }
                    Spacer()
                    Text("12 / 29").font(.system(size: 13, weight: .bold)).foregroundColor(.white)
                }
            }
            .padding(22)
        }
        .padding(.horizontal, 20)
    }
}
```

> 💡 **Pro Tip & Arxitektura siri:**
> SnapKit'da `dividedBy(1.586)` yozish `multipliedBy(1.0 / 1.586)` bilan teng kuchli. Bu esa kodni o'qiyotgan boshqa dasturchiga dizayndagi aspekt formulasi aynan nima ekanligini bir zumda tushunishga yordam beradi.

</details>

---

## 🔴 Topshiriq 20: Premium Paywall Obuna Kartasi (Most Popular Badge)

> **Daraja:** `Zero to Hero Master` | **Maqsad:** Real App Store ilovalaridagi premium obuna (Paywall) kartasi: yuqori o'ng burchakdan qisman tashqariga chiqib turgan 'ENG MASHHUR' nishoni, tanlanganlik indikatori (radio checkmark), oylik va yillik narxlar, tejash foizi (50% TEJANG) va bepul sinov muddati.

SnapKit imkoniyatlarini eng yuqori darajada qo'llash — ko'p qatlamli, nisbiy bog'langan va chegaradan chiquvchi nishonli murakkab komponent.

### Vizual Sxema (UI Mockup)

![Topshiriq 20: Premium Paywall Obuna Kartasi (Most Popular Badge)](/lessons/images/snapkit/task_20.svg)

### 📋 Texnik Talablar va Cheklovlar

- Asosiy karta: 18 pt burchaklar radiusi, 2.5 pt binafsha chegara (selected border).
- 'ENG MASHHUR' badge: kartaning tepa qirrasidan teng yarmi tepaga chiqib tursin (`centerY.equalTo(card.snp.top)`).
- Chap tomonda 32x32 doiraviy radio-checkmark belgisi.
- Tarif nomi, oylik va yillik narxlar bir-biriga mos keluvchi ierarxiyada bo'lsin.
- Pastki qismida ajratuvchi chiziq va '7 Kun Bepul Sinov' tugmasi joylashsin.

<details>
<summary>💡 Kodni ko'rish (SnapKit, UIKit va SwiftUI yechimlari)</summary>

#### 1. SnapKit Yechimi (Asosiy)

```swift
import UIKit
import SnapKit

final class Task20PaywallCardView: UIView {
    // 1. Asosiy karta
    private let cardContainer: UIView = {
        let v = UIView()
        v.backgroundColor = UIColor(white: 0.14, alpha: 1.0)
        v.layer.cornerRadius = 18
        v.layer.borderWidth = 2.5
        v.layer.borderColor = UIColor.systemPurple.cgColor
        return v
    }()

    // 2. Tepadagi suzuvchi "ENG MASHHUR" nishoni
    private let popularBadge: UIView = {
        let v = UIView()
        v.backgroundColor = .systemPurple
        v.layer.cornerRadius = 13
        v.layer.borderWidth = 1
        v.layer.borderColor = UIColor.white.withAlphaComponent(0.4).cgColor

        let l = UILabel()
        l.text = "🔥 ENG MASHHUR"
        l.textColor = .white
        l.font = .systemFont(ofSize: 10, weight: .black)
        v.addSubview(l)
        l.snp.makeConstraints { $0.center.equalToSuperview() }

        return v
    }()

    // 3. Radio checkmark
    private let checkmarkIcon: UIView = {
        let v = UIView()
        v.backgroundColor = .systemPurple
        v.layer.cornerRadius = 14

        let check = UILabel()
        check.text = "✓"
        check.textColor = .white
        check.font = .systemFont(ofSize: 14, weight: .bold)
        v.addSubview(check)
        check.snp.makeConstraints { $0.center.equalToSuperview() }

        return v
    }()

    private let planTitleLabel: UILabel = {
        let l = UILabel()
        l.text = "Yillik Obuna (Pro Max)"
        l.textColor = .white
        l.font = .systemFont(ofSize: 16, weight: .bold)
        return l
    }()

    private let planSubtitleLabel: UILabel = {
        let l = UILabel()
        l.text = "Barcha 100+ darslar va kodlar ochiq"
        l.textColor = .systemPurple.withAlphaComponent(0.8)
        l.font = .systemFont(ofSize: 11)
        return l
    }()

    private let savePillLabel: UILabel = {
        let l = UILabel()
        l.text = " 50% TEJANG "
        l.textColor = .systemGreen
        l.font = .systemFont(ofSize: 10, weight: .heavy)
        l.backgroundColor = UIColor.systemGreen.withAlphaComponent(0.2)
        l.layer.cornerRadius = 5
        l.clipsToBounds = true
        return l
    }()

    private let priceLabel: UILabel = {
        let l = UILabel()
        l.text = "$4.99"
        l.textColor = .white
        l.font = .systemFont(ofSize: 22, weight: .black)
        return l
    }()

    private let pricePeriodLabel: UILabel = {
        let l = UILabel()
        l.text = "oyiga ($59.99/yil)"
        l.textColor = .systemGray
        l.font = .systemFont(ofSize: 10)
        return l
    }()

    private let dividerLine: UIView = {
        let v = UIView()
        v.backgroundColor = UIColor(white: 0.25, alpha: 1.0)
        return v
    }()

    private let trialBadgeButton: UIButton = {
        let btn = UIButton(type: .system)
        btn.setTitle("7 Kun Bepul Sinov", for: .normal)
        btn.setTitleColor(.white, for: .normal)
        btn.titleLabel?.font = .systemFont(ofSize: 11, weight: .bold)
        btn.backgroundColor = UIColor.systemPurple.withAlphaComponent(0.25)
        btn.layer.cornerRadius = 8
        return btn
    }()

    override init(frame: CGRect) {
        super.init(frame: frame)
        setupUI()
    }

    required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") }

    private func setupUI() {
        // cardContainer va popularBadge ikkalasi ham ota-onaga qo'shiladi!
        addSubview(cardContainer)
        addSubview(popularBadge)

        cardContainer.addSubview(checkmarkIcon)
        cardContainer.addSubview(planTitleLabel)
        cardContainer.addSubview(planSubtitleLabel)
        cardContainer.addSubview(savePillLabel)
        cardContainer.addSubview(priceLabel)
        cardContainer.addSubview(pricePeriodLabel)
        cardContainer.addSubview(dividerLine)
        cardContainer.addSubview(trialBadgeButton)

        // Asosiy karta
        cardContainer.snp.makeConstraints { make in
            make.top.equalToSuperview().offset(13) // Badge chiqib turishi uchun joy
            make.leading.trailing.bottom.equalToSuperview()
        }

        // Tepadagi suzuvchi badge:
        popularBadge.snp.makeConstraints { make in
            make.centerY.equalTo(cardContainer.snp.top)
            make.trailing.equalTo(cardContainer).offset(-24)
            make.size.equalTo(CGSize(width: 125, height: 26))
        }

        checkmarkIcon.snp.makeConstraints { make in
            make.top.equalToSuperview().offset(20)
            make.leading.equalToSuperview().offset(16)
            make.size.equalTo(28)
        }

        priceLabel.snp.makeConstraints { make in
            make.top.equalToSuperview().offset(18)
            make.trailing.equalToSuperview().offset(-16)
        }

        pricePeriodLabel.snp.makeConstraints { make in
            make.top.equalTo(priceLabel.snp.bottom).offset(2)
            make.trailing.equalTo(priceLabel)
        }

        planTitleLabel.snp.makeConstraints { make in
            make.top.equalTo(checkmarkIcon)
            make.leading.equalTo(checkmarkIcon.snp.trailing).offset(12)
            make.trailing.lessThanOrEqualTo(priceLabel.snp.leading).offset(-8)
        }

        planSubtitleLabel.snp.makeConstraints { make in
            make.top.equalTo(planTitleLabel.snp.bottom).offset(3)
            make.leading.equalTo(planTitleLabel)
        }

        savePillLabel.snp.makeConstraints { make in
            make.top.equalTo(planSubtitleLabel.snp.bottom).offset(8)
            make.leading.equalTo(planTitleLabel)
            make.height.equalTo(20)
        }

        dividerLine.snp.makeConstraints { make in
            make.top.equalTo(savePillLabel.snp.bottom).offset(16)
            make.leading.trailing.equalToSuperview().inset(16)
            make.height.equalTo(1)
        }

        trialBadgeButton.snp.makeConstraints { make in
            make.top.equalTo(dividerLine.snp.bottom).offset(12)
            make.trailing.equalToSuperview().offset(-16)
            make.bottom.equalToSuperview().offset(-16) // Bottom pin!
            make.size.equalTo(CGSize(width: 140, height: 32))
        }
    }
}
```

#### 2. Klassik UIKit (NSLayoutConstraint) Taqqoslash

```swift
import UIKit

final class Task20UIKitPaywallCardView: UIView {
    private let cardContainer = UIView()
    private let popularBadge = UIView()

    override init(frame: CGRect) {
        super.init(frame: frame)
        [cardContainer, popularBadge].forEach {
            $0.translatesAutoresizingMaskIntoConstraints = false
            addSubview($0)
        }

        NSLayoutConstraint.activate([
            cardContainer.topAnchor.constraint(equalTo: topAnchor, constant: 13),
            cardContainer.leadingAnchor.constraint(equalTo: leadingAnchor),
            cardContainer.trailingAnchor.constraint(equalTo: trailingAnchor),
            cardContainer.bottomAnchor.constraint(equalTo: bottomAnchor),

            // Badge markazi cardContainer ustiga qadaladi:
            popularBadge.centerYAnchor.constraint(equalTo: cardContainer.topAnchor),
            popularBadge.trailingAnchor.constraint(equalTo: cardContainer.trailingAnchor, constant: -24),
            popularBadge.widthAnchor.constraint(equalToConstant: 125),
            popularBadge.heightAnchor.constraint(equalToConstant: 26)
        ])
    }

    required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") }
}
```

#### 3. SwiftUI Ekvivalenti

```swift
import SwiftUI

struct Task20SwiftUIView: View {
    var body: some View {
        ZStack(alignment: .topTrailing) {
            // Main Card
            VStack(alignment: .leading, spacing: 12) {
                HStack(alignment: .top) {
                    Circle()
                        .fill(Color.purple)
                        .frame(width: 28, height: 28)
                        .overlay(Text("✓").foregroundColor(.white).font(.headline))

                    VStack(alignment: .leading, spacing: 3) {
                        Text("Yillik Obuna (Pro Max)")
                            .font(.system(size: 16, weight: .bold))
                            .foregroundColor(.white)
                        Text("Barcha 100+ darslar va kodlar ochiq")
                            .font(.system(size: 11))
                            .foregroundColor(.purple)

                        Text(" 50% TEJANG ")
                            .font(.system(size: 10, weight: .heavy))
                            .foregroundColor(.green)
                            .padding(.vertical, 2)
                            .background(Color.green.opacity(0.2))
                            .clipShape(RoundedRectangle(cornerRadius: 4))
                            .padding(.top, 4)
                    }

                    Spacer()

                    VStack(alignment: .trailing, spacing: 2) {
                        Text("$4.99")
                            .font(.system(size: 22, weight: .black))
                            .foregroundColor(.white)
                        Text("oyiga ($59.99/yil)")
                            .font(.system(size: 10))
                            .foregroundColor(.gray)
                    }
                }

                Divider().background(Color(white: 0.3))

                HStack {
                    Spacer()
                    Text("7 Kun Bepul Sinov")
                        .font(.system(size: 11, weight: .bold))
                        .foregroundColor(.white)
                        .padding(.horizontal, 14)
                        .padding(.vertical, 8)
                        .background(Color.purple.opacity(0.3))
                        .clipShape(RoundedRectangle(cornerRadius: 8))
                }
            }
            .padding(16)
            .background(Color(white: 0.14))
            .clipShape(RoundedRectangle(cornerRadius: 18))
            .overlay(
                RoundedRectangle(cornerRadius: 18)
                    .stroke(Color.purple, lineWidth: 2.5)
            )
            .padding(.top, 13) // Badge uchun yuqoridan bo'shliq

            // Floating Most Popular Badge
            Text("🔥 ENG MASHHUR")
                .font(.system(size: 10, weight: .black))
                .foregroundColor(.white)
                .padding(.horizontal, 12)
                .padding(.vertical, 6)
                .background(Color.purple)
                .clipShape(Capsule())
                .overlay(Capsule().stroke(Color.white.opacity(0.4), lineWidth: 1))
                .padding(.trailing, 24)
        }
    }
}
```

> 💡 **Pro Tip & Arxitektura siri:**
> Tabriklaymiz! Siz SnapKit'dagi eng qiyin arxitekturaviy vazifani — chegaradan tashqariga chiqib turuvchi (floating overlay badge) va dinamik ichki tarmoqqa ega bo'lgan haqiqiy production darajasidagi komponentni muvaffaqiyatli yakunladingiz! Ushbu 20 ta topshiriqni o'zlashtirgan dasturchi har qanday App Store ilovasining UI talablarini 100% yengillik bilan amalga oshira oladi.

</details>

---

## 🔴 Topshiriq 21: Instagram / Twitter Profile Ekrani (Stretchy Header & Sticky Tabs)

> **Daraja:** `Titan / Real-World Project` | **Maqsad:** Real-world profil ekrani: Banner rasmi, banner pastki qirrasidan yarmi chiqib turuvchi 72x72 avatar, 3 ta statistik raqamlar (Posts, Followers, Following), bio matni, 'Profilni tahrirlash' tugmasi va 3 ustunli fotosuratlar to'ri (UICollectionView).

Katta ijtimoiy tarmoqlar (Instagram, X/Twitter) profilidagi murakkab elementlar ierarxiyasi va vertikal oqimni boshqarish.

### Vizual Sxema (UI Mockup)

![Topshiriq 21: Instagram / Twitter Profile Ekrani (Stretchy Header & Sticky Tabs)](/lessons/images/snapkit/task_21.svg)

### 📋 Texnik Talablar va Cheklovlar

- Header cover banner: balandligi 100 pt, ekranning yuqori chetiga to'liq yopishgan.
- Avatar: 72x72 pt, to'liq doira (radius 36), uning vertikal markazi bannerning pastki chizig'iga bog'lansin: `make.centerY.equalTo(banner.snp.bottom)`.
- Statistika bloki: Postlar, Obunachilar va Obunalar - avatardan o'ng tomonda 3 ta teng ustunli qilib joylashtirilsin.
- Bio matni va tahrirlash tugmasi to'liq kenglikda (yonlardan 16 pt).
- Pastki qismida 3 ustunli fotosuratlar to'ri (UICollectionView grid).

<details>
<summary>💡 Kodni ko'rish (SnapKit, UIKit va SwiftUI yechimlari)</summary>

#### 1. SnapKit Yechimi (Asosiy)

```swift
import UIKit
import SnapKit

final class ProfileViewController: UIViewController {
    private let scrollView = UIScrollView()
    private let contentView = UIView()

    private let bannerImageView: UIImageView = {
        let iv = UIImageView()
        iv.backgroundColor = .systemIndigo
        iv.contentMode = .scaleAspectFill
        iv.clipsToBounds = true
        return iv
    }()

    private let avatarImageView: UIImageView = {
        let iv = UIImageView()
        iv.backgroundColor = .systemBlue
        iv.layer.cornerRadius = 36
        iv.layer.borderWidth = 3
        iv.layer.borderColor = UIColor(white: 0.1, alpha: 1.0).cgColor
        iv.clipsToBounds = true
        return iv
    }()

    private let statsStackView: UIStackView = {
        let stack = UIStackView()
        stack.axis = .horizontal
        stack.distribution = .fillEqually
        stack.alignment = .center
        return stack
    }()

    private let nameLabel: UILabel = {
        let l = UILabel()
        l.text = "Azimjon Pulatov"
        l.textColor = .white
        l.font = .systemFont(ofSize: 16, weight: .bold)
        return l
    }()

    private let bioLabel: UILabel = {
        let l = UILabel()
        l.text = "iOS Staff Engineer @ Tech • Swift 6 & SnapKit Master. Zamonaviy arxitektura va toza kod tarafdori."
        l.textColor = .systemGray
        l.font = .systemFont(ofSize: 12)
        l.numberOfLines = 0
        return l
    }()

    private let editProfileButton: UIButton = {
        let btn = UIButton(type: .system)
        btn.setTitle("Profilni tahrirlash", for: .normal)
        btn.setTitleColor(.white, for: .normal)
        btn.titleLabel?.font = .systemFont(ofSize: 13, weight: .semibold)
        btn.backgroundColor = UIColor(white: 0.2, alpha: 1.0)
        btn.layer.cornerRadius = 8
        return btn
    }()

    private let photosCollectionView: UICollectionView = {
        let layout = UICollectionViewFlowLayout()
        layout.minimumLineSpacing = 2
        layout.minimumInteritemSpacing = 2
        let cv = UICollectionView(frame: .zero, collectionViewLayout: layout)
        cv.backgroundColor = .clear
        cv.isScrollEnabled = false // ScrollView ichida bo'lgani uchun balandlik bilan o'lchanadi
        return cv
    }()

    override func viewDidLoad() {
        super.viewDidLoad()
        setupUI()
    }

    private func setupUI() {
        view.backgroundColor = UIColor(white: 0.1, alpha: 1.0)
        view.addSubview(scrollView)
        scrollView.addSubview(contentView)

        scrollView.snp.makeConstraints { make in
            make.edges.equalTo(view.safeAreaLayoutGuide)
        }

        contentView.snp.makeConstraints { make in
            make.edges.equalToSuperview()
            make.width.equalToSuperview()
        }

        [bannerImageView, avatarImageView, statsStackView, nameLabel, bioLabel, editProfileButton, photosCollectionView].forEach {
            contentView.addSubview($0)
        }

        // 1. Banner
        bannerImageView.snp.makeConstraints { make in
            make.top.leading.trailing.equalToSuperview()
            make.height.equalTo(100)
        }

        // 2. Avatar - sir: centerY banner.bottom ga qadaladi!
        avatarImageView.snp.makeConstraints { make in
            make.leading.equalToSuperview().offset(16)
            make.centerY.equalTo(bannerImageView.snp.bottom)
            make.size.equalTo(72)
        }

        // 3. Stats stack - avatardan o'ng tomonda
        statsStackView.snp.makeConstraints { make in
            make.leading.equalTo(avatarImageView.snp.trailing).offset(24)
            make.trailing.equalToSuperview().offset(-16)
            make.top.equalTo(bannerImageView.snp.bottom).offset(12)
            make.height.equalTo(44)
        }

        // 4. Ism va Bio
        nameLabel.snp.makeConstraints { make in
            make.top.equalTo(avatarImageView.snp.bottom).offset(12)
            make.leading.trailing.equalToSuperview().inset(16)
        }

        bioLabel.snp.makeConstraints { make in
            make.top.equalTo(nameLabel.snp.bottom).offset(4)
            make.leading.trailing.equalToSuperview().inset(16)
        }

        // 5. Tahrirlash tugmasi
        editProfileButton.snp.makeConstraints { make in
            make.top.equalTo(bioLabel.snp.bottom).offset(12)
            make.leading.trailing.equalToSuperview().inset(16)
            make.height.equalTo(34)
        }

        // 6. Rasmlar to'ri (UICollectionView) - balandligi kontentga qarab
        photosCollectionView.snp.makeConstraints { make in
            make.top.equalTo(editProfileButton.snp.bottom).offset(16)
            make.leading.trailing.equalToSuperview()
            make.height.equalTo(400) // Dinamik yoki hisoblangan balandlik
            make.bottom.equalToSuperview().offset(-16) // Bottom pin!
        }
    }
}
```

#### 2. Klassik UIKit (NSLayoutConstraint) Taqqoslash

```swift
import UIKit

final class ProfileUIKitViewController: UIViewController {
    private let bannerImageView = UIImageView()
    private let avatarImageView = UIImageView()

    override func viewDidLoad() {
        super.viewDidLoad()
        [bannerImageView, avatarImageView].forEach {
            $0.translatesAutoresizingMaskIntoConstraints = false
            view.addSubview($0)
        }

        NSLayoutConstraint.activate([
            bannerImageView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
            bannerImageView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
            bannerImageView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
            bannerImageView.heightAnchor.constraint(equalToConstant: 100),

            avatarImageView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 16),
            avatarImageView.centerYAnchor.constraint(equalTo: bannerImageView.bottomAnchor),
            avatarImageView.widthAnchor.constraint(equalToConstant: 72),
            avatarImageView.heightAnchor.constraint(equalToConstant: 72)
        ])
    }
}
```

#### 3. SwiftUI Ekvivalenti

```swift
import SwiftUI

struct ProfileSwiftUIView: View {
    var body: some View {
        ScrollView {
            VStack(alignment: .leading, spacing: 12) {
                ZStack(alignment: .bottomLeading) {
                    Rectangle()
                        .fill(Color.indigo)
                        .frame(height: 100)

                    Circle()
                        .fill(Color.blue)
                        .frame(width: 72, height: 72)
                        .overlay(Circle().stroke(Color(white: 0.1), lineWidth: 3))
                        .offset(x: 16, y: 36)
                }
                .padding(.bottom, 36)

                Text("Azimjon Pulatov")
                    .font(.headline).bold()
                    .foregroundColor(.white)
                    .padding(.horizontal, 16)

                Text("iOS Staff Engineer @ Tech • Swift 6 & SnapKit Master.")
                    .font(.caption)
                    .foregroundColor(.gray)
                    .padding(.horizontal, 16)
            }
        }
        .background(Color(white: 0.1).ignoresSafeArea())
    }
}
```

> 💡 **Pro Tip & Arxitektura siri:**
> ScrollView ichida UICollectionView joylashtirilganda, ikkalasi ham scroll bo'lib chalkashmasligi uchun `photosCollectionView.isScrollEnabled = false` qilinadi va uning balandligi `photosCollectionView.snp.makeConstraints { make.height.equalTo(...) }` orqali to'liq qamrab olinadi.

</details>

---

## 🔴 Topshiriq 22: E-Commerce / Delivery Asosiy Ekrani (HomeView Nested Carousels)

> **Daraja:** `Titan / Real-World Project` | **Maqsad:** Uzum Market, Amazon yoki Yandex Go uslubidagi ko'p tarmoqli asosiy ekran: tepada qidiruv paneli, hikoyalar karuseli (Stories), reklama banneri (Hero Slider), 4 ta teng ustunli toifalar (Categories Grid) va gorizontal mahsulotlar karuseli.

Katta e-commerce ilovalarda UIScrollView ichida bir nechta UICollectionView karusellarini to'g'ri joylashtirish.

### Vizual Sxema (UI Mockup)

![Topshiriq 22: E-Commerce / Delivery Asosiy Ekrani (HomeView Nested Carousels)](/lessons/images/snapkit/task_22.svg)

### 📋 Texnik Talablar va Cheklovlar

- Qidiruv paneli (SearchBar): ekranning eng yuqorisida, balandligi 40 pt.
- Stories karuseli: gorizontal scroll, balandligi 75 pt.
- Reklama banneri: kengligi to'liq (yonlardan 16 pt), balandligi 90 pt.
- Toifalar bloki: 4 ta teng ustunli (HStack yoki CollectionView), balandligi 44 pt.
- Tavsiya etilgan mahsulotlar karuseli: gorizontal scroll, balandligi 140 pt.

<details>
<summary>💡 Kodni ko'rish (SnapKit, UIKit va SwiftUI yechimlari)</summary>

#### 1. SnapKit Yechimi (Asosiy)

```swift
import UIKit
import SnapKit

final class HomeFeedViewController: UIViewController {
    private let searchBarView: UIView = {
        let v = UIView()
        v.backgroundColor = UIColor(white: 0.18, alpha: 1.0)
        v.layer.cornerRadius = 10
        return v
    }()

    private let mainScrollView = UIScrollView()
    private let scrollContentView = UIView()

    private let storiesCollectionView: UICollectionView = {
        let layout = UICollectionViewFlowLayout()
        layout.scrollDirection = .horizontal
        layout.itemSize = CGSize(width: 60, height: 75)
        let cv = UICollectionView(frame: .zero, collectionViewLayout: layout)
        cv.backgroundColor = .clear
        cv.showsHorizontalScrollIndicator = false
        return cv
    }()

    private let heroBannerView: UIView = {
        let v = UIView()
        v.backgroundColor = .systemBlue
        v.layer.cornerRadius = 12
        return v
    }()

    private let categoriesStackView: UIStackView = {
        let stack = UIStackView()
        stack.axis = .horizontal
        stack.distribution = .fillEqually
        stack.spacing = 8
        return stack
    }()

    private let productsCarouselView: UICollectionView = {
        let layout = UICollectionViewFlowLayout()
        layout.scrollDirection = .horizontal
        layout.itemSize = CGSize(width: 130, height: 140)
        let cv = UICollectionView(frame: .zero, collectionViewLayout: layout)
        cv.backgroundColor = .clear
        cv.showsHorizontalScrollIndicator = false
        return cv
    }()

    override func viewDidLoad() {
        super.viewDidLoad()
        setupLayout()
    }

    private func setupLayout() {
        view.backgroundColor = UIColor(white: 0.08, alpha: 1.0)
        view.addSubview(searchBarView)
        view.addSubview(mainScrollView)
        mainScrollView.addSubview(scrollContentView)

        // 1. Qidiruv paneli ekranning yuqori Safe Area qismida
        searchBarView.snp.makeConstraints { make in
            make.top.equalTo(view.safeAreaLayoutGuide.snp.top).offset(8)
            make.leading.trailing.equalToSuperview().inset(16)
            make.height.equalTo(40)
        }

        // 2. Asosiy ScrollView qidiruv panelidan pastda
        mainScrollView.snp.makeConstraints { make in
            make.top.equalTo(searchBarView.snp.bottom).offset(8)
            make.leading.trailing.bottom.equalToSuperview()
        }

        scrollContentView.snp.makeConstraints { make in
            make.edges.equalToSuperview()
            make.width.equalToSuperview()
        }

        [storiesCollectionView, heroBannerView, categoriesStackView, productsCarouselView].forEach {
            scrollContentView.addSubview($0)
        }

        // 3. Stories Carousel
        storiesCollectionView.snp.makeConstraints { make in
            make.top.equalToSuperview().offset(8)
            make.leading.trailing.equalToSuperview()
            make.height.equalTo(75)
        }

        // 4. Hero Banner
        heroBannerView.snp.makeConstraints { make in
            make.top.equalTo(storiesCollectionView.snp.bottom).offset(12)
            make.leading.trailing.equalToSuperview().inset(16)
            make.height.equalTo(90)
        }

        // 5. 4 ta Toifalar bloki
        categoriesStackView.snp.makeConstraints { make in
            make.top.equalTo(heroBannerView.snp.bottom).offset(16)
            make.leading.trailing.equalToSuperview().inset(16)
            make.height.equalTo(44)
        }

        // 6. Gorizontal Mahsulotlar Karuseli
        productsCarouselView.snp.makeConstraints { make in
            make.top.equalTo(categoriesStackView.snp.bottom).offset(16)
            make.leading.trailing.equalToSuperview()
            make.height.equalTo(140)
            make.bottom.equalToSuperview().offset(-20) // ScrollView tugashi!
        }
    }
}
```

#### 2. Klassik UIKit (NSLayoutConstraint) Taqqoslash

```swift
import UIKit

final class HomeFeedUIKitVC: UIViewController {
    private let searchBar = UIView()
    private let scrollView = UIScrollView()

    override func viewDidLoad() {
        super.viewDidLoad()
        [searchBar, scrollView].forEach {
            $0.translatesAutoresizingMaskIntoConstraints = false
            view.addSubview($0)
        }

        NSLayoutConstraint.activate([
            searchBar.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 8),
            searchBar.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 16),
            searchBar.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -16),
            searchBar.heightAnchor.constraint(equalToConstant: 40),

            scrollView.topAnchor.constraint(equalTo: searchBar.bottomAnchor, constant: 8),
            scrollView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
            scrollView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
            scrollView.bottomAnchor.constraint(equalTo: view.bottomAnchor)
        ])
    }
}
```

#### 3. SwiftUI Ekvivalenti

```swift
import SwiftUI

struct HomeFeedSwiftUIView: View {
    var body: some View {
        VStack(spacing: 8) {
            RoundedRectangle(cornerRadius: 10)
                .fill(Color(white: 0.18))
                .frame(height: 40)
                .padding(.horizontal, 16)

            ScrollView {
                VStack(spacing: 16) {
                    ScrollView(.horizontal, showsIndicators: false) {
                        HStack(spacing: 12) {
                            ForEach(0..<6) { _ in Circle().fill(Color.purple).frame(width: 50, height: 50) }
                        }
                        .padding(.horizontal, 16)
                    }

                    RoundedRectangle(cornerRadius: 12)
                        .fill(Color.blue)
                        .frame(height: 90)
                        .padding(.horizontal, 16)
                }
            }
        }
        .background(Color(white: 0.08).ignoresSafeArea())
    }
}
```

> 💡 **Pro Tip & Arxitektura siri:**
> Vertikal `UIScrollView` ichida gorizontal `UICollectionView` ishlatganda, iOS imo-ishoralar (gestures) to'qnashuvini avtomatik hal qiladi. Asosiy shart — gorizontal karuselga aniq `height` berish, vertikal kenglikni esa `equalToSuperview()` qilishdir.

</details>

---

## 🔴 Topshiriq 23: Telegram / WhatsApp Chat Xonasi (Keyboard-Docked Input Bar)

> **Daraja:** `Titan / Real-World Project` | **Maqsad:** Telegram yoki WhatsApp darajasidagi chat ekrani: xabarlar UITableView'i, kelgan va ketgan xabar pufakchalari, pastdagi klaviatura balandligiga qarab sakrab ko'tariluvchi matn yozish paneli (Input Accessory Bar) va pastga tushiruvchi suzuvchi tugma (FAB).

iOS 15+ da joriy qilingan `keyboardLayoutGuide` bilan SnapKit'da klaviatura animatsiyasini avtomatlashtirish.

### Vizual Sxema (UI Mockup)

![Topshiriq 23: Telegram / WhatsApp Chat Xonasi (Keyboard-Docked Input Bar)](/lessons/images/snapkit/task_23.svg)

### 📋 Texnik Talablar va Cheklovlar

- Top bar: Chat nomi, a'zolar soni, avatar.
- Xabarlar ro'yxati (UITableView): ekranning butun maydonini egallaydi.
- Input Bar: chapda qo'shish tugmasi (+), o'rtada moslashuvchan UITextField, o'ngda mikrofon (ovoz yozish).
- Eng muhim talab: Input Bar ning pastki qismi `view.keyboardLayoutGuide.snp.top` ga bog'lanishi shart (klaviatura chiqqanda avtomatik ko'tariladi).
- Xabarlar ro'yxati pastki qismi esa aynan Input Bar'ning ustiga bog'lansin.

<details>
<summary>💡 Kodni ko'rish (SnapKit, UIKit va SwiftUI yechimlari)</summary>

#### 1. SnapKit Yechimi (Asosiy)

```swift
import UIKit
import SnapKit

final class ChatRoomViewController: UIViewController {
    private let chatTableView: UITableView = {
        let tv = UITableView()
        tv.backgroundColor = .clear
        tv.separatorStyle = .none
        return tv
    }()

    private let inputContainerView: UIView = {
        let v = UIView()
        v.backgroundColor = UIColor(white: 0.15, alpha: 1.0)
        return v
    }()

    private let attachButton: UIButton = {
        let btn = UIButton(type: .system)
        btn.setTitle("+", for: .normal)
        btn.setTitleColor(.white, for: .normal)
        btn.titleLabel?.font = .systemFont(ofSize: 22, weight: .light)
        return btn
    }()

    private let messageTextField: UITextField = {
        let tf = UITextField()
        tf.placeholder = "Xabar yozing..."
        tf.backgroundColor = UIColor(white: 0.1, alpha: 1.0)
        tf.textColor = .white
        tf.layer.cornerRadius = 16
        tf.leftView = UIView(frame: CGRect(x: 0, y: 0, width: 12, height: 1))
        tf.leftViewMode = .always
        return tf
    }()

    private let micButton: UIButton = {
        let btn = UIButton(type: .system)
        btn.setTitle("🎙", for: .normal)
        btn.backgroundColor = .systemBlue
        btn.layer.cornerRadius = 16
        return btn
    }()

    private let scrollToBottomButton: UIButton = {
        let btn = UIButton(type: .system)
        btn.setTitle("↓", for: .normal)
        btn.setTitleColor(.white, for: .normal)
        btn.backgroundColor = UIColor(white: 0.2, alpha: 0.9)
        btn.layer.cornerRadius = 16
        return btn
    }()

    override func viewDidLoad() {
        super.viewDidLoad()
        setupUI()
    }

    private func setupUI() {
        view.backgroundColor = UIColor(white: 0.08, alpha: 1.0)

        view.addSubview(chatTableView)
        view.addSubview(inputContainerView)
        view.addSubview(scrollToBottomButton)

        inputContainerView.addSubview(attachButton)
        inputContainerView.addSubview(messageTextField)
        inputContainerView.addSubview(micButton)

        // 1. Input Container - iOS 15+ keyboardLayoutGuide ga ulanadi!
        inputContainerView.snp.makeConstraints { make in
            make.leading.trailing.equalToSuperview()
            make.bottom.equalTo(view.keyboardLayoutGuide.snp.top) // Klaviaturaga qadaladi!
            make.height.equalTo(54)
        }

        attachButton.snp.makeConstraints { make in
            make.leading.equalToSuperview().offset(8)
            make.centerY.equalToSuperview()
            make.size.equalTo(36)
        }

        micButton.snp.makeConstraints { make in
            make.trailing.equalToSuperview().offset(-12)
            make.centerY.equalToSuperview()
            make.size.equalTo(32)
        }

        messageTextField.snp.makeConstraints { make in
            make.leading.equalTo(attachButton.snp.trailing).offset(6)
            make.trailing.equalTo(micButton.snp.leading).offset(-8)
            make.centerY.equalToSuperview()
            make.height.equalTo(34)
        }

        // 2. Chat ro'yxati input container tepasiga qadaladi
        chatTableView.snp.makeConstraints { make in
            make.top.equalTo(view.safeAreaLayoutGuide)
            make.leading.trailing.equalToSuperview()
            make.bottom.equalTo(inputContainerView.snp.top)
        }

        // 3. Scroll to bottom suzuvchi FAB
        scrollToBottomButton.snp.makeConstraints { make in
            make.trailing.equalToSuperview().offset(-16)
            make.bottom.equalTo(inputContainerView.snp.top).offset(-12)
            make.size.equalTo(32)
        }
    }
}
```

#### 2. Klassik UIKit (NSLayoutConstraint) Taqqoslash

```swift
import UIKit

final class ChatRoomUIKitVC: UIViewController {
    private let inputContainer = UIView()

    override func viewDidLoad() {
        super.viewDidLoad()
        inputContainer.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(inputContainer)

        // iOS 15+ UIKit keyboardLayoutGuide
        NSLayoutConstraint.activate([
            inputContainer.leadingAnchor.constraint(equalTo: view.leadingAnchor),
            inputContainer.trailingAnchor.constraint(equalTo: view.trailingAnchor),
            inputContainer.bottomAnchor.constraint(equalTo: view.keyboardLayoutGuide.topAnchor),
            inputContainer.heightAnchor.constraint(equalToConstant: 54)
        ])
    }
}
```

#### 3. SwiftUI Ekvivalenti

```swift
import SwiftUI

struct ChatRoomSwiftUIView: View {
    @State private var text = ""

    var body: some View {
        VStack(spacing: 0) {
            ScrollView {
                Text("Xabarlar ro'yxati...")
            }

            HStack {
                Button("+") {}
                TextField("Xabar yozing...", text: $text)
                    .textFieldStyle(.roundedBorder)
                Button("🎙") {}
            }
            .padding(8)
            .background(Color(white: 0.15))
        }
        .background(Color(white: 0.08).ignoresSafeArea())
    }
}
```

> 💡 **Pro Tip & Arxitektura siri:**
> Eski iOS versiyalarida klaviatura balandligini NotificationCenter orqali qo'lda ushlab animatsiya yozilar edi. SnapKit + `view.keyboardLayoutGuide.snp.top` kombinatsiyasi esa 1 qator kod bilan klaviaturaning ochilish va yopilish animatsiyasiga 100% silliq ergashadi!

</details>

---

## 🔴 Topshiriq 24: Fintech / Bank Asosiy Boshqaruv Paneli (Banking Dashboard)

> **Daraja:** `Titan / Real-World Project` | **Maqsad:** Revolut, Click yoki Payme uslubidagi bank boshqaruv ekrani: balans ko'rsatkichi, kredit kartalarning gorizontal varoqlanuvchi karuseli (UICollectionView Paging), 4 ta tezkor amallar tugmalari va operatsiyalar tarixi (UITableView).

Fintech ilovalaridagi ko'p qatlamli ma'lumotlar oqimi va TableView bilan CollectionView birgalikda ishlashi.

### Vizual Sxema (UI Mockup)

![Topshiriq 24: Fintech / Bank Asosiy Boshqaruv Paneli (Banking Dashboard)](/lessons/images/snapkit/task_24.svg)

### 📋 Texnik Talablar va Cheklovlar

- Balans sarlavhasi va yashirish/ko'rsatish ko'z tugmasi (Eye icon).
- Karta karuseli (Paging UICollectionView): balandligi 90 pt.
- 4 ta tezkor amallar (O'tkazma, To'lov, QR skaner, Tahlil): gorizontal teng 4 ustun.
- Amaliyotlar tarixi (UITableView): qolgan butun ekranni egallashi shart.

<details>
<summary>💡 Kodni ko'rish (SnapKit, UIKit va SwiftUI yechimlari)</summary>

#### 1. SnapKit Yechimi (Asosiy)

```swift
import UIKit
import SnapKit

final class BankingDashboardViewController: UIViewController {
    private let balanceLabel: UILabel = {
        let l = UILabel()
        l.text = "$12,450.80"
        l.textColor = .white
        l.font = .systemFont(ofSize: 24, weight: .black)
        return l
    }()

    private let cardsCollectionView: UICollectionView = {
        let layout = UICollectionViewFlowLayout()
        layout.scrollDirection = .horizontal
        layout.itemSize = CGSize(width: 280, height: 85)
        let cv = UICollectionView(frame: .zero, collectionViewLayout: layout)
        cv.backgroundColor = .clear
        cv.isPagingEnabled = true
        return cv
    }()

    private let quickActionsStackView: UIStackView = {
        let stack = UIStackView()
        stack.axis = .horizontal
        stack.distribution = .fillEqually
        stack.spacing = 12
        return stack
    }()

    private let transactionsTableView: UITableView = {
        let tv = UITableView()
        tv.backgroundColor = .clear
        return tv
    }()

    override func viewDidLoad() {
        super.viewDidLoad()
        setupUI()
    }

    private func setupUI() {
        view.backgroundColor = UIColor(white: 0.08, alpha: 1.0)

        [balanceLabel, cardsCollectionView, quickActionsStackView, transactionsTableView].forEach {
            view.addSubview($0)
        }

        balanceLabel.snp.makeConstraints { make in
            make.top.equalTo(view.safeAreaLayoutGuide).offset(12)
            make.leading.equalToSuperview().offset(20)
        }

        cardsCollectionView.snp.makeConstraints { make in
            make.top.equalTo(balanceLabel.snp.bottom).offset(16)
            make.leading.trailing.equalToSuperview()
            make.height.equalTo(85)
        }

        quickActionsStackView.snp.makeConstraints { make in
            make.top.equalTo(cardsCollectionView.snp.bottom).offset(20)
            make.leading.trailing.equalToSuperview().inset(20)
            make.height.equalTo(54)
        }

        // Qolgan butun pastki qism TableView ga beriladi:
        transactionsTableView.snp.makeConstraints { make in
            make.top.equalTo(quickActionsStackView.snp.bottom).offset(20)
            make.leading.trailing.bottom.equalToSuperview()
        }
    }
}
```

#### 2. Klassik UIKit (NSLayoutConstraint) Taqqoslash

```swift
import UIKit

final class BankingUIKitVC: UIViewController {
    private let balanceLabel = UILabel()
    private let transactionsTableView = UITableView()

    override func viewDidLoad() {
        super.viewDidLoad()
        [balanceLabel, transactionsTableView].forEach {
            $0.translatesAutoresizingMaskIntoConstraints = false
            view.addSubview($0)
        }

        NSLayoutConstraint.activate([
            balanceLabel.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 12),
            balanceLabel.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20),

            transactionsTableView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
            transactionsTableView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
            transactionsTableView.trailingAnchor.constraint(equalTo: view.trailingAnchor)
        ])
    }
}
```

#### 3. SwiftUI Ekvivalenti

```swift
import SwiftUI

struct BankingDashboardSwiftUIView: View {
    var body: some View {
        VStack(alignment: .leading, spacing: 16) {
            Text("$12,450.80")
                .font(.system(size: 24, weight: .black))
                .foregroundColor(.white)
                .padding(.horizontal, 20)

            RoundedRectangle(cornerRadius: 14)
                .fill(Color.purple)
                .frame(height: 85)
                .padding(.horizontal, 20)

            List {
                Text("Operatsiyalar ro'yxati...")
            }
        }
        .background(Color(white: 0.08).ignoresSafeArea())
    }
}
```

> 💡 **Pro Tip & Arxitektura siri:**
> Fintech ekranlarida TableView'ning `top` constraint'i yuqoridagi amallar paneliga, `bottom` constraint'i esa `view.snp.bottom` ga bog'lanishi orqali ro'yxat ekranning pastki chegarasigacha to'liq cho'ziladi.

</details>

---

## 🔴 Topshiriq 25: Restoran / Taom Yetkazish Ekrani (Collapsing Hero & Sticky Cart)

> **Daraja:** `Titan / Real-World Project` | **Maqsad:** Restoran sahifasi: tepada ovqatning cover rasmi, orqaga qaytish va yurakcha tugmalari, reyting kartasi, toifalar filtri (tabs), taomlar ro'yxati va eng pastda suzuvchi qizil savat paneli ('Savatga o'tish • $8.50').

Yetkazib berish ilovalarida (Wolt, Yandex Eats, Express24) har doim ekranning pastida ko'rinib turuvchi Sticky Bottom Cart paneli.

### Vizual Sxema (UI Mockup)

![Topshiriq 25: Restoran / Taom Yetkazish Ekrani (Collapsing Hero & Sticky Cart)](/lessons/images/snapkit/task_25.svg)

### 📋 Texnik Talablar va Cheklovlar

- Hero rasm: balandligi 140 pt, ustida suzuvchi Orqaga va Sevimlilar tugmalari.
- Restoran info kartasi rasmni qisman yopib turadi (overlap).
- Taomlar ro'yxati (UITableView yoki ScrollView).
- Sticky Cart Bar: ekranning pastki Safe Area chegarasiga qadalgan, balandligi 48 pt, qizil rangda.

<details>
<summary>💡 Kodni ko'rish (SnapKit, UIKit va SwiftUI yechimlari)</summary>

#### 1. SnapKit Yechimi (Asosiy)

```swift
import UIKit
import SnapKit

final class RestaurantDetailViewController: UIViewController {
    private let scrollView = UIScrollView()
    private let contentView = UIView()

    private let heroImageView: UIImageView = {
        let iv = UIImageView()
        iv.backgroundColor = .systemOrange
        return iv
    }()

    private let backButton = UIButton(type: .system)
    private let favoriteButton = UIButton(type: .system)

    private let stickyCartBar: UIView = {
        let v = UIView()
        v.backgroundColor = .systemPink
        v.layer.cornerRadius = 24
        return v
    }()

    override func viewDidLoad() {
        super.viewDidLoad()
        setupUI()
    }

    private func setupUI() {
        view.backgroundColor = UIColor(white: 0.08, alpha: 1.0)

        view.addSubview(scrollView)
        view.addSubview(stickyCartBar) // CartBar scrollView ustida suzib turadi!
        scrollView.addSubview(contentView)

        // 1. Sticky Cart Bar ekranning pastki Safe Area qismiga mahkamlanadi
        stickyCartBar.snp.makeConstraints { make in
            make.bottom.equalTo(view.safeAreaLayoutGuide.snp.bottom).offset(-8)
            make.leading.trailing.equalToSuperview().inset(16)
            make.height.equalTo(48)
        }

        // 2. ScrollView pastki qismi aynan Cart Bar'ga uriladi
        scrollView.snp.makeConstraints { make in
            make.top.leading.trailing.equalToSuperview()
            make.bottom.equalTo(stickyCartBar.snp.top).offset(-8)
        }

        contentView.snp.makeConstraints { make in
            make.edges.equalToSuperview()
            make.width.equalToSuperview()
        }

        contentView.addSubview(heroImageView)
        view.addSubview(backButton)
        view.addSubview(favoriteButton)

        heroImageView.snp.makeConstraints { make in
            make.top.leading.trailing.equalToSuperview()
            make.height.equalTo(140)
        }

        backButton.snp.makeConstraints { make in
            make.top.equalTo(view.safeAreaLayoutGuide).offset(12)
            make.leading.equalToSuperview().offset(16)
            make.size.equalTo(32)
        }

        favoriteButton.snp.makeConstraints { make in
            make.top.equalTo(backButton)
            make.trailing.equalToSuperview().offset(-16)
            make.size.equalTo(32)
        }
    }
}
```

#### 2. Klassik UIKit (NSLayoutConstraint) Taqqoslash

```swift
import UIKit

final class RestaurantUIKitVC: UIViewController {
    private let stickyCartBar = UIView()

    override func viewDidLoad() {
        super.viewDidLoad()
        stickyCartBar.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(stickyCartBar)

        NSLayoutConstraint.activate([
            stickyCartBar.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: -8),
            stickyCartBar.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 16),
            stickyCartBar.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -16),
            stickyCartBar.heightAnchor.constraint(equalToConstant: 48)
        ])
    }
}
```

#### 3. SwiftUI Ekvivalenti

```swift
import SwiftUI

struct RestaurantDetailSwiftUIView: View {
    var body: some View {
        ZStack(alignment: .bottom) {
            ScrollView {
                Rectangle().fill(Color.orange).frame(height: 140)
            }

            Button(action: {}) {
                Text("Savatga o'tish • $8.50")
                    .foregroundColor(.white).bold()
                    .frame(maxWidth: .infinity)
                    .frame(height: 48)
                    .background(Color.pink)
                    .clipShape(Capsule())
            }
            .padding(.horizontal, 16)
            .padding(.bottom, 8)
        }
        .background(Color(white: 0.08).ignoresSafeArea())
    }
}
```

> 💡 **Pro Tip & Arxitektura siri:**
> Pastki suzuvchi tugmalar (Floating Bottom Cart) mavjud bo'lganda, `scrollView.bottom` ni uning tepasiga bog'lash orqali kontentning eng oxirgi taomi tugma ostida ko'rinmay qolishining oldi olinadi.

</details>

---

## 🔴 Topshiriq 26: Kriptovalyuta / Birja Asset Ekrani (Chart & Order Book Columns)

> **Daraja:** `Titan / Real-World Project` | **Maqsad:** Binance yoki TradingView kabi kriptovalyuta ekrani: jonli narx ko'rsatkichi ($68,450.00), grafik maydoni, vaqt filtrlari (1D, 1W), Order Book (ikkita teng ustun: chapda yashil xaridorlar, o'ngda qizil sotuvchilar) va pastki 'Sotib olish' hamda 'Sotish' tugmalari.

Finans grafiklari va birja order book'idagi yonma-yon teng 50/50 ustunlar arxitekturasi.

### Vizual Sxema (UI Mockup)

![Topshiriq 26: Kriptovalyuta / Birja Asset Ekrani (Chart & Order Book Columns)](/lessons/images/snapkit/task_26.svg)

### 📋 Texnik Talablar va Cheklovlar

- Narx header: 20 pt matn, yonida yashil o'sish foizi nishoni.
- Grafik maydoni (Chart View): balandligi 80 pt.
- Order Book 2 ta teng ustunga bo'linadi (Bids 50% vs Asks 50%).
- Pastki ikkita tugma ('Sotib olish' va 'Sotish') teng kenglikda ekranning pastiga qadalsin.

<details>
<summary>💡 Kodni ko'rish (SnapKit, UIKit va SwiftUI yechimlari)</summary>

#### 1. SnapKit Yechimi (Asosiy)

```swift
import UIKit
import SnapKit

final class CryptoDetailViewController: UIViewController {
    private let priceLabel: UILabel = {
        let l = UILabel()
        l.text = "$68,450.00"
        l.textColor = .white
        l.font = .systemFont(ofSize: 22, weight: .black)
        return l
    }()

    private let chartContainerView: UIView = {
        let v = UIView()
        v.backgroundColor = UIColor(white: 0.15, alpha: 1.0)
        v.layer.cornerRadius = 8
        return v
    }()

    private let bidsColumnView = UIView()
    private let asksColumnView = UIView()

    private let buyButton: UIButton = {
        let btn = UIButton(type: .system)
        btn.setTitle("Sotib olish", for: .normal)
        btn.setTitleColor(.white, for: .normal)
        btn.titleLabel?.font = .systemFont(ofSize: 14, weight: .bold)
        btn.backgroundColor = .systemGreen
        btn.layer.cornerRadius = 10
        return btn
    }()

    private let sellButton: UIButton = {
        let btn = UIButton(type: .system)
        btn.setTitle("Sotish", for: .normal)
        btn.setTitleColor(.white, for: .normal)
        btn.titleLabel?.font = .systemFont(ofSize: 14, weight: .bold)
        btn.backgroundColor = .systemRed
        btn.layer.cornerRadius = 10
        return btn
    }()

    override func viewDidLoad() {
        super.viewDidLoad()
        setupUI()
    }

    private func setupUI() {
        view.backgroundColor = UIColor(white: 0.08, alpha: 1.0)

        [priceLabel, chartContainerView, bidsColumnView, asksColumnView, buyButton, sellButton].forEach {
            view.addSubview($0)
        }

        priceLabel.snp.makeConstraints { make in
            make.top.equalTo(view.safeAreaLayoutGuide).offset(12)
            make.leading.equalToSuperview().offset(16)
        }

        chartContainerView.snp.makeConstraints { make in
            make.top.equalTo(priceLabel.snp.bottom).offset(12)
            make.leading.trailing.equalToSuperview().inset(16)
            make.height.equalTo(80)
        }

        // Order Book 2 teng ustun:
        bidsColumnView.snp.makeConstraints { make in
            make.top.equalTo(chartContainerView.snp.bottom).offset(16)
            make.leading.equalToSuperview().offset(16)
            make.height.equalTo(100)
        }

        asksColumnView.snp.makeConstraints { make in
            make.top.equalTo(bidsColumnView)
            make.leading.equalTo(bidsColumnView.snp.trailing).offset(12)
            make.trailing.equalToSuperview().offset(-16)
            make.width.equalTo(bidsColumnView) // Teng 50% kenglik!
            make.height.equalTo(bidsColumnView)
        }

        // Pastki Sotib olish / Sotish tugmalari:
        buyButton.snp.makeConstraints { make in
            make.bottom.equalTo(view.safeAreaLayoutGuide).offset(-12)
            make.leading.equalToSuperview().offset(16)
            make.height.equalTo(44)
        }

        sellButton.snp.makeConstraints { make in
            make.bottom.equalTo(buyButton)
            make.leading.equalTo(buyButton.snp.trailing).offset(12)
            make.trailing.equalToSuperview().offset(-16)
            make.width.equalTo(buyButton) // 50/50 nisbat
            make.height.equalTo(buyButton)
        }
    }
}
```

#### 2. Klassik UIKit (NSLayoutConstraint) Taqqoslash

```swift
import UIKit

final class CryptoUIKitVC: UIViewController {
    private let buyBtn = UIButton()
    private let sellBtn = UIButton()

    override func viewDidLoad() {
        super.viewDidLoad()
        [buyBtn, sellBtn].forEach {
            $0.translatesAutoresizingMaskIntoConstraints = false
            view.addSubview($0)
        }

        NSLayoutConstraint.activate([
            buyBtn.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 16),
            buyBtn.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: -12),
            buyBtn.heightAnchor.constraint(equalToConstant: 44),

            sellBtn.leadingAnchor.constraint(equalTo: buyBtn.trailingAnchor, constant: 12),
            sellBtn.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -16),
            sellBtn.bottomAnchor.constraint(equalTo: buyBtn.bottomAnchor),
            sellBtn.widthAnchor.constraint(equalTo: buyBtn.widthAnchor),
            sellBtn.heightAnchor.constraint(equalToConstant: 44)
        ])
    }
}
```

#### 3. SwiftUI Ekvivalenti

```swift
import SwiftUI

struct CryptoDetailSwiftUIView: View {
    var body: some View {
        VStack {
            Text("$68,450.00").font(.title.bold()).foregroundColor(.white)
            Spacer()
            HStack(spacing: 12) {
                Button("Sotib olish") {}.frame(maxWidth: .infinity, height: 44).background(Color.green).foregroundColor(.white).cornerRadius(10)
                Button("Sotish") {}.frame(maxWidth: .infinity, height: 44).background(Color.red).foregroundColor(.white).cornerRadius(10)
            }
            .padding(.horizontal, 16)
        }
        .background(Color(white: 0.08).ignoresSafeArea())
    }
}
```

> 💡 **Pro Tip & Arxitektura siri:**
> Ikkita tugmani 50/50 teng bo'lishda `make.width.equalTo(buyButton)` usulini qo'llash ekranning istalgan kengligida (iPhone SE yoki Pro Max) mukammal simmetriyani kafolatlaydi.

</details>

---

## 🔴 Topshiriq 27: App Store 'Bugun' Interaktiv Karta (Today Card Lockup)

> **Daraja:** `Titan / Real-World Project` | **Maqsad:** Apple App Store 'Bugun' (Today) yorlig'idagi mashhur karta: ulkan artwork rasmi, 'KUN O'YINI' sarlavhasi, o'ng yuqoridagi '✕' yopish tugmasi va karta ichidagi pastki App Lockup qatori (52x52 belgi, o'yin nomi va 'YUKLASH' tugmasi).

App Store dizaynidagi murakkab kompozitsiya va ichki bloklarni qadash ko'nikmasi.

### Vizual Sxema (UI Mockup)

![Topshiriq 27: App Store 'Bugun' Interaktiv Karta (Today Card Lockup)](/lessons/images/snapkit/task_27.svg)

### 📋 Texnik Talablar va Cheklovlar

- Asosiy karta: burchaklar radiusi 20 pt, soya bilan.
- Yuqori rasm qismi: karta balandligining 70% qismi.
- Yopish tugmasi ('✕'): rasmining yuqori-o'ng burchagida suzib turadi.
- Pastki ilova qatori: 52x52 icon, 2 qatorli matn va o'ngda kapsula shaklidagi 'YUKLASH' tugmasi.

<details>
<summary>💡 Kodni ko'rish (SnapKit, UIKit va SwiftUI yechimlari)</summary>

#### 1. SnapKit Yechimi (Asosiy)

```swift
import UIKit
import SnapKit

final class AppStoreTodayCardView: UIView {
    private let heroArtworkView: UIView = {
        let v = UIView()
        v.backgroundColor = .systemPurple
        v.layer.cornerRadius = 20
        v.clipsToBounds = true
        return v
    }()

    private let closeButton: UIButton = {
        let btn = UIButton(type: .system)
        btn.setTitle("✕", for: .normal)
        btn.setTitleColor(.white, for: .normal)
        btn.backgroundColor = UIColor(white: 0.1, alpha: 0.6)
        btn.layer.cornerRadius = 14
        return btn
    }()

    private let appLockupView: UIView = {
        let v = UIView()
        v.backgroundColor = UIColor(white: 0.15, alpha: 1.0)
        v.layer.cornerRadius = 20
        return v
    }()

    private let appIconImageView: UIImageView = {
        let iv = UIImageView()
        iv.backgroundColor = .systemBlue
        iv.layer.cornerRadius = 12
        iv.clipsToBounds = true
        return iv
    }()

    private let getButton: UIButton = {
        let btn = UIButton(type: .system)
        btn.setTitle("YUKLASH", for: .normal)
        btn.setTitleColor(.black, for: .normal)
        btn.titleLabel?.font = .systemFont(ofSize: 11, weight: .heavy)
        btn.backgroundColor = .systemSky ?? .systemBlue
        btn.layer.cornerRadius = 16
        return btn
    }()

    override init(frame: CGRect) {
        super.init(frame: frame)
        setupUI()
    }

    required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") }

    private func setupUI() {
        layer.cornerRadius = 20
        addSubview(heroArtworkView)
        addSubview(closeButton)
        addSubview(appLockupView)

        appLockupView.addSubview(appIconImageView)
        appLockupView.addSubview(getButton)

        heroArtworkView.snp.makeConstraints { make in
            make.top.leading.trailing.equalToSuperview()
            make.bottom.equalTo(appLockupView.snp.top).offset(15) // Qisman tutashuv
        }

        closeButton.snp.makeConstraints { make in
            make.top.trailing.equalToSuperview().inset(16)
            make.size.equalTo(28)
        }

        appLockupView.snp.makeConstraints { make in
            make.leading.trailing.bottom.equalToSuperview()
            make.height.equalTo(80)
        }

        appIconImageView.snp.makeConstraints { make in
            make.leading.equalToSuperview().offset(16)
            make.centerY.equalToSuperview()
            make.size.equalTo(52)
        }

        getButton.snp.makeConstraints { make in
            make.trailing.equalToSuperview().offset(-16)
            make.centerY.equalToSuperview()
            make.size.equalTo(CGSize(width: 85, height: 32))
        }
    }
}

private extension UIColor {
    static var systemSky: UIColor? { UIColor(red: 0.22, green: 0.74, blue: 0.97, alpha: 1.0) }
}
```

#### 2. Klassik UIKit (NSLayoutConstraint) Taqqoslash

```swift
import UIKit

final class AppStoreTodayUIKitCard: UIView {
    private let appLockupView = UIView()
    private let getButton = UIButton()

    override init(frame: CGRect) {
        super.init(frame: frame)
        [appLockupView, getButton].forEach {
            $0.translatesAutoresizingMaskIntoConstraints = false
            addSubview($0)
        }

        NSLayoutConstraint.activate([
            appLockupView.leadingAnchor.constraint(equalTo: leadingAnchor),
            appLockupView.trailingAnchor.constraint(equalTo: trailingAnchor),
            appLockupView.bottomAnchor.constraint(equalTo: bottomAnchor),
            appLockupView.heightAnchor.constraint(equalToConstant: 80)
        ])
    }

    required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") }
}
```

#### 3. SwiftUI Ekvivalenti

```swift
import SwiftUI

struct AppStoreTodaySwiftUIView: View {
    var body: some View {
        VStack(spacing: 0) {
            ZStack(alignment: .topTrailing) {
                Rectangle().fill(Color.purple).frame(height: 240)
                Button("✕") {}
                    .frame(width: 28, height: 28)
                    .background(Color.black.opacity(0.5))
                    .clipShape(Circle())
                    .padding(16)
            }

            HStack {
                RoundedRectangle(cornerRadius: 12).fill(Color.blue).frame(width: 52, height: 52)
                Spacer()
                Button("YUKLASH") {}
                    .padding(.horizontal, 16).padding(.vertical, 8)
                    .background(Color.blue).foregroundColor(.black).clipShape(Capsule())
            }
            .padding(16)
            .background(Color(white: 0.15))
        }
        .clipShape(RoundedRectangle(cornerRadius: 20))
    }
}
```

> 💡 **Pro Tip & Arxitektura siri:**
> App Store kartalarida burchak radiusi `layer.cornerRadius = 20` qilinganda, ichki rasm chegaradan chiqmasligi uchun ota-ona view'da `clipsToBounds = true` yoki ichki qatlamlarda ham radius berilishi kerak.

</details>

---

## 🔴 Topshiriq 28: Fitness & Salomatlik Faollik Paneli (Concentric Rings & Weekly Chart)

> **Daraja:** `Titan / Real-World Project` | **Maqsad:** Apple Fitness uslubidagi faollik ekrani: chapda konsentrik faollik aylanasi (Move, Exercise, Stand), o'ngda 3 ta metrika yozuvlari, haftalik 7 ta ustunli vertikal grafik va pastda yurak urishi (72 BPM) kartasi.

Salomatlik ilovalaridagi geometrik doiralar va haftalik diagramma qutilarining joylashuvi.

### Vizual Sxema (UI Mockup)

![Topshiriq 28: Fitness & Salomatlik Faollik Paneli (Concentric Rings & Weekly Chart)](/lessons/images/snapkit/task_28.svg)

### 📋 Texnik Talablar va Cheklovlar

- Faollik doiralari bloki chapda (100x100 o'lcham).
- O'ng tomonda 3 ta qator metrikalar (Qizil, Yashil, Ko'k ranglar bilan).
- Haftalik diagramma: 7 ta ustun yonma-yon teng masofada joylashsin.
- Yurak urishi kartasi: pastda 60 pt balandlikda, chapda yurak belgisi, o'ngda miniatyura EKG grafigi.

<details>
<summary>💡 Kodni ko'rish (SnapKit, UIKit va SwiftUI yechimlari)</summary>

#### 1. SnapKit Yechimi (Asosiy)

```swift
import UIKit
import SnapKit

final class FitnessDashboardViewController: UIViewController {
    private let ringsContainerView: UIView = {
        let v = UIView()
        v.backgroundColor = .clear
        return v
    }()

    private let metricsStackView: UIStackView = {
        let stack = UIStackView()
        stack.axis = .vertical
        stack.spacing = 8
        stack.distribution = .fillEqually
        return stack
    }()

    private let weeklyChartContainer: UIView = {
        let v = UIView()
        v.backgroundColor = UIColor(white: 0.14, alpha: 1.0)
        v.layer.cornerRadius = 12
        return v
    }()

    private let heartRateCard: UIView = {
        let v = UIView()
        v.backgroundColor = UIColor(white: 0.14, alpha: 1.0)
        v.layer.cornerRadius = 12
        return v
    }()

    override func viewDidLoad() {
        super.viewDidLoad()
        setupUI()
    }

    private func setupUI() {
        view.backgroundColor = UIColor(white: 0.08, alpha: 1.0)

        [ringsContainerView, metricsStackView, weeklyChartContainer, heartRateCard].forEach {
            view.addSubview($0)
        }

        ringsContainerView.snp.makeConstraints { make in
            make.top.equalTo(view.safeAreaLayoutGuide).offset(16)
            make.leading.equalToSuperview().offset(20)
            make.size.equalTo(100)
        }

        metricsStackView.snp.makeConstraints { make in
            make.leading.equalTo(ringsContainerView.snp.trailing).offset(20)
            make.trailing.equalToSuperview().offset(-20)
            make.centerY.equalTo(ringsContainerView)
        }

        weeklyChartContainer.snp.makeConstraints { make in
            make.top.equalTo(ringsContainerView.snp.bottom).offset(24)
            make.leading.trailing.equalToSuperview().inset(16)
            make.height.equalTo(120)
        }

        heartRateCard.snp.makeConstraints { make in
            make.top.equalTo(weeklyChartContainer.snp.bottom).offset(16)
            make.leading.trailing.equalToSuperview().inset(16)
            make.height.equalTo(60)
        }
    }
}
```

#### 2. Klassik UIKit (NSLayoutConstraint) Taqqoslash

```swift
import UIKit

final class FitnessUIKitVC: UIViewController {
    private let ringsView = UIView()
    private let chartView = UIView()

    override func viewDidLoad() {
        super.viewDidLoad()
        [ringsView, chartView].forEach {
            $0.translatesAutoresizingMaskIntoConstraints = false
            view.addSubview($0)
        }

        NSLayoutConstraint.activate([
            ringsView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 16),
            ringsView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20),
            ringsView.widthAnchor.constraint(equalToConstant: 100),
            ringsView.heightAnchor.constraint(equalToConstant: 100)
        ])
    }
}
```

#### 3. SwiftUI Ekvivalenti

```swift
import SwiftUI

struct FitnessDashboardSwiftUIView: View {
    var body: some View {
        VStack(spacing: 20) {
            HStack(spacing: 20) {
                Circle().stroke(Color.red, lineWidth: 8).frame(width: 100, height: 100)
                VStack(alignment: .leading, spacing: 8) {
                    Text("Harakat: 540 kkal").foregroundColor(.red)
                    Text("Mashq: 42 daq").foregroundColor(.green)
                    Text("Tik turish: 10 soat").foregroundColor(.blue)
                }
            }
            RoundedRectangle(cornerRadius: 12).fill(Color(white: 0.14)).frame(height: 120)
        }
        .padding(16)
        .background(Color(white: 0.08).ignoresSafeArea())
    }
}
```

> 💡 **Pro Tip & Arxitektura siri:**
> Haftalik ustunli grafikda har bir ustun balandligini belgilashda `barView.snp.makeConstraints { make.height.equalTo(weeklyChartContainer).multipliedBy(ratio) }` usuli eng moslashuvchan yechim hisoblanadi.

</details>

---

## 🔴 Topshiriq 29: Buyurtmani Rasmiylashtirish Ekrani (Checkout Multi-Step Form)

> **Daraja:** `Titan / Real-World Project` | **Maqsad:** E-Commerce checkout formasi: manzil kartasi, to'lov usuli (karta raqami bilan), promokod kiritish maydoni va 'Qo'llash' tugmasi, hisob-kitob jadvallari (Mahsulotlar, Yetkazib berish, Chegirma, Jami) va pastki qadalgan 'Buyurtma berish' tugmasi.

Forma elementlari, dinamik matnlar va moliyaviy hisob-kitob qatorlarining uzluksiz bog'lanishi.

### Vizual Sxema (UI Mockup)

![Topshiriq 29: Buyurtmani Rasmiylashtirish Ekrani (Checkout Multi-Step Form)](/lessons/images/snapkit/task_29.svg)

### 📋 Texnik Talablar va Cheklovlar

- Yetkazib berish manzili kartasi: ichida manzil va o'ngda 'O'zgartirish' havolasi.
- Promokod maydoni: inline 'Qo'llash' tugmasi bilan bir qatorda.
- Hisob-kitob jadvali: 4 ta qator (Mahsulotlar, Yetkazib berish, Chegirma, Jami to'lov).
- Sticky 'Buyurtma berish' tugmasi: pastki Safe Area ustida, balandligi 50 pt.

<details>
<summary>💡 Kodni ko'rish (SnapKit, UIKit va SwiftUI yechimlari)</summary>

#### 1. SnapKit Yechimi (Asosiy)

```swift
import UIKit
import SnapKit

final class CheckoutSummaryViewController: UIViewController {
    private let scrollView = UIScrollView()
    private let contentView = UIView()

    private let addressCardView: UIView = {
        let v = UIView()
        v.backgroundColor = UIColor(white: 0.15, alpha: 1.0)
        v.layer.cornerRadius = 10
        return v
    }()

    private let promoCodeContainer: UIView = {
        let v = UIView()
        v.backgroundColor = UIColor(white: 0.15, alpha: 1.0)
        v.layer.cornerRadius = 8
        return v
    }()

    private let applyPromoButton: UIButton = {
        let btn = UIButton(type: .system)
        btn.setTitle("Qo'llash", for: .normal)
        btn.setTitleColor(.white, for: .normal)
        btn.backgroundColor = .systemGreen
        btn.layer.cornerRadius = 6
        return btn
    }()

    private let calculationCardView: UIView = {
        let v = UIView()
        v.backgroundColor = UIColor(white: 0.15, alpha: 1.0)
        v.layer.cornerRadius = 10
        return v
    }()

    private let placeOrderButton: UIButton = {
        let btn = UIButton(type: .system)
        btn.setTitle("Buyurtma berish ($40.00)", for: .normal)
        btn.setTitleColor(.white, for: .normal)
        btn.titleLabel?.font = .systemFont(ofSize: 15, weight: .bold)
        btn.backgroundColor = .systemOrange
        btn.layer.cornerRadius = 25
        return btn
    }()

    override func viewDidLoad() {
        super.viewDidLoad()
        setupUI()
    }

    private func setupUI() {
        view.backgroundColor = UIColor(white: 0.08, alpha: 1.0)

        view.addSubview(scrollView)
        view.addSubview(placeOrderButton)
        scrollView.addSubview(contentView)

        placeOrderButton.snp.makeConstraints { make in
            make.bottom.equalTo(view.safeAreaLayoutGuide).offset(-8)
            make.leading.trailing.equalToSuperview().inset(16)
            make.height.equalTo(50)
        }

        scrollView.snp.makeConstraints { make in
            make.top.leading.trailing.equalToSuperview()
            make.bottom.equalTo(placeOrderButton.snp.top).offset(-8)
        }

        contentView.snp.makeConstraints { make in
            make.edges.equalToSuperview()
            make.width.equalToSuperview()
        }

        [addressCardView, promoCodeContainer, calculationCardView].forEach {
            contentView.addSubview($0)
        }
        promoCodeContainer.addSubview(applyPromoButton)

        addressCardView.snp.makeConstraints { make in
            make.top.equalToSuperview().offset(12)
            make.leading.trailing.equalToSuperview().inset(16)
            make.height.equalTo(50)
        }

        promoCodeContainer.snp.makeConstraints { make in
            make.top.equalTo(addressCardView.snp.bottom).offset(12)
            make.leading.trailing.equalToSuperview().inset(16)
            make.height.equalTo(40)
        }

        applyPromoButton.snp.makeConstraints { make in
            make.trailing.equalToSuperview().offset(-6)
            make.centerY.equalToSuperview()
            make.size.equalTo(CGSize(width: 80, height: 30))
        }

        calculationCardView.snp.makeConstraints { make in
            make.top.equalTo(promoCodeContainer.snp.bottom).offset(16)
            make.leading.trailing.equalToSuperview().inset(16)
            make.height.equalTo(120)
            make.bottom.equalToSuperview().offset(-20) // ScrollView bottom!
        }
    }
}
```

#### 2. Klassik UIKit (NSLayoutConstraint) Taqqoslash

```swift
import UIKit

final class CheckoutUIKitVC: UIViewController {
    private let placeOrderBtn = UIButton()

    override func viewDidLoad() {
        super.viewDidLoad()
        placeOrderBtn.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(placeOrderBtn)

        NSLayoutConstraint.activate([
            placeOrderBtn.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: -8),
            placeOrderBtn.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 16),
            placeOrderBtn.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -16),
            placeOrderBtn.heightAnchor.constraint(equalToConstant: 50)
        ])
    }
}
```

#### 3. SwiftUI Ekvivalenti

```swift
import SwiftUI

struct CheckoutSwiftUIView: View {
    var body: some View {
        VStack {
            ScrollView {
                VStack(spacing: 12) {
                    RoundedRectangle(cornerRadius: 10).fill(Color(white: 0.15)).frame(height: 50)
                    RoundedRectangle(cornerRadius: 10).fill(Color(white: 0.15)).frame(height: 120)
                }
                .padding(16)
            }

            Button("Buyurtma berish ($40.00)") {}
                .frame(maxWidth: .infinity, height: 50)
                .background(Color.orange)
                .foregroundColor(.white)
                .clipShape(Capsule())
                .padding(.horizontal, 16)
                .padding(.bottom, 8)
        }
        .background(Color(white: 0.08).ignoresSafeArea())
    }
}
```

> 💡 **Pro Tip & Arxitektura siri:**
> Formada narx jadvalining 'Chapda matn, o'ngda raqam' qatorlarini `UIStackView(axis: .horizontal)` bilan yaratib, `make.leading.trailing.equalToSuperview()` qilish har qanday ekranda chetlar tekis bo'lishini ta'minlaydi.

</details>

---

## 🔴 Topshiriq 30: To'liq Ekranli Podcast / Audio Pleer (PodcastPlayerFullView)

> **Daraja:** `Titan / Zero to Hero Masterpiece` | **Maqsad:** Apple Podcasts va Spotify to'liq ekranli audio pleeri: yuqori boshqaruv paneli (pastga tushirish chevron, ulashish), markazda 1:1 kvadrat katta albom rasmi (110x110), epizod nomi, to'lqinsimon slayder (Waveform scrubber), 5 ta ijro tugmalari (15s orqaga, oldingi, katta play 44x44, keyingi, 30s oldinga) va pastdagi Bluetooth / AirPods chiqish marshruti.

Audio ilovalarning barcha ekran o'lchamlari bo'yicha moslashuvchan, mukammal simmetrik pleer arxitekturasi.

### Vizual Sxema (UI Mockup)

![Topshiriq 30: To'liq Ekranli Podcast / Audio Pleer (PodcastPlayerFullView)](/lessons/images/snapkit/task_30.svg)

### 📋 Texnik Talablar va Cheklovlar

- Albom rasmi: kvadrat 1:1, burchak radiusi 14 pt, soya (drop shadow).
- Slayder paneli: chapda o'tgan vaqt (18:42), o'ngda qolgan vaqt (-29:18).
- 5 ta boshqaruv tugmasi bitta gorizontal o'qda teng taqsimlansin.
- O'rtadagi Play/Pause tugmasi boshqa tugmalardan sezilarli darajada katta (44x44) bo'lsin.

<details>
<summary>💡 Kodni ko'rish (SnapKit, UIKit va SwiftUI yechimlari)</summary>

#### 1. SnapKit Yechimi (Asosiy)

```swift
import UIKit
import SnapKit

final class PodcastPlayerFullViewController: UIViewController {
    private let dismissButton: UIButton = {
        let btn = UIButton(type: .system)
        btn.setTitle("⌄", for: .normal)
        btn.setTitleColor(.white, for: .normal)
        btn.titleLabel?.font = .systemFont(ofSize: 24, weight: .bold)
        return btn
    }()

    private let artworkImageView: UIImageView = {
        let iv = UIImageView()
        iv.backgroundColor = .systemPurple
        iv.layer.cornerRadius = 14
        iv.clipsToBounds = true
        return iv
    }()

    private let titleLabel: UILabel = {
        let l = UILabel()
        l.text = "Ep. 42: SnapKit Zero to Hero Maxsus Darsi"
        l.textColor = .white
        l.font = .systemFont(ofSize: 15, weight: .black)
        l.textAlignment = .center
        return l
    }()

    private let sliderView = UISlider()

    private let controlsStackView: UIStackView = {
        let stack = UIStackView()
        stack.axis = .horizontal
        stack.distribution = .equalSpacing
        stack.alignment = .center
        return stack
    }()

    private let playButton: UIButton = {
        let btn = UIButton(type: .system)
        btn.setTitle("▶", for: .normal)
        btn.setTitleColor(.white, for: .normal)
        btn.backgroundColor = .systemPink
        btn.layer.cornerRadius = 22
        return btn
    }()

    private let audioRouteLabel: UILabel = {
        let l = UILabel()
        l.text = "🎧 AirPods Pro (Azimjon)"
        l.textColor = .systemSky ?? .systemBlue
        l.font = .systemFont(ofSize: 11, weight: .semibold)
        l.textAlignment = .center
        return l
    }()

    override func viewDidLoad() {
        super.viewDidLoad()
        setupUI()
    }

    private func setupUI() {
        view.backgroundColor = UIColor(white: 0.08, alpha: 1.0)

        [dismissButton, artworkImageView, titleLabel, sliderView, controlsStackView, audioRouteLabel].forEach {
            view.addSubview($0)
        }

        dismissButton.snp.makeConstraints { make in
            make.top.equalTo(view.safeAreaLayoutGuide).offset(8)
            make.leading.equalToSuperview().offset(16)
            make.size.equalTo(32)
        }

        // Kvadrat Artwork - markazda
        artworkImageView.snp.makeConstraints { make in
            make.top.equalTo(dismissButton.snp.bottom).offset(16)
            make.centerX.equalToSuperview()
            make.size.equalTo(110)
        }

        titleLabel.snp.makeConstraints { make in
            make.top.equalTo(artworkImageView.snp.bottom).offset(16)
            make.leading.trailing.equalToSuperview().inset(24)
        }

        sliderView.snp.makeConstraints { make in
            make.top.equalTo(titleLabel.snp.bottom).offset(20)
            make.leading.trailing.equalToSuperview().inset(24)
        }

        controlsStackView.snp.makeConstraints { make in
            make.top.equalTo(sliderView.snp.bottom).offset(24)
            make.leading.trailing.equalToSuperview().inset(32)
            make.height.equalTo(50)
        }

        playButton.snp.makeConstraints { make in
            make.size.equalTo(44)
        }

        audioRouteLabel.snp.makeConstraints { make in
            make.bottom.equalTo(view.safeAreaLayoutGuide).offset(-16)
            make.centerX.equalToSuperview()
        }
    }
}

private extension UIColor {
    static var systemSky: UIColor? { UIColor(red: 0.22, green: 0.74, blue: 0.97, alpha: 1.0) }
}
```

#### 2. Klassik UIKit (NSLayoutConstraint) Taqqoslash

```swift
import UIKit

final class PodcastUIKitVC: UIViewController {
    private let artworkImageView = UIImageView()

    override func viewDidLoad() {
        super.viewDidLoad()
        artworkImageView.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(artworkImageView)

        NSLayoutConstraint.activate([
            artworkImageView.centerXAnchor.constraint(equalTo: view.centerXAnchor),
            artworkImageView.centerYAnchor.constraint(equalTo: view.centerYAnchor),
            artworkImageView.widthAnchor.constraint(equalToConstant: 110),
            artworkImageView.heightAnchor.constraint(equalToConstant: 110)
        ])
    }
}
```

#### 3. SwiftUI Ekvivalenti

```swift
import SwiftUI

struct PodcastPlayerSwiftUIView: View {
    var body: some View {
        VStack(spacing: 20) {
            RoundedRectangle(cornerRadius: 14)
                .fill(Color.purple)
                .frame(width: 110, height: 110)

            Text("Ep. 42: SnapKit Zero to Hero Maxsus Darsi")
                .font(.headline.bold())
                .foregroundColor(.white)

            HStack(spacing: 24) {
                Text("↺15").foregroundColor(.gray)
                Circle().fill(Color.pink).frame(width: 44, height: 44)
                Text("30↻").foregroundColor(.gray)
            }
        }
        .background(Color(white: 0.08).ignoresSafeArea())
    }
}
```

> 💡 **Pro Tip & Arxitektura siri:**
> Tabriklaymiz! Siz 30 ta to'liq vizual topshiriqni yakunladingiz! Ushbu bilimlar bilan siz iOS ekotizimidagi istalgan murakkab ilovani — Instagram, Spotify, Binance, Telegram yoki Amazon darajasidagi interfeyslarni SnapKit orqali yuqori darajada qura olasiz.

</details>

---

## 🎓 Zero to Hero Xulosasi va Keyingi Qadamlar

Siz SnapKit bo'yicha eng oddiy markazlashtirishdan boshlab, haqiqiy App Store gigantlari (Instagram Profile, E-Commerce Home Feed, Telegram Chat, Revolut Banking, Food Delivery, Binance Crypto, App Store Today, Apple Fitness, Checkout va Spotify/Podcast Player) darajasidagi **30 ta murakkab vizual topshiriqni** to'liq yakunladingiz!

### Ushbu amaliyotda o'rganilgan asosiy ko'nikmalar:
1. **Poydevor:** `center`, `size`, `edges`, `inset` va `offset` o'rtasidagi farqlarni his qilish.
2. **Moslashuvchanlik:** `safeAreaLayoutGuide` bilan Dynamic Island va Notch'ga mos interfeys qurish.
3. **Proporsiyalar:** `multipliedBy` va `dividedBy` yordamida 16:9 yoki 1.586 aniq geometrik nisbatlarni ushlash.
4. **Cheklovlar va Tengsizliklar:** `greaterThanOrEqualTo` hamda `lessThanOrEqualTo` orqali Telegram va iMessage chat bubble'larini yaratish.
5. **Ustuvorlik jangi:** `setContentCompressionResistancePriority` va `setContentHuggingPriority` bilan qaysi matn '...' bo'lishini va qaysi biri to'liq qolishini boshqarish.
6. **O'zgaruvchan ro'yxatlar:** Self-sizing `UITableViewCell` uchun tepadan pastgacha uzluksiz pin-to-bottom qoidasi.
7. **ScrollView qat'iy qoidalari:** `contentView` ning `edges` va `width` bog'lanishi orqali mukammal vertikal scroll.
8. **Animatsiyalar:** `remakeConstraints` va `layoutIfNeeded()` bilan 120Hz silliq interaktiv chiziqlar.
9. **Real Production Screens:** `keyboardLayoutGuide` bilan chat input paneli, Stretchy Profile header, Sticky Floating Cart bar, ikkita teng ustunli birja kitobi va audio pleer boshqaruvi.

Endi siz iOS interfeyslarini yaratishda har qanday murakkablikdagi dizaynni ko'rganingizda uni tezkor, toza va xatosiz kodga aylantira olasiz! 🚀
