remove Expo project and all related files

Remove the entire Expo/React Native application: routes (app/), source
code (src/), assets, iOS native build, config plugins, StoreKit config,
npm dependencies, TypeScript/ESLint/Vitest configs, and Expo-specific
documentation. The repository now contains only: admin-web, supabase,
youtube-worker, tabatago-swift, docs, scripts, and CI/tooling configs.
This commit is contained in:
Millian Lamiaux
2026-04-21 21:55:00 +02:00
parent 8c90b73d90
commit 89cca25e22
285 changed files with 11212 additions and 44392 deletions

View File

@@ -0,0 +1,29 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleDisplayName</key>
<string>TabataGoWidget</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>XPC!</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>NSExtension</key>
<dict>
<key>NSExtensionPointIdentifier</key>
<string>com.apple.widgetkit-extension</string>
</dict>
</dict>
</plist>

View File

@@ -0,0 +1,165 @@
import WidgetKit
import SwiftUI
// Timeline entry
struct TabataEntry: TimelineEntry {
let date: Date
let streak: Int
let lastWorkoutLabel: String // e.g. "Yesterday" or "2 days ago"
}
// Provider
struct TabataProvider: TimelineProvider {
private let sharedDefaults = UserDefaults(suiteName: "group.com.tabatago.app")
func placeholder(in context: Context) -> TabataEntry {
TabataEntry(date: Date(), streak: 7, lastWorkoutLabel: "Today")
}
func getSnapshot(in context: Context, completion: @escaping (TabataEntry) -> Void) {
completion(makeEntry())
}
func getTimeline(in context: Context, completion: @escaping (Timeline<TabataEntry>) -> Void) {
let entry = makeEntry()
// Refresh at midnight so the streak date label stays accurate
let midnight = Calendar.current.startOfDay(for: Date().addingTimeInterval(86_400))
completion(Timeline(entries: [entry], policy: .after(midnight)))
}
private func makeEntry() -> TabataEntry {
let streak = sharedDefaults?.integer(forKey: "streak") ?? 0
let lastDate = sharedDefaults?.object(forKey: "lastWorkoutDate") as? Date
let label = relativeLabel(for: lastDate)
return TabataEntry(date: Date(), streak: streak, lastWorkoutLabel: label)
}
private func relativeLabel(for date: Date?) -> String {
guard let date else { return "Not started" }
let days = Calendar.current.dateComponents([.day],
from: Calendar.current.startOfDay(for: date),
to: Calendar.current.startOfDay(for: Date())).day ?? 0
switch days {
case 0: return "Today"
case 1: return "Yesterday"
default: return "\(days) days ago"
}
}
}
// Views
/// `.accessoryCircular` streak count inside an orange ring
struct CircularComplicationView: View {
let entry: TabataEntry
var body: some View {
ZStack {
AccessoryWidgetBackground()
VStack(spacing: 0) {
Image(systemName: "bolt.fill")
.font(.system(size: 9, weight: .bold))
.foregroundStyle(.orange)
Text("\(entry.streak)")
.font(.system(size: 18, weight: .black, design: .rounded))
.minimumScaleFactor(0.5)
}
}
.widgetAccentable()
}
}
/// `.accessoryRectangular` streak + last workout date
struct RectangularComplicationView: View {
let entry: TabataEntry
var body: some View {
VStack(alignment: .leading, spacing: 2) {
HStack(spacing: 4) {
Image(systemName: "bolt.fill")
.foregroundStyle(.orange)
.font(.system(size: 10, weight: .bold))
Text("\(entry.streak) day streak")
.font(.system(size: 12, weight: .bold, design: .rounded))
}
Text(entry.lastWorkoutLabel)
.font(.system(size: 11))
.foregroundStyle(.secondary)
Text("Open TabataGo →")
.font(.system(size: 10, weight: .medium))
.foregroundStyle(.orange)
}
.frame(maxWidth: .infinity, alignment: .leading)
.widgetAccentable()
}
}
/// `.accessoryCorner` tiny bolt + streak digit in the corner
struct CornerComplicationView: View {
let entry: TabataEntry
var body: some View {
ZStack {
AccessoryWidgetBackground()
Image(systemName: "bolt.fill")
.font(.system(size: 14, weight: .bold))
.foregroundStyle(.orange)
}
.widgetLabel("\(entry.streak) day streak")
}
}
// Widget definition
struct TabataGoComplication: Widget {
static let kind = "TabataGoComplication"
var body: some WidgetConfiguration {
StaticConfiguration(kind: Self.kind, provider: TabataProvider()) { entry in
TabataComplicationEntryView(entry: entry)
.containerBackground(.black, for: .widget)
}
.configurationDisplayName("TabataGo")
.description("Your current workout streak.")
.supportedFamilies([
.accessoryCircular,
.accessoryRectangular,
.accessoryCorner
])
}
}
struct TabataComplicationEntryView: View {
@Environment(\.widgetFamily) var family
let entry: TabataEntry
var body: some View {
switch family {
case .accessoryCircular:
CircularComplicationView(entry: entry)
case .accessoryRectangular:
RectangularComplicationView(entry: entry)
case .accessoryCorner:
CornerComplicationView(entry: entry)
default:
CircularComplicationView(entry: entry)
}
}
}
// Previews
#Preview("Circular", as: .accessoryCircular) {
TabataGoComplication()
} timeline: {
TabataEntry(date: .now, streak: 7, lastWorkoutLabel: "Today")
}
#Preview("Rectangular", as: .accessoryRectangular) {
TabataGoComplication()
} timeline: {
TabataEntry(date: .now, streak: 7, lastWorkoutLabel: "Today")
}