A simple iOS tip calculator and bill splitter, built with SwiftUI and MVVM.
- Enter a bill amount
- Choose a tip percentage - preset buttons (10% / 15% / 20%) or a custom value
- Set how many people are splitting the bill
- See the tip amount, total, and per-person amount update live
- Ask AI for advice: Describe your dining experience and let Google's Gemini AI suggest an appropriate tip percentage and explain why.
To keep the app secure, the Gemini API key is completely excluded from source control. To run the app locally:
- Clone the repository.
- Get a free API key from Google AI Studio.
- In Xcode, go to
File > New > File...and create a Configuration Settings File named exactlyConfig.xcconfigin the root folder. - Add your key to the file like this:
GEMINI_API_KEY = your_api_key_here - Build and run. The app will securely inject the key at runtime via
Info.plist.
This is a day-to-day project, focused on shipping small, complete features rather than pure algorithm drilling, to better enhance familiarity with the iOS developing environment.
MVVM, deliberately kept simple with a dedicated service layer for networking:
SplitBill/
├── SplitBillApp.swift
├── Views/
│ ├── ContentView.swift
│ └── TipSuggestionSheet.swift
├── ViewModels/
│ └── TipCalculatorViewModel.swift # All state + derived calculations
├── Services/
│ └── TipSuggestionService.swift # Network calls to Gemini API
- The View never calculates anything. It only reads values from the ViewModel and renders them.
- Tip, total, and per-person amounts are computed properties, not stored values that get manually kept in sync. They're derived fresh from the current inputs every time, which avoids an entire class of "UI shows one thing, math uses another" bugs.
- Preset vs. custom tip selection uses a single source of truth. Rather than writing to one shared
tipPercentvariable from two different UI elements (which risks the two getting out of sync), the ViewModel tracksselectedPresetPercent(optional) andcustomTipTextseparately, and a computedtipPercentproperty decides which one to trust. Selecting a preset clears the custom text; typing a custom value clears the preset. - Divide-by-zero is guarded explicitly.
Doubledivision by zero doesn't crash in Swift — it silently producesinf/nan— so the per-person calculation falls back safely if the people count is zero, rather than letting a bad value quietly propagate into the UI. - API Keys are hidden from Git. The project uses an
.xcconfigfile injected intoInfo.plistto prevent leaking secrets into version control.
- Xcode 16+
- iOS 17+
Core functionality is complete. Open items:
- Rounding edge case (who absorbs the leftover cent when the total doesn't divide evenly)
- Unit tests on the ViewModel