Update: 2026-05-07 15:49:13
This commit is contained in:
@@ -21,7 +21,8 @@
|
|||||||
"guzzlehttp/guzzle": "^7.9",
|
"guzzlehttp/guzzle": "^7.9",
|
||||||
"respect/validation": "^2.3",
|
"respect/validation": "^2.3",
|
||||||
"league/flysystem": "^3.28",
|
"league/flysystem": "^3.28",
|
||||||
"symfony/mailer": "^7.1"
|
"symfony/mailer": "^7.1",
|
||||||
|
"phpoffice/phpspreadsheet": "^2.1"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"phpunit/phpunit": "^11.0",
|
"phpunit/phpunit": "^11.0",
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"colors" : [
|
||||||
|
{
|
||||||
|
"idiom" : "universal"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
{
|
||||||
|
"images" : [
|
||||||
|
{
|
||||||
|
"idiom" : "universal",
|
||||||
|
"platform" : "ios",
|
||||||
|
"size" : "1024x1024"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"appearances" : [
|
||||||
|
{
|
||||||
|
"appearance" : "luminosity",
|
||||||
|
"value" : "dark"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"idiom" : "universal",
|
||||||
|
"platform" : "ios",
|
||||||
|
"size" : "1024x1024"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"appearances" : [
|
||||||
|
{
|
||||||
|
"appearance" : "luminosity",
|
||||||
|
"value" : "tinted"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"idiom" : "universal",
|
||||||
|
"platform" : "ios",
|
||||||
|
"size" : "1024x1024"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"colors" : [
|
||||||
|
{
|
||||||
|
"idiom" : "universal"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
||||||
11
musadaq-app/ios/MusadaqLiveActivity/Info.plist
Normal file
11
musadaq-app/ios/MusadaqLiveActivity/Info.plist
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
<?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>NSExtension</key>
|
||||||
|
<dict>
|
||||||
|
<key>NSExtensionPointIdentifier</key>
|
||||||
|
<string>com.apple.widgetkit-extension</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
@@ -0,0 +1,84 @@
|
|||||||
|
//
|
||||||
|
// MusadaqLiveActivity.swift
|
||||||
|
// MusadaqLiveActivity
|
||||||
|
//
|
||||||
|
// Created by Hamza Aleghwairyeen on 07/05/2026.
|
||||||
|
//
|
||||||
|
|
||||||
|
import WidgetKit
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
struct Provider: TimelineProvider {
|
||||||
|
func placeholder(in context: Context) -> SimpleEntry {
|
||||||
|
SimpleEntry(date: Date(), emoji: "😀")
|
||||||
|
}
|
||||||
|
|
||||||
|
func getSnapshot(in context: Context, completion: @escaping (SimpleEntry) -> ()) {
|
||||||
|
let entry = SimpleEntry(date: Date(), emoji: "😀")
|
||||||
|
completion(entry)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getTimeline(in context: Context, completion: @escaping (Timeline<Entry>) -> ()) {
|
||||||
|
var entries: [SimpleEntry] = []
|
||||||
|
|
||||||
|
// Generate a timeline consisting of five entries an hour apart, starting from the current date.
|
||||||
|
let currentDate = Date()
|
||||||
|
for hourOffset in 0 ..< 5 {
|
||||||
|
let entryDate = Calendar.current.date(byAdding: .hour, value: hourOffset, to: currentDate)!
|
||||||
|
let entry = SimpleEntry(date: entryDate, emoji: "😀")
|
||||||
|
entries.append(entry)
|
||||||
|
}
|
||||||
|
|
||||||
|
let timeline = Timeline(entries: entries, policy: .atEnd)
|
||||||
|
completion(timeline)
|
||||||
|
}
|
||||||
|
|
||||||
|
// func relevances() async -> WidgetRelevances<Void> {
|
||||||
|
// // Generate a list containing the contexts this widget is relevant in.
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
struct SimpleEntry: TimelineEntry {
|
||||||
|
let date: Date
|
||||||
|
let emoji: String
|
||||||
|
}
|
||||||
|
|
||||||
|
struct MusadaqLiveActivityEntryView : View {
|
||||||
|
var entry: Provider.Entry
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
VStack {
|
||||||
|
Text("Time:")
|
||||||
|
Text(entry.date, style: .time)
|
||||||
|
|
||||||
|
Text("Emoji:")
|
||||||
|
Text(entry.emoji)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct MusadaqLiveActivity: Widget {
|
||||||
|
let kind: String = "MusadaqLiveActivity"
|
||||||
|
|
||||||
|
var body: some WidgetConfiguration {
|
||||||
|
StaticConfiguration(kind: kind, provider: Provider()) { entry in
|
||||||
|
if #available(iOS 17.0, *) {
|
||||||
|
MusadaqLiveActivityEntryView(entry: entry)
|
||||||
|
.containerBackground(.fill.tertiary, for: .widget)
|
||||||
|
} else {
|
||||||
|
MusadaqLiveActivityEntryView(entry: entry)
|
||||||
|
.padding()
|
||||||
|
.background()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.configurationDisplayName("My Widget")
|
||||||
|
.description("This is an example widget.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#Preview(as: .systemSmall) {
|
||||||
|
MusadaqLiveActivity()
|
||||||
|
} timeline: {
|
||||||
|
SimpleEntry(date: .now, emoji: "😀")
|
||||||
|
SimpleEntry(date: .now, emoji: "🤩")
|
||||||
|
}
|
||||||
@@ -0,0 +1,86 @@
|
|||||||
|
//
|
||||||
|
// MusadaqLiveActivityBundle.swift
|
||||||
|
// MusadaqLiveActivity
|
||||||
|
//
|
||||||
|
// Created by Hamza Aleghwairyeen on 07/05/2026.
|
||||||
|
//
|
||||||
|
|
||||||
|
import WidgetKit
|
||||||
|
import SwiftUI
|
||||||
|
import ActivityKit
|
||||||
|
|
||||||
|
// ─── 1. Data Model ───────────────────────────────────
|
||||||
|
struct InvoiceBatchAttributes: ActivityAttributes {
|
||||||
|
public struct ContentState: Codable, Hashable {
|
||||||
|
var current: Int
|
||||||
|
var total: Int
|
||||||
|
var isDone: Bool
|
||||||
|
}
|
||||||
|
var companyName: String
|
||||||
|
}
|
||||||
|
|
||||||
|
// ─── 2. Bundle ───────────────────────────────────────
|
||||||
|
@main
|
||||||
|
struct MusadaqLiveActivityBundle: WidgetBundle {
|
||||||
|
var body: some Widget {
|
||||||
|
MusadaqLiveActivityLiveActivity()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ─── 3. Widget ───────────────────────────────────────
|
||||||
|
struct MusadaqLiveActivityLiveActivity: Widget {
|
||||||
|
var body: some WidgetConfiguration {
|
||||||
|
ActivityConfiguration(for: InvoiceBatchAttributes.self) { context in
|
||||||
|
// Lock Screen UI
|
||||||
|
ZStack {
|
||||||
|
Color(red: 0.043, green: 0.098, blue: 0.161) // #0B1929
|
||||||
|
HStack(spacing: 12) {
|
||||||
|
Image(systemName: context.state.isDone
|
||||||
|
? "checkmark.doc.fill" : "arrow.up.doc.fill")
|
||||||
|
.foregroundColor(Color(red: 0.831, green: 0.659, blue: 0.263)) // #D4A843
|
||||||
|
.font(.title2)
|
||||||
|
VStack(alignment: .leading, spacing: 4) {
|
||||||
|
Text(context.state.isDone ? "✅ تم الرفع بنجاح" : "مُصادَق — جارٍ الرفع...")
|
||||||
|
.font(.caption.bold())
|
||||||
|
.foregroundColor(.white)
|
||||||
|
ProgressView(
|
||||||
|
value: Double(context.state.current),
|
||||||
|
total: Double(context.state.total)
|
||||||
|
)
|
||||||
|
.tint(Color(red: 0.831, green: 0.659, blue: 0.263))
|
||||||
|
Text("\(context.state.current) / \(context.state.total) فاتورة — \(context.attributes.companyName)")
|
||||||
|
.font(.caption2)
|
||||||
|
.foregroundColor(.gray)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.padding()
|
||||||
|
}
|
||||||
|
} dynamicIsland: { context in
|
||||||
|
DynamicIsland {
|
||||||
|
DynamicIslandExpandedRegion(.leading) {
|
||||||
|
Image(systemName: "arrow.up.doc.fill")
|
||||||
|
.foregroundColor(Color(red: 0.831, green: 0.659, blue: 0.263))
|
||||||
|
}
|
||||||
|
DynamicIslandExpandedRegion(.trailing) {
|
||||||
|
Text("\(context.state.current)/\(context.state.total)")
|
||||||
|
.font(.caption.bold()).foregroundColor(.white)
|
||||||
|
}
|
||||||
|
DynamicIslandExpandedRegion(.bottom) {
|
||||||
|
ProgressView(value: Double(context.state.current),
|
||||||
|
total: Double(context.state.total))
|
||||||
|
.tint(Color(red: 0.831, green: 0.659, blue: 0.263))
|
||||||
|
}
|
||||||
|
} compactLeading: {
|
||||||
|
Image(systemName: "arrow.up.doc.fill")
|
||||||
|
.foregroundColor(Color(red: 0.831, green: 0.659, blue: 0.263))
|
||||||
|
.font(.caption)
|
||||||
|
} compactTrailing: {
|
||||||
|
Text("\(context.state.current)/\(context.state.total)")
|
||||||
|
.font(.caption2.bold()).foregroundColor(.white)
|
||||||
|
} minimal: {
|
||||||
|
Image(systemName: "arrow.up.doc.fill")
|
||||||
|
.foregroundColor(Color(red: 0.831, green: 0.659, blue: 0.263))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
//
|
||||||
|
// MusadaqLiveActivityControl.swift
|
||||||
|
// MusadaqLiveActivity
|
||||||
|
//
|
||||||
|
// Created by Hamza Aleghwairyeen on 07/05/2026.
|
||||||
|
//
|
||||||
|
|
||||||
|
import AppIntents
|
||||||
|
import SwiftUI
|
||||||
|
import WidgetKit
|
||||||
|
|
||||||
|
struct MusadaqLiveActivityControl: ControlWidget {
|
||||||
|
var body: some ControlWidgetConfiguration {
|
||||||
|
StaticControlConfiguration(
|
||||||
|
kind: "com.example.musadaqApp.MusadaqLiveActivity",
|
||||||
|
provider: Provider()
|
||||||
|
) { value in
|
||||||
|
ControlWidgetToggle(
|
||||||
|
"Start Timer",
|
||||||
|
isOn: value,
|
||||||
|
action: StartTimerIntent()
|
||||||
|
) { isRunning in
|
||||||
|
Label(isRunning ? "On" : "Off", systemImage: "timer")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.displayName("Timer")
|
||||||
|
.description("A an example control that runs a timer.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension MusadaqLiveActivityControl {
|
||||||
|
struct Provider: ControlValueProvider {
|
||||||
|
var previewValue: Bool {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
func currentValue() async throws -> Bool {
|
||||||
|
let isRunning = true // Check if the timer is running
|
||||||
|
return isRunning
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct StartTimerIntent: SetValueIntent {
|
||||||
|
static let title: LocalizedStringResource = "Start a timer"
|
||||||
|
|
||||||
|
@Parameter(title: "Timer is running")
|
||||||
|
var value: Bool
|
||||||
|
|
||||||
|
func perform() async throws -> some IntentResult {
|
||||||
|
// Start / stop the timer based on `value`.
|
||||||
|
return .result()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,80 @@
|
|||||||
|
//
|
||||||
|
// MusadaqLiveActivityLiveActivity.swift
|
||||||
|
// MusadaqLiveActivity
|
||||||
|
//
|
||||||
|
// Created by Hamza Aleghwairyeen on 07/05/2026.
|
||||||
|
//
|
||||||
|
|
||||||
|
import ActivityKit
|
||||||
|
import WidgetKit
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
struct MusadaqLiveActivityAttributes: ActivityAttributes {
|
||||||
|
public struct ContentState: Codable, Hashable {
|
||||||
|
// Dynamic stateful properties about your activity go here!
|
||||||
|
var emoji: String
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fixed non-changing properties about your activity go here!
|
||||||
|
var name: String
|
||||||
|
}
|
||||||
|
|
||||||
|
struct MusadaqLiveActivityLiveActivity: Widget {
|
||||||
|
var body: some WidgetConfiguration {
|
||||||
|
ActivityConfiguration(for: MusadaqLiveActivityAttributes.self) { context in
|
||||||
|
// Lock screen/banner UI goes here
|
||||||
|
VStack {
|
||||||
|
Text("Hello \(context.state.emoji)")
|
||||||
|
}
|
||||||
|
.activityBackgroundTint(Color.cyan)
|
||||||
|
.activitySystemActionForegroundColor(Color.black)
|
||||||
|
|
||||||
|
} dynamicIsland: { context in
|
||||||
|
DynamicIsland {
|
||||||
|
// Expanded UI goes here. Compose the expanded UI through
|
||||||
|
// various regions, like leading/trailing/center/bottom
|
||||||
|
DynamicIslandExpandedRegion(.leading) {
|
||||||
|
Text("Leading")
|
||||||
|
}
|
||||||
|
DynamicIslandExpandedRegion(.trailing) {
|
||||||
|
Text("Trailing")
|
||||||
|
}
|
||||||
|
DynamicIslandExpandedRegion(.bottom) {
|
||||||
|
Text("Bottom \(context.state.emoji)")
|
||||||
|
// more content
|
||||||
|
}
|
||||||
|
} compactLeading: {
|
||||||
|
Text("L")
|
||||||
|
} compactTrailing: {
|
||||||
|
Text("T \(context.state.emoji)")
|
||||||
|
} minimal: {
|
||||||
|
Text(context.state.emoji)
|
||||||
|
}
|
||||||
|
.widgetURL(URL(string: "http://www.apple.com"))
|
||||||
|
.keylineTint(Color.red)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension MusadaqLiveActivityAttributes {
|
||||||
|
fileprivate static var preview: MusadaqLiveActivityAttributes {
|
||||||
|
MusadaqLiveActivityAttributes(name: "World")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension MusadaqLiveActivityAttributes.ContentState {
|
||||||
|
fileprivate static var smiley: MusadaqLiveActivityAttributes.ContentState {
|
||||||
|
MusadaqLiveActivityAttributes.ContentState(emoji: "😀")
|
||||||
|
}
|
||||||
|
|
||||||
|
fileprivate static var starEyes: MusadaqLiveActivityAttributes.ContentState {
|
||||||
|
MusadaqLiveActivityAttributes.ContentState(emoji: "🤩")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#Preview("Notification", as: .content, using: MusadaqLiveActivityAttributes.preview) {
|
||||||
|
MusadaqLiveActivityLiveActivity()
|
||||||
|
} contentStates: {
|
||||||
|
MusadaqLiveActivityAttributes.ContentState.smiley
|
||||||
|
MusadaqLiveActivityAttributes.ContentState.starEyes
|
||||||
|
}
|
||||||
10
musadaq-app/ios/MusadaqLiveActivityExtension.entitlements
Normal file
10
musadaq-app/ios/MusadaqLiveActivityExtension.entitlements
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
<?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>com.apple.security.application-groups</key>
|
||||||
|
<array>
|
||||||
|
<string>group.com.musadaq.app</string>
|
||||||
|
</array>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
archiveVersion = 1;
|
archiveVersion = 1;
|
||||||
classes = {
|
classes = {
|
||||||
};
|
};
|
||||||
objectVersion = 54;
|
objectVersion = 70;
|
||||||
objects = {
|
objects = {
|
||||||
|
|
||||||
/* Begin PBXBuildFile section */
|
/* Begin PBXBuildFile section */
|
||||||
@@ -17,6 +17,9 @@
|
|||||||
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
|
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
|
||||||
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
|
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
|
||||||
BF0A71587203972CC86D9A9D /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7D6221B80BFD02DE32675609 /* Pods_Runner.framework */; };
|
BF0A71587203972CC86D9A9D /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7D6221B80BFD02DE32675609 /* Pods_Runner.framework */; };
|
||||||
|
C68ADD2A2FACB4B8000DB48F /* WidgetKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C68ADD292FACB4B8000DB48F /* WidgetKit.framework */; };
|
||||||
|
C68ADD2C2FACB4B8000DB48F /* SwiftUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C68ADD2B2FACB4B8000DB48F /* SwiftUI.framework */; };
|
||||||
|
C68ADD3B2FACB4BA000DB48F /* MusadaqLiveActivityExtension.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = C68ADD282FACB4B8000DB48F /* MusadaqLiveActivityExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
|
||||||
/* End PBXBuildFile section */
|
/* End PBXBuildFile section */
|
||||||
|
|
||||||
/* Begin PBXContainerItemProxy section */
|
/* Begin PBXContainerItemProxy section */
|
||||||
@@ -27,6 +30,13 @@
|
|||||||
remoteGlobalIDString = 97C146ED1CF9000F007C117D;
|
remoteGlobalIDString = 97C146ED1CF9000F007C117D;
|
||||||
remoteInfo = Runner;
|
remoteInfo = Runner;
|
||||||
};
|
};
|
||||||
|
C68ADD392FACB4BA000DB48F /* PBXContainerItemProxy */ = {
|
||||||
|
isa = PBXContainerItemProxy;
|
||||||
|
containerPortal = 97C146E61CF9000F007C117D /* Project object */;
|
||||||
|
proxyType = 1;
|
||||||
|
remoteGlobalIDString = C68ADD272FACB4B8000DB48F;
|
||||||
|
remoteInfo = MusadaqLiveActivityExtension;
|
||||||
|
};
|
||||||
/* End PBXContainerItemProxy section */
|
/* End PBXContainerItemProxy section */
|
||||||
|
|
||||||
/* Begin PBXCopyFilesBuildPhase section */
|
/* Begin PBXCopyFilesBuildPhase section */
|
||||||
@@ -40,6 +50,17 @@
|
|||||||
name = "Embed Frameworks";
|
name = "Embed Frameworks";
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
|
C68ADD3C2FACB4BA000DB48F /* Embed Foundation Extensions */ = {
|
||||||
|
isa = PBXCopyFilesBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
dstPath = "";
|
||||||
|
dstSubfolderSpec = 13;
|
||||||
|
files = (
|
||||||
|
C68ADD3B2FACB4BA000DB48F /* MusadaqLiveActivityExtension.appex in Embed Foundation Extensions */,
|
||||||
|
);
|
||||||
|
name = "Embed Foundation Extensions";
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
/* End PBXCopyFilesBuildPhase section */
|
/* End PBXCopyFilesBuildPhase section */
|
||||||
|
|
||||||
/* Begin PBXFileReference section */
|
/* Begin PBXFileReference section */
|
||||||
@@ -67,8 +88,27 @@
|
|||||||
A516B9E15A13BFDC50FA3878 /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = "<group>"; };
|
A516B9E15A13BFDC50FA3878 /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = "<group>"; };
|
||||||
B5F124508D0E246590A34406 /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
B5F124508D0E246590A34406 /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
C1D35ECD47C3CDCBD2C89CB0 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = "<group>"; };
|
C1D35ECD47C3CDCBD2C89CB0 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = "<group>"; };
|
||||||
|
C68ADD282FACB4B8000DB48F /* MusadaqLiveActivityExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = MusadaqLiveActivityExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
|
C68ADD292FACB4B8000DB48F /* WidgetKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WidgetKit.framework; path = System/Library/Frameworks/WidgetKit.framework; sourceTree = SDKROOT; };
|
||||||
|
C68ADD2B2FACB4B8000DB48F /* SwiftUI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SwiftUI.framework; path = System/Library/Frameworks/SwiftUI.framework; sourceTree = SDKROOT; };
|
||||||
|
C68ADD422FACB594000DB48F /* MusadaqLiveActivityExtension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = MusadaqLiveActivityExtension.entitlements; sourceTree = "<group>"; };
|
||||||
|
C68ADD432FACBB13000DB48F /* Runner.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Runner.entitlements; sourceTree = "<group>"; };
|
||||||
/* End PBXFileReference section */
|
/* End PBXFileReference section */
|
||||||
|
|
||||||
|
/* Begin PBXFileSystemSynchronizedBuildFileExceptionSet section */
|
||||||
|
C68ADD402FACB4BA000DB48F /* PBXFileSystemSynchronizedBuildFileExceptionSet */ = {
|
||||||
|
isa = PBXFileSystemSynchronizedBuildFileExceptionSet;
|
||||||
|
membershipExceptions = (
|
||||||
|
Info.plist,
|
||||||
|
);
|
||||||
|
target = C68ADD272FACB4B8000DB48F /* MusadaqLiveActivityExtension */;
|
||||||
|
};
|
||||||
|
/* End PBXFileSystemSynchronizedBuildFileExceptionSet section */
|
||||||
|
|
||||||
|
/* Begin PBXFileSystemSynchronizedRootGroup section */
|
||||||
|
C68ADD2D2FACB4B8000DB48F /* MusadaqLiveActivity */ = {isa = PBXFileSystemSynchronizedRootGroup; exceptions = (C68ADD402FACB4BA000DB48F /* PBXFileSystemSynchronizedBuildFileExceptionSet */, ); explicitFileTypes = {}; explicitFolders = (); path = MusadaqLiveActivity; sourceTree = "<group>"; };
|
||||||
|
/* End PBXFileSystemSynchronizedRootGroup section */
|
||||||
|
|
||||||
/* Begin PBXFrameworksBuildPhase section */
|
/* Begin PBXFrameworksBuildPhase section */
|
||||||
61D890350FB4633E292F3803 /* Frameworks */ = {
|
61D890350FB4633E292F3803 /* Frameworks */ = {
|
||||||
isa = PBXFrameworksBuildPhase;
|
isa = PBXFrameworksBuildPhase;
|
||||||
@@ -86,6 +126,15 @@
|
|||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
|
C68ADD252FACB4B8000DB48F /* Frameworks */ = {
|
||||||
|
isa = PBXFrameworksBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
C68ADD2C2FACB4B8000DB48F /* SwiftUI.framework in Frameworks */,
|
||||||
|
C68ADD2A2FACB4B8000DB48F /* WidgetKit.framework in Frameworks */,
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
/* End PBXFrameworksBuildPhase section */
|
/* End PBXFrameworksBuildPhase section */
|
||||||
|
|
||||||
/* Begin PBXGroup section */
|
/* Begin PBXGroup section */
|
||||||
@@ -107,7 +156,6 @@
|
|||||||
4CDBE737BB43361B59042085 /* Pods-RunnerTests.release.xcconfig */,
|
4CDBE737BB43361B59042085 /* Pods-RunnerTests.release.xcconfig */,
|
||||||
A516B9E15A13BFDC50FA3878 /* Pods-RunnerTests.profile.xcconfig */,
|
A516B9E15A13BFDC50FA3878 /* Pods-RunnerTests.profile.xcconfig */,
|
||||||
);
|
);
|
||||||
name = Pods;
|
|
||||||
path = Pods;
|
path = Pods;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
@@ -125,8 +173,10 @@
|
|||||||
97C146E51CF9000F007C117D = {
|
97C146E51CF9000F007C117D = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
C68ADD422FACB594000DB48F /* MusadaqLiveActivityExtension.entitlements */,
|
||||||
9740EEB11CF90186004384FC /* Flutter */,
|
9740EEB11CF90186004384FC /* Flutter */,
|
||||||
97C146F01CF9000F007C117D /* Runner */,
|
97C146F01CF9000F007C117D /* Runner */,
|
||||||
|
C68ADD2D2FACB4B8000DB48F /* MusadaqLiveActivity */,
|
||||||
97C146EF1CF9000F007C117D /* Products */,
|
97C146EF1CF9000F007C117D /* Products */,
|
||||||
331C8082294A63A400263BE5 /* RunnerTests */,
|
331C8082294A63A400263BE5 /* RunnerTests */,
|
||||||
01F4F223F169A9E6C26FA35C /* GoogleService-Info.plist */,
|
01F4F223F169A9E6C26FA35C /* GoogleService-Info.plist */,
|
||||||
@@ -140,6 +190,7 @@
|
|||||||
children = (
|
children = (
|
||||||
97C146EE1CF9000F007C117D /* Runner.app */,
|
97C146EE1CF9000F007C117D /* Runner.app */,
|
||||||
331C8081294A63A400263BE5 /* RunnerTests.xctest */,
|
331C8081294A63A400263BE5 /* RunnerTests.xctest */,
|
||||||
|
C68ADD282FACB4B8000DB48F /* MusadaqLiveActivityExtension.appex */,
|
||||||
);
|
);
|
||||||
name = Products;
|
name = Products;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@@ -147,6 +198,7 @@
|
|||||||
97C146F01CF9000F007C117D /* Runner */ = {
|
97C146F01CF9000F007C117D /* Runner */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
C68ADD432FACBB13000DB48F /* Runner.entitlements */,
|
||||||
97C146FA1CF9000F007C117D /* Main.storyboard */,
|
97C146FA1CF9000F007C117D /* Main.storyboard */,
|
||||||
97C146FD1CF9000F007C117D /* Assets.xcassets */,
|
97C146FD1CF9000F007C117D /* Assets.xcassets */,
|
||||||
97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */,
|
97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */,
|
||||||
@@ -164,6 +216,8 @@
|
|||||||
children = (
|
children = (
|
||||||
7D6221B80BFD02DE32675609 /* Pods_Runner.framework */,
|
7D6221B80BFD02DE32675609 /* Pods_Runner.framework */,
|
||||||
B5F124508D0E246590A34406 /* Pods_RunnerTests.framework */,
|
B5F124508D0E246590A34406 /* Pods_RunnerTests.framework */,
|
||||||
|
C68ADD292FACB4B8000DB48F /* WidgetKit.framework */,
|
||||||
|
C68ADD2B2FACB4B8000DB48F /* SwiftUI.framework */,
|
||||||
);
|
);
|
||||||
name = Frameworks;
|
name = Frameworks;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@@ -200,6 +254,7 @@
|
|||||||
97C146EB1CF9000F007C117D /* Frameworks */,
|
97C146EB1CF9000F007C117D /* Frameworks */,
|
||||||
97C146EC1CF9000F007C117D /* Resources */,
|
97C146EC1CF9000F007C117D /* Resources */,
|
||||||
9705A1C41CF9048500538489 /* Embed Frameworks */,
|
9705A1C41CF9048500538489 /* Embed Frameworks */,
|
||||||
|
C68ADD3C2FACB4BA000DB48F /* Embed Foundation Extensions */,
|
||||||
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
|
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
|
||||||
E56C32186B9FB7A499F5B38F /* [CP] Embed Pods Frameworks */,
|
E56C32186B9FB7A499F5B38F /* [CP] Embed Pods Frameworks */,
|
||||||
B23DF4822D0EB618AED457C9 /* [CP] Copy Pods Resources */,
|
B23DF4822D0EB618AED457C9 /* [CP] Copy Pods Resources */,
|
||||||
@@ -207,12 +262,35 @@
|
|||||||
buildRules = (
|
buildRules = (
|
||||||
);
|
);
|
||||||
dependencies = (
|
dependencies = (
|
||||||
|
C68ADD3A2FACB4BA000DB48F /* PBXTargetDependency */,
|
||||||
);
|
);
|
||||||
name = Runner;
|
name = Runner;
|
||||||
productName = Runner;
|
productName = Runner;
|
||||||
productReference = 97C146EE1CF9000F007C117D /* Runner.app */;
|
productReference = 97C146EE1CF9000F007C117D /* Runner.app */;
|
||||||
productType = "com.apple.product-type.application";
|
productType = "com.apple.product-type.application";
|
||||||
};
|
};
|
||||||
|
C68ADD272FACB4B8000DB48F /* MusadaqLiveActivityExtension */ = {
|
||||||
|
isa = PBXNativeTarget;
|
||||||
|
buildConfigurationList = C68ADD412FACB4BA000DB48F /* Build configuration list for PBXNativeTarget "MusadaqLiveActivityExtension" */;
|
||||||
|
buildPhases = (
|
||||||
|
C68ADD242FACB4B8000DB48F /* Sources */,
|
||||||
|
C68ADD262FACB4B8000DB48F /* Resources */,
|
||||||
|
C68ADD252FACB4B8000DB48F /* Frameworks */,
|
||||||
|
);
|
||||||
|
buildRules = (
|
||||||
|
);
|
||||||
|
dependencies = (
|
||||||
|
);
|
||||||
|
fileSystemSynchronizedGroups = (
|
||||||
|
C68ADD2D2FACB4B8000DB48F /* MusadaqLiveActivity */,
|
||||||
|
);
|
||||||
|
name = MusadaqLiveActivityExtension;
|
||||||
|
packageProductDependencies = (
|
||||||
|
);
|
||||||
|
productName = MusadaqLiveActivityExtension;
|
||||||
|
productReference = C68ADD282FACB4B8000DB48F /* MusadaqLiveActivityExtension.appex */;
|
||||||
|
productType = "com.apple.product-type.app-extension";
|
||||||
|
};
|
||||||
/* End PBXNativeTarget section */
|
/* End PBXNativeTarget section */
|
||||||
|
|
||||||
/* Begin PBXProject section */
|
/* Begin PBXProject section */
|
||||||
@@ -220,6 +298,7 @@
|
|||||||
isa = PBXProject;
|
isa = PBXProject;
|
||||||
attributes = {
|
attributes = {
|
||||||
BuildIndependentTargetsInParallel = YES;
|
BuildIndependentTargetsInParallel = YES;
|
||||||
|
LastSwiftUpdateCheck = 2600;
|
||||||
LastUpgradeCheck = 1510;
|
LastUpgradeCheck = 1510;
|
||||||
ORGANIZATIONNAME = "";
|
ORGANIZATIONNAME = "";
|
||||||
TargetAttributes = {
|
TargetAttributes = {
|
||||||
@@ -231,6 +310,9 @@
|
|||||||
CreatedOnToolsVersion = 7.3.1;
|
CreatedOnToolsVersion = 7.3.1;
|
||||||
LastSwiftMigration = 1100;
|
LastSwiftMigration = 1100;
|
||||||
};
|
};
|
||||||
|
C68ADD272FACB4B8000DB48F = {
|
||||||
|
CreatedOnToolsVersion = 26.0;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */;
|
buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */;
|
||||||
@@ -248,6 +330,7 @@
|
|||||||
targets = (
|
targets = (
|
||||||
97C146ED1CF9000F007C117D /* Runner */,
|
97C146ED1CF9000F007C117D /* Runner */,
|
||||||
331C8080294A63A400263BE5 /* RunnerTests */,
|
331C8080294A63A400263BE5 /* RunnerTests */,
|
||||||
|
C68ADD272FACB4B8000DB48F /* MusadaqLiveActivityExtension */,
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
/* End PBXProject section */
|
/* End PBXProject section */
|
||||||
@@ -272,6 +355,13 @@
|
|||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
|
C68ADD262FACB4B8000DB48F /* Resources */ = {
|
||||||
|
isa = PBXResourcesBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
/* End PBXResourcesBuildPhase section */
|
/* End PBXResourcesBuildPhase section */
|
||||||
|
|
||||||
/* Begin PBXShellScriptBuildPhase section */
|
/* Begin PBXShellScriptBuildPhase section */
|
||||||
@@ -336,10 +426,14 @@
|
|||||||
inputFileListPaths = (
|
inputFileListPaths = (
|
||||||
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-input-files.xcfilelist",
|
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-input-files.xcfilelist",
|
||||||
);
|
);
|
||||||
|
inputPaths = (
|
||||||
|
);
|
||||||
name = "[CP] Copy Pods Resources";
|
name = "[CP] Copy Pods Resources";
|
||||||
outputFileListPaths = (
|
outputFileListPaths = (
|
||||||
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-output-files.xcfilelist",
|
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-output-files.xcfilelist",
|
||||||
);
|
);
|
||||||
|
outputPaths = (
|
||||||
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
shellPath = /bin/sh;
|
shellPath = /bin/sh;
|
||||||
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n";
|
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n";
|
||||||
@@ -375,10 +469,14 @@
|
|||||||
inputFileListPaths = (
|
inputFileListPaths = (
|
||||||
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist",
|
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist",
|
||||||
);
|
);
|
||||||
|
inputPaths = (
|
||||||
|
);
|
||||||
name = "[CP] Embed Pods Frameworks";
|
name = "[CP] Embed Pods Frameworks";
|
||||||
outputFileListPaths = (
|
outputFileListPaths = (
|
||||||
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist",
|
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist",
|
||||||
);
|
);
|
||||||
|
outputPaths = (
|
||||||
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
shellPath = /bin/sh;
|
shellPath = /bin/sh;
|
||||||
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
|
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
|
||||||
@@ -404,6 +502,13 @@
|
|||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
|
C68ADD242FACB4B8000DB48F /* Sources */ = {
|
||||||
|
isa = PBXSourcesBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
/* End PBXSourcesBuildPhase section */
|
/* End PBXSourcesBuildPhase section */
|
||||||
|
|
||||||
/* Begin PBXTargetDependency section */
|
/* Begin PBXTargetDependency section */
|
||||||
@@ -412,6 +517,11 @@
|
|||||||
target = 97C146ED1CF9000F007C117D /* Runner */;
|
target = 97C146ED1CF9000F007C117D /* Runner */;
|
||||||
targetProxy = 331C8085294A63A400263BE5 /* PBXContainerItemProxy */;
|
targetProxy = 331C8085294A63A400263BE5 /* PBXContainerItemProxy */;
|
||||||
};
|
};
|
||||||
|
C68ADD3A2FACB4BA000DB48F /* PBXTargetDependency */ = {
|
||||||
|
isa = PBXTargetDependency;
|
||||||
|
target = C68ADD272FACB4B8000DB48F /* MusadaqLiveActivityExtension */;
|
||||||
|
targetProxy = C68ADD392FACB4BA000DB48F /* PBXContainerItemProxy */;
|
||||||
|
};
|
||||||
/* End PBXTargetDependency section */
|
/* End PBXTargetDependency section */
|
||||||
|
|
||||||
/* Begin PBXVariantGroup section */
|
/* Begin PBXVariantGroup section */
|
||||||
@@ -492,6 +602,7 @@
|
|||||||
buildSettings = {
|
buildSettings = {
|
||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
CLANG_ENABLE_MODULES = YES;
|
CLANG_ENABLE_MODULES = YES;
|
||||||
|
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
|
||||||
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
||||||
DEVELOPMENT_TEAM = 63CVT8G5P8;
|
DEVELOPMENT_TEAM = 63CVT8G5P8;
|
||||||
ENABLE_BITCODE = NO;
|
ENABLE_BITCODE = NO;
|
||||||
@@ -500,7 +611,7 @@
|
|||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
);
|
);
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.example.musadaqApp;
|
PRODUCT_BUNDLE_IDENTIFIER = com.musadaq.app;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||||
SWIFT_VERSION = 5.0;
|
SWIFT_VERSION = 5.0;
|
||||||
@@ -675,6 +786,7 @@
|
|||||||
buildSettings = {
|
buildSettings = {
|
||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
CLANG_ENABLE_MODULES = YES;
|
CLANG_ENABLE_MODULES = YES;
|
||||||
|
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
|
||||||
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
||||||
DEVELOPMENT_TEAM = 63CVT8G5P8;
|
DEVELOPMENT_TEAM = 63CVT8G5P8;
|
||||||
ENABLE_BITCODE = NO;
|
ENABLE_BITCODE = NO;
|
||||||
@@ -683,7 +795,7 @@
|
|||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
);
|
);
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.example.musadaqApp;
|
PRODUCT_BUNDLE_IDENTIFIER = com.musadaq.app;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||||
@@ -698,6 +810,7 @@
|
|||||||
buildSettings = {
|
buildSettings = {
|
||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
CLANG_ENABLE_MODULES = YES;
|
CLANG_ENABLE_MODULES = YES;
|
||||||
|
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
|
||||||
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
||||||
DEVELOPMENT_TEAM = 63CVT8G5P8;
|
DEVELOPMENT_TEAM = 63CVT8G5P8;
|
||||||
ENABLE_BITCODE = NO;
|
ENABLE_BITCODE = NO;
|
||||||
@@ -706,7 +819,7 @@
|
|||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
);
|
);
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.example.musadaqApp;
|
PRODUCT_BUNDLE_IDENTIFIER = com.musadaq.app;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||||
SWIFT_VERSION = 5.0;
|
SWIFT_VERSION = 5.0;
|
||||||
@@ -714,6 +827,138 @@
|
|||||||
};
|
};
|
||||||
name = Release;
|
name = Release;
|
||||||
};
|
};
|
||||||
|
C68ADD3D2FACB4BA000DB48F /* Debug */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
|
||||||
|
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||||
|
ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground;
|
||||||
|
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||||
|
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
|
||||||
|
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||||
|
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||||
|
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||||
|
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||||
|
CODE_SIGN_ENTITLEMENTS = MusadaqLiveActivityExtension.entitlements;
|
||||||
|
CODE_SIGN_STYLE = Automatic;
|
||||||
|
CURRENT_PROJECT_VERSION = 1;
|
||||||
|
DEVELOPMENT_TEAM = 63CVT8G5P8;
|
||||||
|
ENABLE_USER_SCRIPT_SANDBOXING = YES;
|
||||||
|
GCC_C_LANGUAGE_STANDARD = gnu17;
|
||||||
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
|
INFOPLIST_FILE = MusadaqLiveActivity/Info.plist;
|
||||||
|
INFOPLIST_KEY_CFBundleDisplayName = MusadaqLiveActivity;
|
||||||
|
INFOPLIST_KEY_NSHumanReadableCopyright = "";
|
||||||
|
IPHONEOS_DEPLOYMENT_TARGET = 26.0;
|
||||||
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
|
"$(inherited)",
|
||||||
|
"@executable_path/Frameworks",
|
||||||
|
"@executable_path/../../Frameworks",
|
||||||
|
);
|
||||||
|
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
|
||||||
|
MARKETING_VERSION = 1.0;
|
||||||
|
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||||
|
MTL_FAST_MATH = YES;
|
||||||
|
PRODUCT_BUNDLE_IDENTIFIER = com.musadaq.app.MusadaqLiveActivity;
|
||||||
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
SKIP_INSTALL = YES;
|
||||||
|
STRING_CATALOG_GENERATE_SYMBOLS = YES;
|
||||||
|
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)";
|
||||||
|
SWIFT_APPROACHABLE_CONCURRENCY = YES;
|
||||||
|
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||||
|
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||||
|
SWIFT_UPCOMING_FEATURE_MEMBER_IMPORT_VISIBILITY = YES;
|
||||||
|
SWIFT_VERSION = 5.0;
|
||||||
|
TARGETED_DEVICE_FAMILY = "1,2";
|
||||||
|
};
|
||||||
|
name = Debug;
|
||||||
|
};
|
||||||
|
C68ADD3E2FACB4BA000DB48F /* Release */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
|
||||||
|
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||||
|
ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground;
|
||||||
|
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||||
|
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
|
||||||
|
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||||
|
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||||
|
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||||
|
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||||
|
CODE_SIGN_ENTITLEMENTS = MusadaqLiveActivityExtension.entitlements;
|
||||||
|
CODE_SIGN_STYLE = Automatic;
|
||||||
|
CURRENT_PROJECT_VERSION = 1;
|
||||||
|
DEVELOPMENT_TEAM = 63CVT8G5P8;
|
||||||
|
ENABLE_USER_SCRIPT_SANDBOXING = YES;
|
||||||
|
GCC_C_LANGUAGE_STANDARD = gnu17;
|
||||||
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
|
INFOPLIST_FILE = MusadaqLiveActivity/Info.plist;
|
||||||
|
INFOPLIST_KEY_CFBundleDisplayName = MusadaqLiveActivity;
|
||||||
|
INFOPLIST_KEY_NSHumanReadableCopyright = "";
|
||||||
|
IPHONEOS_DEPLOYMENT_TARGET = 26.0;
|
||||||
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
|
"$(inherited)",
|
||||||
|
"@executable_path/Frameworks",
|
||||||
|
"@executable_path/../../Frameworks",
|
||||||
|
);
|
||||||
|
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
|
||||||
|
MARKETING_VERSION = 1.0;
|
||||||
|
MTL_FAST_MATH = YES;
|
||||||
|
PRODUCT_BUNDLE_IDENTIFIER = com.musadaq.app.MusadaqLiveActivity;
|
||||||
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
SKIP_INSTALL = YES;
|
||||||
|
STRING_CATALOG_GENERATE_SYMBOLS = YES;
|
||||||
|
SWIFT_APPROACHABLE_CONCURRENCY = YES;
|
||||||
|
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||||
|
SWIFT_UPCOMING_FEATURE_MEMBER_IMPORT_VISIBILITY = YES;
|
||||||
|
SWIFT_VERSION = 5.0;
|
||||||
|
TARGETED_DEVICE_FAMILY = "1,2";
|
||||||
|
};
|
||||||
|
name = Release;
|
||||||
|
};
|
||||||
|
C68ADD3F2FACB4BA000DB48F /* Profile */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
|
||||||
|
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||||
|
ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground;
|
||||||
|
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||||
|
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
|
||||||
|
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||||
|
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||||
|
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||||
|
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||||
|
CODE_SIGN_ENTITLEMENTS = MusadaqLiveActivityExtension.entitlements;
|
||||||
|
CODE_SIGN_STYLE = Automatic;
|
||||||
|
CURRENT_PROJECT_VERSION = 1;
|
||||||
|
DEVELOPMENT_TEAM = 63CVT8G5P8;
|
||||||
|
ENABLE_USER_SCRIPT_SANDBOXING = YES;
|
||||||
|
GCC_C_LANGUAGE_STANDARD = gnu17;
|
||||||
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
|
INFOPLIST_FILE = MusadaqLiveActivity/Info.plist;
|
||||||
|
INFOPLIST_KEY_CFBundleDisplayName = MusadaqLiveActivity;
|
||||||
|
INFOPLIST_KEY_NSHumanReadableCopyright = "";
|
||||||
|
IPHONEOS_DEPLOYMENT_TARGET = 26.0;
|
||||||
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
|
"$(inherited)",
|
||||||
|
"@executable_path/Frameworks",
|
||||||
|
"@executable_path/../../Frameworks",
|
||||||
|
);
|
||||||
|
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
|
||||||
|
MARKETING_VERSION = 1.0;
|
||||||
|
MTL_FAST_MATH = YES;
|
||||||
|
PRODUCT_BUNDLE_IDENTIFIER = com.musadaq.app.MusadaqLiveActivity;
|
||||||
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
SKIP_INSTALL = YES;
|
||||||
|
STRING_CATALOG_GENERATE_SYMBOLS = YES;
|
||||||
|
SWIFT_APPROACHABLE_CONCURRENCY = YES;
|
||||||
|
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||||
|
SWIFT_UPCOMING_FEATURE_MEMBER_IMPORT_VISIBILITY = YES;
|
||||||
|
SWIFT_VERSION = 5.0;
|
||||||
|
TARGETED_DEVICE_FAMILY = "1,2";
|
||||||
|
};
|
||||||
|
name = Profile;
|
||||||
|
};
|
||||||
/* End XCBuildConfiguration section */
|
/* End XCBuildConfiguration section */
|
||||||
|
|
||||||
/* Begin XCConfigurationList section */
|
/* Begin XCConfigurationList section */
|
||||||
@@ -747,6 +992,16 @@
|
|||||||
defaultConfigurationIsVisible = 0;
|
defaultConfigurationIsVisible = 0;
|
||||||
defaultConfigurationName = Release;
|
defaultConfigurationName = Release;
|
||||||
};
|
};
|
||||||
|
C68ADD412FACB4BA000DB48F /* Build configuration list for PBXNativeTarget "MusadaqLiveActivityExtension" */ = {
|
||||||
|
isa = XCConfigurationList;
|
||||||
|
buildConfigurations = (
|
||||||
|
C68ADD3D2FACB4BA000DB48F /* Debug */,
|
||||||
|
C68ADD3E2FACB4BA000DB48F /* Release */,
|
||||||
|
C68ADD3F2FACB4BA000DB48F /* Profile */,
|
||||||
|
);
|
||||||
|
defaultConfigurationIsVisible = 0;
|
||||||
|
defaultConfigurationName = Release;
|
||||||
|
};
|
||||||
/* End XCConfigurationList section */
|
/* End XCConfigurationList section */
|
||||||
};
|
};
|
||||||
rootObject = 97C146E61CF9000F007C117D /* Project object */;
|
rootObject = 97C146E61CF9000F007C117D /* Project object */;
|
||||||
|
|||||||
@@ -34,6 +34,8 @@
|
|||||||
<string>تطبيق مُصادَق يحتاج للوصول إلى الميكروفون لاستخدام المساعد الصوتي وتسجيل الملاحظات.</string>
|
<string>تطبيق مُصادَق يحتاج للوصول إلى الميكروفون لاستخدام المساعد الصوتي وتسجيل الملاحظات.</string>
|
||||||
<key>NSPhotoLibraryUsageDescription</key>
|
<key>NSPhotoLibraryUsageDescription</key>
|
||||||
<string>تطبيق مُصادَق يحتاج للوصول إلى الصور لاختيار فواتير محفوظة مسبقاً في معرض الصور.</string>
|
<string>تطبيق مُصادَق يحتاج للوصول إلى الصور لاختيار فواتير محفوظة مسبقاً في معرض الصور.</string>
|
||||||
|
<key>NSSupportsLiveActivities</key>
|
||||||
|
<true/>
|
||||||
<key>UIApplicationSceneManifest</key>
|
<key>UIApplicationSceneManifest</key>
|
||||||
<dict>
|
<dict>
|
||||||
<key>UIApplicationSupportsMultipleScenes</key>
|
<key>UIApplicationSupportsMultipleScenes</key>
|
||||||
@@ -74,5 +76,9 @@
|
|||||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||||
</array>
|
</array>
|
||||||
|
<key>NSSupportsLiveActivities</key>
|
||||||
|
<true/>
|
||||||
|
<key>NSSupportsLiveActivitiesFrequentUpdates</key>
|
||||||
|
<true/>
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
|
|||||||
10
musadaq-app/ios/Runner/Runner.entitlements
Normal file
10
musadaq-app/ios/Runner/Runner.entitlements
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
<?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>com.apple.security.application-groups</key>
|
||||||
|
<array>
|
||||||
|
<string>group.com.musadaq.app</string>
|
||||||
|
</array>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
22
scratch/run_migration.php
Normal file
22
scratch/run_migration.php
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
<?php
|
||||||
|
require 'app/bootstrap.php';
|
||||||
|
|
||||||
|
$sql = file_get_contents('scratch/stage0_db_update.sql');
|
||||||
|
$db = \App\Core\Database::getInstance()->getConnection();
|
||||||
|
|
||||||
|
try {
|
||||||
|
// MySQL PDO cannot run multiple statements with exec() sometimes depending on driver,
|
||||||
|
// so we split by semicolon and handle.
|
||||||
|
$statements = array_filter(array_map('trim', explode(';', $sql)));
|
||||||
|
|
||||||
|
foreach ($statements as $stmt) {
|
||||||
|
if (!empty($stmt)) {
|
||||||
|
$db->exec($stmt);
|
||||||
|
echo "Executed: " . substr($stmt, 0, 50) . "...\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
echo "Migration completed successfully!\n";
|
||||||
|
} catch (Exception $e) {
|
||||||
|
echo "Migration failed: " . $e->getMessage() . "\n";
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
73
scratch/stage0_db_update.sql
Normal file
73
scratch/stage0_db_update.sql
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
-- Stage 0: Database Updates for Mobile Support & Bulk Import
|
||||||
|
|
||||||
|
-- 1. Update Users Table
|
||||||
|
ALTER TABLE users ADD COLUMN phone VARCHAR(20) NULL AFTER email;
|
||||||
|
ALTER TABLE users ADD COLUMN phone_hash VARCHAR(64) NULL AFTER phone;
|
||||||
|
ALTER TABLE users ADD COLUMN pin_hash VARCHAR(255) NULL;
|
||||||
|
ALTER TABLE users ADD COLUMN biometric_enabled BOOLEAN DEFAULT FALSE;
|
||||||
|
ALTER TABLE users ADD INDEX idx_phone_hash (phone_hash);
|
||||||
|
|
||||||
|
-- 2. User Devices Table
|
||||||
|
CREATE TABLE user_devices (
|
||||||
|
id CHAR(36) PRIMARY KEY DEFAULT (UUID()),
|
||||||
|
user_id CHAR(36) NOT NULL,
|
||||||
|
device_fingerprint VARCHAR(64) NOT NULL,
|
||||||
|
device_name VARCHAR(100),
|
||||||
|
platform ENUM('android','ios') NOT NULL,
|
||||||
|
app_version VARCHAR(20),
|
||||||
|
push_token TEXT NULL,
|
||||||
|
is_trusted BOOLEAN DEFAULT FALSE,
|
||||||
|
last_seen_at DATETIME,
|
||||||
|
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
|
||||||
|
UNIQUE KEY uq_user_device (user_id, device_fingerprint)
|
||||||
|
);
|
||||||
|
|
||||||
|
-- 3. Invoice Batches Table
|
||||||
|
CREATE TABLE invoice_batches (
|
||||||
|
id CHAR(36) PRIMARY KEY,
|
||||||
|
tenant_id CHAR(36) NOT NULL,
|
||||||
|
company_id CHAR(36) NOT NULL,
|
||||||
|
uploaded_by CHAR(36) NOT NULL,
|
||||||
|
total_images INT NOT NULL DEFAULT 0,
|
||||||
|
processed_images INT NOT NULL DEFAULT 0,
|
||||||
|
status ENUM('uploading','processing','done','partial_fail') DEFAULT 'uploading',
|
||||||
|
source ENUM('mobile_scan','web_upload','whatsapp') DEFAULT 'mobile_scan',
|
||||||
|
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
completed_at DATETIME NULL,
|
||||||
|
FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE,
|
||||||
|
FOREIGN KEY (company_id) REFERENCES companies(id) ON DELETE CASCADE,
|
||||||
|
FOREIGN KEY (uploaded_by) REFERENCES users(id) ON DELETE SET NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
-- 4. Invoice Processing Queue Table
|
||||||
|
CREATE TABLE invoice_processing_queue (
|
||||||
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||||
|
batch_id CHAR(36) NOT NULL,
|
||||||
|
invoice_id CHAR(36) NULL,
|
||||||
|
tenant_id CHAR(36) NOT NULL,
|
||||||
|
image_path VARCHAR(500) NOT NULL,
|
||||||
|
status ENUM('pending','processing','done','failed') DEFAULT 'pending',
|
||||||
|
attempts INT DEFAULT 0,
|
||||||
|
error_message TEXT NULL,
|
||||||
|
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
processed_at DATETIME NULL,
|
||||||
|
INDEX idx_status_tenant (status, tenant_id),
|
||||||
|
INDEX idx_batch (batch_id)
|
||||||
|
);
|
||||||
|
|
||||||
|
-- 5. Excel Imports Table
|
||||||
|
CREATE TABLE excel_imports (
|
||||||
|
id CHAR(36) PRIMARY KEY DEFAULT (UUID()),
|
||||||
|
tenant_id CHAR(36) NOT NULL,
|
||||||
|
company_id CHAR(36) NOT NULL,
|
||||||
|
uploaded_by CHAR(36) NOT NULL,
|
||||||
|
filename VARCHAR(255) NOT NULL,
|
||||||
|
total_rows INT DEFAULT 0,
|
||||||
|
success_rows INT DEFAULT 0,
|
||||||
|
failed_rows INT DEFAULT 0,
|
||||||
|
status ENUM('processing','done','failed') DEFAULT 'processing',
|
||||||
|
error_log JSON NULL,
|
||||||
|
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
FOREIGN KEY (tenant_id) REFERENCES tenants(id) ON DELETE CASCADE
|
||||||
|
);
|
||||||
@@ -111,6 +111,134 @@ try {
|
|||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## File: `migrate_payments.php`
|
||||||
|
|
||||||
|
```php
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Migration Script: Payment System & Subscriptions
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
require_once __DIR__ . '/../app/bootstrap/init.php';
|
||||||
|
|
||||||
|
use App\Core\Database;
|
||||||
|
|
||||||
|
$db = Database::getInstance();
|
||||||
|
|
||||||
|
try {
|
||||||
|
echo "Starting migration...\n";
|
||||||
|
|
||||||
|
// 1. Create subscription_plans table
|
||||||
|
echo "Creating subscription_plans table...\n";
|
||||||
|
$db->exec("
|
||||||
|
CREATE TABLE IF NOT EXISTS subscription_plans (
|
||||||
|
id VARCHAR(50) PRIMARY KEY,
|
||||||
|
name_ar VARCHAR(255) NOT NULL,
|
||||||
|
name_en VARCHAR(255) NOT NULL,
|
||||||
|
max_companies INT NOT NULL,
|
||||||
|
max_invoices_month INT NOT NULL,
|
||||||
|
max_users INT NOT NULL,
|
||||||
|
price_jod DECIMAL(10,3) NOT NULL,
|
||||||
|
ai_features BOOLEAN DEFAULT TRUE,
|
||||||
|
jofotara_enabled BOOLEAN DEFAULT TRUE,
|
||||||
|
sort_order INT DEFAULT 0,
|
||||||
|
is_active BOOLEAN DEFAULT TRUE,
|
||||||
|
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
|
||||||
|
");
|
||||||
|
|
||||||
|
// 2. Insert initial plans
|
||||||
|
echo "Inserting initial plans...\n";
|
||||||
|
$plans = require __DIR__ . '/../app/config/plans.php';
|
||||||
|
$stmt = $db->prepare("
|
||||||
|
INSERT INTO subscription_plans (id, name_ar, name_en, max_companies, max_invoices_month, max_users, price_jod, ai_features, jofotara_enabled, sort_order)
|
||||||
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||||
|
ON DUPLICATE KEY UPDATE
|
||||||
|
name_ar = VALUES(name_ar),
|
||||||
|
price_jod = VALUES(price_jod),
|
||||||
|
max_companies = VALUES(max_companies),
|
||||||
|
max_invoices_month = VALUES(max_invoices_month)
|
||||||
|
");
|
||||||
|
|
||||||
|
$order = 0;
|
||||||
|
foreach ($plans as $id => $plan) {
|
||||||
|
$stmt->execute([
|
||||||
|
$id,
|
||||||
|
$plan['name_ar'],
|
||||||
|
$plan['name_en'],
|
||||||
|
$plan['max_companies'],
|
||||||
|
$plan['max_invoices_month'],
|
||||||
|
$plan['max_users'],
|
||||||
|
$plan['price_jod'],
|
||||||
|
$plan['ai_features'] ? 1 : 0,
|
||||||
|
$plan['jofotara_enabled'] ? 1 : 0,
|
||||||
|
$order++
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. Create payment_requests table
|
||||||
|
echo "Creating payment_requests table...\n";
|
||||||
|
$db->exec("
|
||||||
|
CREATE TABLE IF NOT EXISTS payment_requests (
|
||||||
|
id CHAR(36) PRIMARY KEY,
|
||||||
|
tenant_id CHAR(36) NOT NULL,
|
||||||
|
user_id CHAR(36) NOT NULL,
|
||||||
|
plan_id VARCHAR(50) NOT NULL,
|
||||||
|
amount_jod DECIMAL(10,3) NOT NULL,
|
||||||
|
internal_reference VARCHAR(50) UNIQUE NOT NULL,
|
||||||
|
cliq_alias VARCHAR(100) NOT NULL,
|
||||||
|
payer_name VARCHAR(255) DEFAULT NULL,
|
||||||
|
bank_reference VARCHAR(100) DEFAULT NULL,
|
||||||
|
status ENUM('pending','uploaded','verified','approved','rejected') DEFAULT 'pending',
|
||||||
|
admin_notes TEXT DEFAULT NULL,
|
||||||
|
verified_at DATETIME DEFAULT NULL,
|
||||||
|
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||||
|
FOREIGN KEY (tenant_id) REFERENCES tenants(id),
|
||||||
|
FOREIGN KEY (user_id) REFERENCES users(id),
|
||||||
|
INDEX idx_status (status),
|
||||||
|
INDEX idx_bank_ref (bank_reference)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
|
||||||
|
");
|
||||||
|
|
||||||
|
// 4. Create bank_transactions table
|
||||||
|
echo "Creating bank_transactions table...\n";
|
||||||
|
$db->exec("
|
||||||
|
CREATE TABLE IF NOT EXISTS bank_transactions (
|
||||||
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||||
|
bank_reference VARCHAR(100) UNIQUE NOT NULL,
|
||||||
|
amount DECIMAL(10,3) NOT NULL,
|
||||||
|
sender_name VARCHAR(255) DEFAULT NULL,
|
||||||
|
raw_message TEXT NOT NULL,
|
||||||
|
is_claimed BOOLEAN DEFAULT FALSE,
|
||||||
|
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
INDEX idx_ref (bank_reference)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
|
||||||
|
");
|
||||||
|
|
||||||
|
// 5. Update subscriptions table if needed
|
||||||
|
echo "Updating subscriptions table schema...\n";
|
||||||
|
// Check if column plan_id exists, if not add it
|
||||||
|
$cols = $db->query("SHOW COLUMNS FROM subscriptions")->fetchAll(PDO::FETCH_COLUMN);
|
||||||
|
if (!in_array('plan_id', $cols)) {
|
||||||
|
$db->exec("ALTER TABLE subscriptions ADD COLUMN plan_id VARCHAR(50) AFTER tenant_id");
|
||||||
|
$db->exec("ALTER TABLE subscriptions MODIFY COLUMN plan ENUM('free','basic','office','pro','enterprise') DEFAULT 'free'");
|
||||||
|
}
|
||||||
|
if (!in_array('max_users', $cols)) {
|
||||||
|
$db->exec("ALTER TABLE subscriptions ADD COLUMN max_users INT NOT NULL DEFAULT 1 AFTER max_invoices_per_month");
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "Migration completed successfully!\n";
|
||||||
|
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
echo "Migration failed: " . $e->getMessage() . "\n";
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
## File: `list_users.php`
|
## File: `list_users.php`
|
||||||
|
|
||||||
```php
|
```php
|
||||||
|
|||||||
Reference in New Issue
Block a user