MacTorn_mirror/wiki/Development.md
Paweł Orzech 715f0877ff
docs: Add comprehensive GitHub wiki documentation
Create wiki/ directory with 11 markdown pages covering:
- Home, Installation, Getting Started guides
- Features documentation for all tabs
- API Setup with permissions and security
- Configuration options and settings
- Troubleshooting and FAQ
- Development guide with architecture overview
- Changelog with version history
- Sidebar navigation
2026-01-20 13:24:55 +00:00

250 lines
5.7 KiB
Markdown

# Development
This guide covers building MacTorn from source and contributing to the project.
## Prerequisites
- **macOS 13.0+** (Ventura or later)
- **Xcode 15+** (with Swift 5)
- **Git**
## Getting the Source
```bash
git clone https://github.com/pawelorzech/MacTorn.git
cd MacTorn/MacTorn
```
## Building
### Using Xcode
```bash
open MacTorn.xcodeproj
```
Press `Cmd + R` to build and run.
### Using Make
MacTorn includes a Makefile for common operations:
```bash
# Build Debug version
make build
# Build Release (Universal Binary)
make release
# Run unit tests
make test
# Run UI tests
make test-ui
# Run all tests
make test-all
# Clean build artifacts
make clean
```
All make commands use `xcodebuild` with code signing disabled (`CODE_SIGN_IDENTITY="-"`).
## Project Structure
```
MacTorn/
├── MacTorn/ # Main app target
│ ├── MacTornApp.swift # App entry point
│ ├── ViewModels/
│ │ └── AppState.swift # Central state manager
│ ├── Models/
│ │ └── TornModels.swift # Data models & API config
│ ├── Views/
│ │ ├── ContentView.swift # Main tab container
│ │ ├── StatusView.swift # Status tab
│ │ ├── TravelView.swift # Travel tab
│ │ ├── MoneyView.swift # Money tab
│ │ ├── AttacksView.swift # Attacks tab
│ │ ├── FactionView.swift # Faction tab
│ │ ├── WatchlistView.swift # Watchlist tab
│ │ ├── SettingsView.swift # Settings tab
│ │ └── Components/ # Reusable components
│ ├── Utilities/
│ │ ├── NotificationManager.swift
│ │ ├── LaunchAtLoginManager.swift
│ │ ├── ShortcutsManager.swift
│ │ └── SoundManager.swift
│ ├── Networking/
│ │ └── NetworkSession.swift # Network abstraction
│ └── Helpers/
│ └── TransparencyEnvironment.swift
├── MacTornTests/ # Unit tests
│ ├── Models/
│ ├── ViewModels/
│ ├── Mocks/
│ │ └── MockNetworkSession.swift
│ └── Fixtures/
│ └── TornAPIFixtures.swift
└── MacTornUITests/ # UI tests
```
## Architecture Overview
### App Structure
MacTorn uses SwiftUI with the `@main` attribute and `MenuBarExtra` scene for the menu bar interface.
### State Management
**AppState** (`AppState.swift`) is the central state manager:
- Uses `@MainActor` for thread safety
- Handles API polling via Combine's `Timer.publish`
- Manages data parsing, notifications, and watchlist
- Uses dependency injection via `NetworkSession` protocol
### Networking
The `NetworkSession` protocol abstracts network calls:
```swift
protocol NetworkSession {
func data(from url: URL) async throws -> (Data, URLResponse)
}
```
This allows injecting `URLSession` for production and `MockNetworkSession` for testing.
### Data Models
All models are in `TornModels.swift`:
- `TornResponse` - Main API response
- `Bar` - Energy/Nerve/Happy/Life bar
- `Travel` - Travel status
- `Status` - Player status
- `Chain` - Faction chain
- `WatchlistItem` - Watched item with price
`TornAPI` enum contains endpoint configurations.
## Testing
### Writing Unit Tests
Tests use `MockNetworkSession` for API testing:
```swift
import XCTest
@testable import MacTorn
final class MyTests: XCTestCase {
func testExample() async throws {
let mockSession = MockNetworkSession()
let appState = AppState(session: mockSession)
try mockSession.setSuccessResponse(json: TornAPIFixtures.validFullResponse)
await appState.refreshNow()
XCTAssertNotNil(appState.data)
}
}
```
### Test Fixtures
`TornAPIFixtures.swift` contains sample JSON responses for testing.
### Running Tests
```bash
# Unit tests only
make test
# UI tests only
make test-ui
# All tests
make test-all
```
## Key Patterns
### API Polling
`AppState.startPolling()` uses Combine's Timer:
```swift
func startPolling() {
timerCancellable?.cancel()
timerCancellable = Timer.publish(every: TimeInterval(refreshInterval), on: .main, in: .common)
.autoconnect()
.sink { [weak self] _ in
Task { @MainActor in
await self?.fetchData()
}
}
}
```
### Live Countdown
Travel timer updates every second independently of API polling:
```swift
travelTimerCancellable = Timer.publish(every: 1, on: .main, in: .common)
.autoconnect()
.sink { [weak self] _ in
self?.updateTravelCountdown()
}
```
### Accessibility
`TransparencyEnvironment.swift` provides a custom environment key:
```swift
@Environment(\.reduceTransparency) private var reduceTransparency
```
Views use this to adjust backgrounds based on accessibility settings.
### State Persistence
- `@AppStorage` for simple values (API key, refresh interval, appearance)
- `UserDefaults` for complex data (notification rules, watchlist)
## Contributing
### Workflow
1. Fork the repository
2. Create a feature branch (`git checkout -b feature/my-feature`)
3. Make changes
4. Run tests (`make test-all`)
5. Commit with descriptive message
6. Push to your fork
7. Create a Pull Request
### Code Style
- Use Swift standard naming conventions
- Keep views focused and extract components
- Add tests for new functionality
- Update documentation as needed
### Pull Request Guidelines
- Describe what changes were made and why
- Reference any related issues
- Ensure all tests pass
- Keep changes focused (one feature/fix per PR)
## License
MacTorn is released under the MIT License. See [LICENSE](https://github.com/pawelorzech/MacTorn/blob/main/LICENSE) for details.
---
**See Also:** [[Changelog]] for version history