diff --git a/medmap/Assets.xcassets/corporateLogos.imageset/Contents.json b/medmap/Assets.xcassets/corporateLogos.imageset/Contents.json
new file mode 100644
index 0000000..cdef1a0
--- /dev/null
+++ b/medmap/Assets.xcassets/corporateLogos.imageset/Contents.json
@@ -0,0 +1,12 @@
+{
+ "images" : [
+ {
+ "filename" : "corporateLogos.svg",
+ "idiom" : "universal"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
diff --git a/medmap/Assets.xcassets/corporateLogos.imageset/corporateLogos.svg b/medmap/Assets.xcassets/corporateLogos.imageset/corporateLogos.svg
new file mode 100644
index 0000000..06894d1
--- /dev/null
+++ b/medmap/Assets.xcassets/corporateLogos.imageset/corporateLogos.svg
@@ -0,0 +1,9 @@
+
diff --git a/medmap/Assets.xcassets/splashImage.imageset/Contents.json b/medmap/Assets.xcassets/splashImage.imageset/Contents.json
new file mode 100644
index 0000000..f162b5c
--- /dev/null
+++ b/medmap/Assets.xcassets/splashImage.imageset/Contents.json
@@ -0,0 +1,12 @@
+{
+ "images" : [
+ {
+ "filename" : "splashImage.png",
+ "idiom" : "universal"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
diff --git a/medmap/Assets.xcassets/splashImage.imageset/splashImage.png b/medmap/Assets.xcassets/splashImage.imageset/splashImage.png
new file mode 100644
index 0000000..04290cd
Binary files /dev/null and b/medmap/Assets.xcassets/splashImage.imageset/splashImage.png differ
diff --git a/medmap/Assets.xcassets/splashLogo.imageset/Contents.json b/medmap/Assets.xcassets/splashLogo.imageset/Contents.json
new file mode 100644
index 0000000..7d6821e
--- /dev/null
+++ b/medmap/Assets.xcassets/splashLogo.imageset/Contents.json
@@ -0,0 +1,12 @@
+{
+ "images" : [
+ {
+ "filename" : "splashLogo.svg",
+ "idiom" : "universal"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
diff --git a/medmap/Assets.xcassets/splashLogo.imageset/splashLogo.svg b/medmap/Assets.xcassets/splashLogo.imageset/splashLogo.svg
new file mode 100644
index 0000000..c72453a
--- /dev/null
+++ b/medmap/Assets.xcassets/splashLogo.imageset/splashLogo.svg
@@ -0,0 +1,11 @@
+
diff --git a/medmap/Extensions/Color+Extensions.swift b/medmap/Extensions/Color+Extensions.swift
new file mode 100644
index 0000000..ea62737
--- /dev/null
+++ b/medmap/Extensions/Color+Extensions.swift
@@ -0,0 +1,63 @@
+//
+// Color+Extensions.swift
+// medmap
+//
+// Created by RSA on 28/08/2026.
+//
+
+import SwiftUI
+
+// MARK: - Color + Hex Initializer
+extension Color {
+ init(hex: String) {
+ let hexString = hex.trimmingCharacters(in: .whitespacesAndNewlines)
+ .replacingOccurrences(of: "#", with: "")
+
+ var rgbValue: UInt64 = 0
+ Scanner(string: hexString).scanHexInt64(&rgbValue)
+
+ let length = hexString.count
+
+ let r, g, b, a: Double
+
+ switch length {
+ case 6: // RRGGBB
+ r = Double((rgbValue & 0xFF0000) >> 16) / 255.0
+ g = Double((rgbValue & 0x00FF00) >> 8) / 255.0
+ b = Double(rgbValue & 0x0000FF) / 255.0
+ a = 1.0
+ case 8: // RRGGBBAA
+ r = Double((rgbValue & 0xFF000000) >> 24) / 255.0
+ g = Double((rgbValue & 0x00FF0000) >> 16) / 255.0
+ b = Double((rgbValue & 0x0000FF00) >> 8) / 255.0
+ a = Double(rgbValue & 0x000000FF) / 255.0
+ default:
+ r = 0
+ g = 0
+ b = 0
+ a = 1.0
+ }
+
+ self.init(.sRGB, red: r, green: g, blue: b, opacity: a)
+ }
+}
+
+// MARK: - Custom App Colors
+extension Color {
+ static let appBackground = Color(hex: "#4078BC")
+ static let appBackgroundDark = Color(hex: "##4078BC")
+
+
+
+
+
+
+ static let appSecondary = Color(hex: "#F7F7F8")
+ static let appAccent = Color(hex: "#4A2EC2")
+ static let appTextPrimary = Color(hex: "#333333")
+ static let appBorder = Color(hex: "#E5E5E5")
+
+ // Add more as needed, e.g.:
+ // static let appError = Color(hex: "#FF3B30")
+ // static let appSuccess = Color(hex: "#34C759")
+}
diff --git a/medmap/Extensions/Data+Extensions.swift b/medmap/Extensions/Data+Extensions.swift
new file mode 100644
index 0000000..beda99e
--- /dev/null
+++ b/medmap/Extensions/Data+Extensions.swift
@@ -0,0 +1,86 @@
+//
+// Data+Extensions.swift
+// FluxRead
+//
+// Created by RSA on 15/02/2026.
+//
+
+import Foundation
+
+extension Data {
+
+ init(copyingBufferOf array: [T]) {
+ self = array.withUnsafeBufferPointer(Data.init)
+ }
+
+ func toArray(type: T.Type) -> [T] where T: ExpressibleByIntegerLiteral {
+ var array = [T](repeating: 0, count: self.count / MemoryLayout.stride)
+ _ = array.withUnsafeMutableBytes { copyBytes(to: $0) }
+ return array
+ }
+
+ /// Saves the Data object to a file at the specified URL
+ /// - Parameters:
+ /// - url: The destination file URL
+ /// - options: Writing options (default: .atomic)
+ /// - Throws: Error if writing fails
+ func saveToFile(at url: URL, options: WritingOptions = .atomic) throws {
+ try self.write(to: url, options: options)
+
+ }
+
+ /// Saves the Data object to a file with a specified filename in a directory
+ /// - Parameters:
+ /// - filename: The name of the file to create
+ /// - directory: The directory URL where the file should be saved
+ /// - options: Writing options (default: .atomic)
+ /// - Returns: The URL of the saved file
+ /// - Throws: Error if writing fails
+ @discardableResult
+ func saveToFile(filename: String, in directory: URL, options: WritingOptions = .atomic) throws -> URL {
+ let fileURL = directory.appendingPathComponent(filename)
+ try self.write(to: fileURL, options: options)
+
+ return fileURL
+ }
+
+ /// Saves the Data object to the app's Documents directory
+ /// - Parameters:
+ /// - filename: The name of the file to create
+ /// - options: Writing options (default: .atomic)
+ /// - Returns: The URL of the saved file
+ /// - Throws: Error if writing fails or Documents directory not accessible
+ @discardableResult
+ func saveToDocuments(filename: String, options: WritingOptions = .atomic) throws -> URL {
+ guard let documentsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else {
+ throw NSError(domain: "DataExtension", code: -1, userInfo: [NSLocalizedDescriptionKey: "Could not access Documents directory"])
+ }
+ return try saveToFile(filename: filename, in: documentsDirectory, options: options)
+ }
+
+ /// Saves the Data object to the app's temporary directory
+ /// - Parameters:
+ /// - filename: The name of the file to create
+ /// - options: Writing options (default: .atomic)
+ /// - Returns: The URL of the saved file
+ /// - Throws: Error if writing fails
+ @discardableResult
+ func saveToTemporary(filename: String, options: WritingOptions = .atomic) throws -> URL {
+ let temporaryDirectory = FileManager.default.temporaryDirectory
+ return try saveToFile(filename: filename, in: temporaryDirectory, options: options)
+ }
+
+ /// Saves the Data object to the app's Caches directory
+ /// - Parameters:
+ /// - filename: The name of the file to create
+ /// - options: Writing options (default: .atomic)
+ /// - Returns: The URL of the saved file
+ /// - Throws: Error if writing fails or Caches directory not accessible
+ @discardableResult
+ func saveToCaches(filename: String, options: WritingOptions = .atomic) throws -> URL {
+ guard let cachesDirectory = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask).first else {
+ throw NSError(domain: "DataExtension", code: -1, userInfo: [NSLocalizedDescriptionKey: "Could not access Caches directory"])
+ }
+ return try saveToFile(filename: filename, in: cachesDirectory, options: options)
+ }
+}
diff --git a/medmap/Extensions/Date+extensions.swift b/medmap/Extensions/Date+extensions.swift
new file mode 100644
index 0000000..fa32128
--- /dev/null
+++ b/medmap/Extensions/Date+extensions.swift
@@ -0,0 +1,22 @@
+//
+// Date+extensions.swift
+// FluxRead
+//
+// Created by RSA on 30/11/2025.
+//
+
+import Foundation
+
+extension Date {
+ static func firstDayOfMonth(year: Int, month: Int, calendar: Calendar = .current) -> Date? {
+ var components = DateComponents()
+ components.year = year
+ components.month = month
+ components.day = 1
+ components.hour = 0
+ components.minute = 0
+ components.second = 0
+
+ return calendar.date(from: components)
+ }
+}
diff --git a/medmap/Extensions/Font+CustomFonts.swift b/medmap/Extensions/Font+CustomFonts.swift
new file mode 100755
index 0000000..71448db
--- /dev/null
+++ b/medmap/Extensions/Font+CustomFonts.swift
@@ -0,0 +1,49 @@
+// Copyright © 2024 VOID Software SA. All rights reserved.
+
+import SwiftUI
+
+extension Font {
+
+ static let jakartaRegularName = "Plus Jakarta Sans Regular"
+ static let jakartaBold = "Plus Jakarta Sans Bold"
+ static let jakartaLight = "Plus Jakarta Sans Light"
+ static let jakartaMedium = "Plus Jakarta Sans Medium"
+
+ static let interRegular = "Inter Regular"
+ static let interBold = "Inter Bold"
+
+ static let redHatSemibold = "Red Hat Display SemiBold"
+ static let redHat = "Red Hat Display Regular"
+
+ static let jakartaRegular24 = Font.custom(jakartaRegularName, size: 24)
+ static let jakartaRegular64 = Font.custom(jakartaRegularName, size: 64)
+ static let jakartaRegular60 = Font.custom(jakartaRegularName, size: 60)
+ static let jakartaRegular56 = Font.custom(jakartaRegularName, size: 56)
+ static let jakartaRegular16 = Font.custom(jakartaRegularName, size: 16)
+ static let jakartaRegular14 = Font.custom(jakartaRegularName, size: 14)
+ static let jakartaRegular12 = Font.custom(jakartaRegularName, size: 12)
+ static let jakartaRegular6 = Font.custom(jakartaRegularName, size: 6)
+ static let jakartaRegular18 = Font.custom(jakartaRegularName, size: 18)
+ static let jakartaRegular40 = Font.custom(jakartaRegularName, size: 40)
+ static let jakartaBold12 = Font.custom(jakartaBold, size: 12)
+ static let jakartaBold14 = Font.custom(jakartaBold, size: 14)
+ static let jakartaBold16 = Font.custom(jakartaBold, size: 16)
+ static let jakartaBold18 = Font.custom(jakartaBold, size: 18)
+ static let jakartaBold22 = Font.custom(jakartaBold, size: 22)
+ static let jakartaBold24 = Font.custom(jakartaBold, size: 24)
+ static let jakartaBold64 = Font.custom(jakartaBold, size: 64)
+ static let jakartaBold40 = Font.custom(jakartaBold, size: 40)
+ static let interRegular14 = Font.custom(interRegular, size: 14)
+ static let interRegular16 = Font.custom(interRegular, size: 16)
+ static let interRegular12 = Font.custom(interRegular, size: 12)
+ static let interBold14 = Font.custom(interBold, size: 14)
+ static let redHatSemibold24 = Font.custom(redHatSemibold, size: 24)
+ static let redHatSemibold18 = Font.custom(redHatSemibold, size: 18)
+ static let redHat24 = Font.custom(redHat, size: 24)
+ static let redHat14 = Font.custom(redHat, size: 14)
+ static let redHat12 = Font.custom(redHat, size: 12)
+ static let jakartaMedium14 = Font.custom(jakartaMedium, size: 14)
+ static let jakartaMedium18 = Font.custom(jakartaMedium, size: 18)
+ static let jakartaMedium40 = Font.custom(jakartaMedium, size: 40)
+
+}
diff --git a/medmap/Network/FluxReaderAPI.swift b/medmap/Network/MedMapAPI.swift
similarity index 100%
rename from medmap/Network/FluxReaderAPI.swift
rename to medmap/Network/MedMapAPI.swift
diff --git a/medmap/ViewModels/DashboardViewModel.swift b/medmap/ViewModels/DashboardViewModel.swift
new file mode 100644
index 0000000..2044b25
--- /dev/null
+++ b/medmap/ViewModels/DashboardViewModel.swift
@@ -0,0 +1,7 @@
+//
+// DashboardViewModel.swift
+// medmap
+//
+// Created by RSA on 28/08/2026.
+//
+
diff --git a/medmap/ViewModels/ViewModel.swift b/medmap/ViewModels/ViewModel.swift
index 7fc86c9..2a4006b 100644
--- a/medmap/ViewModels/ViewModel.swift
+++ b/medmap/ViewModels/ViewModel.swift
@@ -14,7 +14,7 @@ import UserNotifications
class ViewModel: ObservableObject {
-
+ var appStateManager: AppStateManager = DIContainer.shared.resolve()
@Published var isLoading: Bool = false
diff --git a/medmap/Views/DashboardView.swift b/medmap/Views/DashboardView.swift
new file mode 100644
index 0000000..005b429
--- /dev/null
+++ b/medmap/Views/DashboardView.swift
@@ -0,0 +1,7 @@
+//
+// DashboardView.swift
+// medmap
+//
+// Created by RSA on 28/08/2026.
+//
+
diff --git a/medmap/Views/SplashScreenView.swift b/medmap/Views/SplashScreenView.swift
index d7ba5bf..cbce4ed 100644
--- a/medmap/Views/SplashScreenView.swift
+++ b/medmap/Views/SplashScreenView.swift
@@ -12,158 +12,39 @@ struct SplashScreenView: View {
@ObservedObject var viewModel: SplashScreenViewModel
- @State private var glowPulse = false
- @State private var logoScale = 0.85
- @State private var logoOpacity = 0.0
- @State private var ringRotate = 0.0
- @State private var ringOpacity = 0.0
-
var body: some View {
ZStack {
-
- // ── Deep black base ──────────────────────────────────────────
- Color.black.ignoresSafeArea()
-
- // ── Bottom-half warm particle field ──────────────────────────
- SplashParticleField()
- .ignoresSafeArea()
- .opacity(0.90)
-
- // ── Radial glow anchored to centre top ───────────────────────
+
+
+ Color.appBackground.ignoresSafeArea()
+
VStack(spacing: 0) {
- RadialGradient(
- colors: [
- Color.orange.opacity(glowPulse ? 0.22 : 0.10),
- Color.yellow.opacity(glowPulse ? 0.10 : 0.04),
- Color.clear
- ],
- center: .center,
- startRadius: 0,
- endRadius: 340
- )
- .frame(width: 680, height: 680)
- .blur(radius: 48)
- .scaleEffect(glowPulse ? 1.12 : 1.0)
- .animation(
- .easeInOut(duration: 3.8).repeatForever(autoreverses: true),
- value: glowPulse
- )
+
+ HStack {
+ Image("splashLogo")
+ .frame(width: 150, height: 180)
+ .padding(.leading, 70)
+ .padding(.top, 90)
+ Spacer()
+ }
+
Spacer()
+
+ Image("splashImage")
+ .padding(.top, 20)
+ Spacer()
+
+ Image("corporateLogos")
+ .padding(.bottom, 35)
+
}
.ignoresSafeArea()
-
- // ── Orbiting arc ring around logo ────────────────────────────
- ZStack {
- // slow outer arc
- Circle()
- .trim(from: 0.0, to: 0.28)
- .stroke(
- LinearGradient(
- colors: [Color.orange.opacity(0.45), Color.clear],
- startPoint: .leading, endPoint: .trailing
- ),
- style: StrokeStyle(lineWidth: 1.0, lineCap: .round)
- )
- .frame(width: 210, height: 210)
- .rotationEffect(.degrees(ringRotate))
- .opacity(ringOpacity)
-
- // faster inner arc
- Circle()
- .trim(from: 0.55, to: 0.72)
- .stroke(
- LinearGradient(
- colors: [Color.yellow.opacity(0.30), Color.clear],
- startPoint: .leading, endPoint: .trailing
- ),
- style: StrokeStyle(lineWidth: 0.6, lineCap: .round)
- )
- .frame(width: 175, height: 175)
- .rotationEffect(.degrees(-ringRotate * 1.4))
- .opacity(ringOpacity)
- }
-
- // ── Logo centred ─────────────────────────────────────────────
- VStack(spacing: 0) {
- Spacer()
-
-
- Spacer()
- }
+
}
.ignoresSafeArea()
.onAppear {
- // Logo entrance
- withAnimation(.spring(response: 0.75, dampingFraction: 0.72).delay(0.1)) {
- logoScale = 1.0
- logoOpacity = 1.0
- }
- // Glow breath
- glowPulse = true
-
- // Ring fade-in then continuous rotation
- withAnimation(.easeIn(duration: 0.8).delay(0.4)) {
- ringOpacity = 1.0
- }
- withAnimation(.linear(duration: 12).repeatForever(autoreverses: false).delay(0.4)) {
- ringRotate = 360
- }
-
+
}
}
}
-
-// MARK: - Splash Particle Field
-// Warm, slow-drifting particles — denser than the reader version, tinted orange/gold
-
-struct SplashParticleField: View {
-
- @State private var tick: Double = 0
- private let timer = Timer.publish(every: 1.0 / 60.0, on: .main, in: .common).autoconnect()
-
- private struct Particle {
- let x, y, speed, phase: Double
- let radius: CGFloat
- let opacity: Double
- let warm: Bool // warm (orange/gold) vs cool (white)
- }
-
- private let particles: [Particle] = (0..<120).map { i in
- let seed = Double(i) * 1.618033
- return Particle(
- x: (seed * 0.7369).truncatingRemainder(dividingBy: 1.0),
- y: (seed * 1.2345).truncatingRemainder(dividingBy: 1.0),
- speed: Double.random(in: 8...28),
- phase: Double.random(in: 0...Double.pi * 2),
- radius: CGFloat(Double.random(in: 0.7...2.8)),
- opacity: Double.random(in: 0.04...0.28),
- warm: i % 3 != 0
- )
- }
-
- var body: some View {
- Canvas { ctx, size in
- let t = tick
- for p in particles {
- let x = (p.x + t / p.speed).truncatingRemainder(dividingBy: 1.0) * size.width
- let drift = sin(t / (p.speed * 0.6) + p.phase) * 22
- let y = p.y * size.height + CGFloat(drift)
- let pulse = 0.65 + 0.35 * sin(t / 2.5 + p.phase)
- let alpha = p.opacity * pulse
- let color: Color = p.warm
- ? Color(red: 1.0, green: 0.62, blue: 0.18).opacity(alpha)
- : Color.white.opacity(alpha * 0.55)
-
- ctx.fill(
- Path(ellipseIn: CGRect(
- x: x - p.radius, y: y - p.radius,
- width: p.radius * 2, height: p.radius * 2
- )),
- with: .color(color)
- )
- }
- }
- .onReceive(timer) { _ in tick += 1.0 / 60.0 }
- }
-}