Subscription Manager

Subscription Manager

by dockui

Modern SwiftUI template witha visually appealing layout to showcase services like Spotify, Adobe, and gym memberships.

Platform
SwiftUI
Code
Native Swift
Format
Screen
Access
Free

Code Snippet

import SwiftUI

struct SubscriptionManagerView: View {
    // Sample subscription data
    @State private var subscriptions: [Subscription] = [
        Subscription(
            name: "Spotify Premium",
            icon: "music.note",
            color: Color.green,
            price: 9.99,
            billingCycle: .monthly,
            nextBillingDate: Date().addingTimeInterval(86400 * 12),
            category: .entertainment
        ),
        Subscription(
            name: "Adobe Creative Cloud",
            icon: "paintbrush.pointed",
            color: Color.red,
            price: 52.99,
            billingCycle: .monthly,
            nextBillingDate: Date().addingTimeInterval(86400 * 5),
            category: .productivity
        ),
        Subscription(
            name: "Fitness First",
            icon: "figure.run",
            color: Color.orange,
            price: 75.00,
            billingCycle: .monthly,
            nextBillingDate: Date().addingTimeInterval(86400 * 20),
            category: .health
        ),
        Subscription(
            name: "Netflix",
            icon: "play.tv",
            color: Color.red,
            price: 15.99,
            billingCycle: .monthly,
            nextBillingDate: Date().addingTimeInterval(86400 * 8),
            category: .entertainment
        ),
        Subscription(
            name: "iCloud+",
            icon: "cloud",
            color: Color.blue,
            price: 2.99,
            billingCycle: .monthly,
            nextBillingDate: Date().addingTimeInterval(86400 * 15),
            category: .storage
        )
    ]
    
    @State private var selectedCategory: SubscriptionCategory?
    @State private var showingAddSubscription = false
    
    var totalMonthly: Double {
        subscriptions.reduce(0) { $0 + $1.price }
    }
    
    var body: some View {
        NavigationStack {
            ScrollView {
                VStack(spacing: 24) {
                    // Monthly Summary Card
                    VStack(spacing: 16) {
                        HStack {
                            VStack(alignment: .leading) {
                                Text("Monthly Total")
                                    .font(.subheadline)
                                    .foregroundColor(.secondary)
                                Text("$\(totalMonthly, specifier: "%.2f")")
                                    .font(.system(size: 34, weight: .bold))
                            }
                            Spacer()
                            
                            // Circular progress to next billing
                            ZStack {
                                Circle()
                                    .stroke(Color.secondary.opacity(0.2), lineWidth: 4)
                                Circle()
                                    .trim(from: 0, to: 0.7)
                                    .stroke(Color.blue, style: StrokeStyle(
                                        lineWidth: 4,
                                        lineCap: .round
                                    ))
                                    .rotationEffect(.degrees(-90))
                            }
                            .frame(width: 50, height: 50)
                        }
                        
                        // Category pills
                        ScrollView(.horizontal, showsIndicators: false) {
                            HStack(spacing: 12) {
                                ForEach(SubscriptionCategory.allCases) { category in
                                    CategoryPillSub(
                                        category: category,
                                        isSelected: selectedCategory == category,
                                        action: {
                                            withAnimation {
                                                selectedCategory = selectedCategory == category ? nil : category
                                            }
                                        }
                                    )
                                }
                            }
                            .padding(.horizontal, 4)
                        }
                    }
                    .padding()
                    .background(Color(uiColor: .systemBackground))
                    .cornerRadius(16)
                    .shadow(radius: 2)
                    .padding(.horizontal)
                    
                    // Subscriptions List
                    VStack(spacing: 16) {
                        ForEach(filteredSubscriptions) { subscription in
                            SubscriptionRow(subscription: subscription)
                        }
                    }
                    .padding(.horizontal)
                }
                .padding(.vertical)
            }
            .background(Color(uiColor: .systemGroupedBackground))
            .navigationTitle("Subscriptions")
            .toolbar {
                ToolbarItem(placement: .primaryAction) {
                    Button(action: { showingAddSubscription = true }) {
                        Image(systemName: "plus.circle.fill")
                            .font(.title3)
                    }
                }
            }
        }
    }
    
    var filteredSubscriptions: [Subscription] {
        guard let category = selectedCategory else { return subscriptions }
        return subscriptions.filter { $0.category == category }
    }
}

struct SubscriptionRow: View {
    let subscription: Subscription
    
    var body: some View {
        HStack(spacing: 16) {
            // Icon
            ZStack {
                RoundedRectangle(cornerRadius: 12)
                    .fill(subscription.color.opacity(0.1))
                    .frame(width: 48, height: 48)
                
                Image(systemName: subscription.icon)
                    .font(.title2)
                    .foregroundColor(subscription.color)
            }
            
            // Details
            VStack(alignment: .leading, spacing: 4) {
                Text(subscription.name)
                    .font(.headline)
                
                Text(subscription.nextBillingDate, style: .date)
                    .font(.caption)
                    .foregroundColor(.secondary)
            }
            
            Spacer()
            
            // Price
            VStack(alignment: .trailing, spacing: 4) {
                Text("$\(subscription.price, specifier: "%.2f")")
                    .font(.title3)
                    .bold()
                
                Text(subscription.billingCycle.rawValue)
                    .font(.caption)
                    .foregroundColor(.secondary)
            }
        }
        .padding()
        .background(Color(uiColor: .systemBackground))
        .cornerRadius(16)
        .shadow(radius: 2)
    }
}

struct CategoryPillSub: View {
    let category: SubscriptionCategory
    let isSelected: Bool
    let action: () -> Void
    
    var body: some View {
        Button(action: action) {
            Text(category.rawValue)
                .font(.subheadline)
                .padding(.horizontal, 16)
                .padding(.vertical, 8)
                .background(isSelected ? Color.blue : Color(uiColor: .systemGray5))
                .foregroundColor(isSelected ? .white : .primary)
                .cornerRadius(20)
        }
    }
}

// Models
struct Subscription: Identifiable {
    let id = UUID()
    let name: String
    let icon: String
    let color: Color
    let price: Double
    let billingCycle: BillingCycle
    let nextBillingDate: Date
    let category: SubscriptionCategory
}

enum BillingCycle: String {
    case monthly = "Monthly"
    case yearly = "Yearly"
    case weekly = "Weekly"
}

enum SubscriptionCategory: String, CaseIterable, Identifiable {
    case entertainment = "Entertainment"
    case productivity = "Productivity"
    case health = "Health"
    case storage = "Storage"
    case other = "Other"
    
    var id: String { rawValue }
}

Similar Blogs

View All Articles
How to Translate Xcode String Catalogs with AI

How to Translate Xcode String Catalogs with AI

Learn how to efficiently translate Xcode string catalogs using AI fast, streamlining localization for your iOS and SwiftUI applications.

by dockui
May 4
How to optimize your SwiftUI app in 2026

How to optimize your SwiftUI app in 2026

Discover top strategies to optimize your SwiftUI app in 2026, enhancing performance, responsiveness, and maintainability with modern concurrency.

by dockui
Apr 29
SwiftUI: iOS Confirmation Alert (Confirm + Cancel)

SwiftUI: iOS Confirmation Alert (Confirm + Cancel)

SwiftUI iOS confirmation alert with Confirm and Cancel buttons. Beginners guide to building safe actions, destructive deletes, and commit dialogs.

by dockui
Nov 11
SwiftUI: IOS Haptic Feedback Guide 2026

SwiftUI: IOS Haptic Feedback Guide 2026

Add click to vibrate haptic feedback in SwiftUI. Full guide to UIImpactFeedbackgenerator, success, error, selection, and tap vibration patterns with code.

by dockui
Nov 11

Code copied to clipboard!