Skip to content

Latest commit

 

History

1 Commit

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

🎬 MovieTracker

A production-quality iOS app for discovering movies and tracking your watchlist, favorites, watched history, personal ratings, and reviews — with an offline-first statistics dashboard. Built with SwiftUI, SwiftData, and modern Swift concurrency.

Portfolio project demonstrating clean MVVM architecture, dependency injection, and a fully testable, layered codebase.

✨ Features

  • 🔎 Search TMDB with debounced input and stale-request cancellation
  • 🏠 Home grid of popular movies with pull-to-refresh
  • 🎞 Rich detail screen with progressive loading (instant base + async enrichment)
  • 🔖 Watchlist, ❤️ Favorites, ✅ Watched history (one movie, many states)
  • ⭐️ Personal ratings (half-star, drag-to-rate) and ✍️ reviews
  • 📊 Statistics dashboard — counts, average rating, rating histogram, top genres, and watched-by-decade charts (Swift Charts)
  • 🔀 Sort & filter saved lists (by rating, title, date, TMDB score)
  • 🌓 Dark Mode, ♿️ Dynamic Type & Reduce Motion support
  • 📴 Offline support — saved data and stats work with no network
  • 🎇 Zoom transitions, skeleton loaders, and haptics

📸 Screenshots

Home Detail Statistics
tbd tbd tbd

🛠 Tech Stack

  • Swift 6 (strict concurrency)
  • SwiftUI (iOS 18+)
  • SwiftData for local persistence
  • Swift Charts for the dashboard
  • URLSession + async/await networking
  • Swift Testing for unit tests
  • MVVM + repository/service layers + dependency injection

🏗 Architecture

Two decoupled stacks meet at the ViewModel:

  • Networking — a generic APIClient executes declarative Endpoints and decodes into immutable Sendable DTOs (Movie, MovieDetail).
  • Persistence — a SavedMovie @Model stores a snapshot of each saved movie (offline-capable); @Query drives reactive reads, a SavedMovieRepository owns all writes.

ViewModels are @Observable, @MainActor, and expose a finite-state enum (idle / loading / loaded / empty / failed) that the view renders with a single switch. Services and clients are protocols, so tests inject mocks.

See ARCHITECTURE.md for the full diagram and rationale.

📁 Project Structure

MovieTracker/
├── App/                      # @main entry, DI wiring, .modelContainer
├── Core/
│   ├── Navigation/           # AppTab, AppRouter, RootTabView, movieDestination
│   ├── Networking/           # APIClient, Endpoint, APIError, Models (DTOs)
│   ├── Services/             # MovieService (+ Mock)
│   ├── Persistence/          # SavedMovie, SavedMovieRepository, filtering
│   ├── Components/           # Reusable views (posters, rows, stars, skeletons)
│   ├── Theme/                # AppTheme
│   └── Utilities/            # GenreCatalog
├── Features/                 # Home, Search, MovieDetail, Watchlist,
│                             # Statistics, Profile, Shared (each: Views/ViewModels)
├── Resources/                # Assets, Secrets.xcconfig (git-ignored)
└── MovieTrackerTests/        # ViewModel, repository, query & calculator tests

🚀 Getting Started

⚠️ This repository contains the Swift source files and folder structure. It does not include an .xcodeproj (Xcode generates that). Follow the steps below on a Mac to assemble the project.

Requirements

  • macOS with Xcode 16+ (iOS 18 SDK)
  • A free TMDB account

1. Create the Xcode project

  1. Xcode ▸ New Project ▸ iOS App. Name it MovieTracker, Interface: SwiftUI, Storage: SwiftData, Language: Swift.
  2. Delete the generated ContentView.swift (and the default @main App file — we provide our own in App/MovieTrackerApp.swift).
  3. Drag the App, Core, Features, and Resources folders into the project navigator ("Copy items if needed", "Create groups").
  4. Add the MovieTrackerTests files to the test target (create a Unit Testing Bundle target if the project doesn't have one).

2. Get a TMDB token

TMDB ▸ Settings ▸ API ▸ API Read Access Token (v4 auth).

3. Add your secret (kept out of source control)

Copy Resources/Secrets.xcconfig.exampleResources/Secrets.xcconfig and paste your token:

TMDB_ACCESS_TOKEN = your_read_access_token_here

Then:

  • Project ▸ Info ▸ Configurations → set Secrets.xcconfig for Debug & Release
  • Info.plist → add key TMDB_ACCESS_TOKEN with value $(TMDB_ACCESS_TOKEN)
  • Confirm Secrets.xcconfig is git-ignored (it is, in .gitignore)

4. Build & run

Select a simulator and press ⌘R.

5. Run tests

⌘U, or:

xcodebuild test -scheme MovieTracker -destination 'platform=iOS Simulator,name=iPhone 16'

🧪 Testing

  • ViewModel state machines (mock service + actor-based sequence mock)
  • Repository behavior against an in-memory SwiftData store
  • Composed query predicates against a real store
  • Pure statistics calculations

🗺 Roadmap

See ROADMAP.md — pagination, genre-filter relationship, versioned schema migrations, URLProtocol networking tests, widgets, notifications & deep linking.

🙏 Credits

This product uses the TMDB API but is not endorsed or certified by TMDB. Movie data and images © The Movie Database. (Attribution is shown in-app on the Profile screen; add the TMDB logo to Assets before shipping.)

📄 License

MIT — see LICENSE (add your preferred license file).

About

Offline-first iOS app for tracking movies — watchlist, ratings, reviews, and a stats dashboard. SwiftUI + SwiftData, MVVM, fully tested.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages