Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e1881acc18 | ||
|
|
f4b914a2ad | ||
|
|
34ef156538 | ||
|
|
cfb551328b | ||
|
|
40366f0708 |
@@ -15,7 +15,7 @@ migration:
|
|||||||
- platform: root
|
- platform: root
|
||||||
create_revision: d3b14c876900e553bc736ca19295fc09e3853e8e
|
create_revision: d3b14c876900e553bc736ca19295fc09e3853e8e
|
||||||
base_revision: d3b14c876900e553bc736ca19295fc09e3853e8e
|
base_revision: d3b14c876900e553bc736ca19295fc09e3853e8e
|
||||||
- platform: android
|
- platform: ios
|
||||||
create_revision: d3b14c876900e553bc736ca19295fc09e3853e8e
|
create_revision: d3b14c876900e553bc736ca19295fc09e3853e8e
|
||||||
base_revision: d3b14c876900e553bc736ca19295fc09e3853e8e
|
base_revision: d3b14c876900e553bc736ca19295fc09e3853e8e
|
||||||
|
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ analyzer:
|
|||||||
exclude:
|
exclude:
|
||||||
- build/**
|
- build/**
|
||||||
- android/**
|
- android/**
|
||||||
|
- ios/**
|
||||||
|
|
||||||
linter:
|
linter:
|
||||||
# The lint rules applied to this project can be customized in the
|
# The lint rules applied to this project can be customized in the
|
||||||
|
|||||||
@@ -0,0 +1,34 @@
|
|||||||
|
**/dgph
|
||||||
|
*.mode1v3
|
||||||
|
*.mode2v3
|
||||||
|
*.moved-aside
|
||||||
|
*.pbxuser
|
||||||
|
*.perspectivev3
|
||||||
|
**/*sync/
|
||||||
|
.sconsign.dblite
|
||||||
|
.tags*
|
||||||
|
**/.vagrant/
|
||||||
|
**/DerivedData/
|
||||||
|
Icon?
|
||||||
|
**/Pods/
|
||||||
|
**/.symlinks/
|
||||||
|
profile
|
||||||
|
xcuserdata
|
||||||
|
**/.generated/
|
||||||
|
Flutter/App.framework
|
||||||
|
Flutter/Flutter.framework
|
||||||
|
Flutter/Flutter.podspec
|
||||||
|
Flutter/Generated.xcconfig
|
||||||
|
Flutter/ephemeral/
|
||||||
|
Flutter/app.flx
|
||||||
|
Flutter/app.zip
|
||||||
|
Flutter/flutter_assets/
|
||||||
|
Flutter/flutter_export_environment.sh
|
||||||
|
ServiceDefinitions.json
|
||||||
|
Runner/GeneratedPluginRegistrant.*
|
||||||
|
|
||||||
|
# Exceptions to above rules.
|
||||||
|
!default.mode1v3
|
||||||
|
!default.mode2v3
|
||||||
|
!default.pbxuser
|
||||||
|
!default.perspectivev3
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
<?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>en</string>
|
||||||
|
<key>CFBundleExecutable</key>
|
||||||
|
<string>App</string>
|
||||||
|
<key>CFBundleIdentifier</key>
|
||||||
|
<string>io.flutter.flutter.app</string>
|
||||||
|
<key>CFBundleInfoDictionaryVersion</key>
|
||||||
|
<string>6.0</string>
|
||||||
|
<key>CFBundleName</key>
|
||||||
|
<string>App</string>
|
||||||
|
<key>CFBundlePackageType</key>
|
||||||
|
<string>FMWK</string>
|
||||||
|
<key>CFBundleShortVersionString</key>
|
||||||
|
<string>1.0</string>
|
||||||
|
<key>CFBundleSignature</key>
|
||||||
|
<string>????</string>
|
||||||
|
<key>CFBundleVersion</key>
|
||||||
|
<string>1.0</string>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
#include "Generated.xcconfig"
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
#include "Generated.xcconfig"
|
||||||
@@ -0,0 +1,662 @@
|
|||||||
|
// !$*UTF8*$!
|
||||||
|
{
|
||||||
|
archiveVersion = 1;
|
||||||
|
classes = {
|
||||||
|
};
|
||||||
|
objectVersion = 60;
|
||||||
|
objects = {
|
||||||
|
|
||||||
|
/* Begin PBXBuildFile section */
|
||||||
|
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
|
||||||
|
331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; };
|
||||||
|
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
|
||||||
|
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
|
||||||
|
7884E8682EC3CC0700C636F2 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7884E8672EC3CC0400C636F2 /* SceneDelegate.swift */; };
|
||||||
|
78A318202AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage in Frameworks */ = {isa = PBXBuildFile; productRef = 78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */; };
|
||||||
|
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
|
||||||
|
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
|
||||||
|
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
|
||||||
|
/* End PBXBuildFile section */
|
||||||
|
|
||||||
|
/* Begin PBXContainerItemProxy section */
|
||||||
|
331C8085294A63A400263BE5 /* PBXContainerItemProxy */ = {
|
||||||
|
isa = PBXContainerItemProxy;
|
||||||
|
containerPortal = 97C146E61CF9000F007C117D /* Project object */;
|
||||||
|
proxyType = 1;
|
||||||
|
remoteGlobalIDString = 97C146ED1CF9000F007C117D;
|
||||||
|
remoteInfo = Runner;
|
||||||
|
};
|
||||||
|
/* End PBXContainerItemProxy section */
|
||||||
|
|
||||||
|
/* Begin PBXCopyFilesBuildPhase section */
|
||||||
|
9705A1C41CF9048500538489 /* Embed Frameworks */ = {
|
||||||
|
isa = PBXCopyFilesBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
dstPath = "";
|
||||||
|
dstSubfolderSpec = 10;
|
||||||
|
files = (
|
||||||
|
);
|
||||||
|
name = "Embed Frameworks";
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
|
/* End PBXCopyFilesBuildPhase section */
|
||||||
|
|
||||||
|
/* Begin PBXFileReference section */
|
||||||
|
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; };
|
||||||
|
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; };
|
||||||
|
331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = "<group>"; };
|
||||||
|
331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
|
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
|
||||||
|
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = "<group>"; };
|
||||||
|
74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
||||||
|
7884E8672EC3CC0400C636F2 /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = "<group>"; };
|
||||||
|
78E0A7A72DC9AD7400C4905E /* FlutterGeneratedPluginSwiftPackage */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = FlutterGeneratedPluginSwiftPackage; path = Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage; sourceTree = "<group>"; };
|
||||||
|
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; };
|
||||||
|
9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = "<group>"; };
|
||||||
|
9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = "<group>"; };
|
||||||
|
97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
|
97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
|
||||||
|
97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
||||||
|
97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
|
||||||
|
97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||||
|
/* End PBXFileReference section */
|
||||||
|
|
||||||
|
/* Begin PBXFrameworksBuildPhase section */
|
||||||
|
97C146EB1CF9000F007C117D /* Frameworks */ = {
|
||||||
|
isa = PBXFrameworksBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
78A318202AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage in Frameworks */,
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
|
/* End PBXFrameworksBuildPhase section */
|
||||||
|
|
||||||
|
/* Begin PBXGroup section */
|
||||||
|
331C8082294A63A400263BE5 /* RunnerTests */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
331C807B294A618700263BE5 /* RunnerTests.swift */,
|
||||||
|
);
|
||||||
|
path = RunnerTests;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
9740EEB11CF90186004384FC /* Flutter */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
78E0A7A72DC9AD7400C4905E /* FlutterGeneratedPluginSwiftPackage */,
|
||||||
|
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */,
|
||||||
|
9740EEB21CF90195004384FC /* Debug.xcconfig */,
|
||||||
|
7AFA3C8E1D35360C0083082E /* Release.xcconfig */,
|
||||||
|
9740EEB31CF90195004384FC /* Generated.xcconfig */,
|
||||||
|
);
|
||||||
|
name = Flutter;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
97C146E51CF9000F007C117D = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
9740EEB11CF90186004384FC /* Flutter */,
|
||||||
|
97C146F01CF9000F007C117D /* Runner */,
|
||||||
|
97C146EF1CF9000F007C117D /* Products */,
|
||||||
|
331C8082294A63A400263BE5 /* RunnerTests */,
|
||||||
|
);
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
97C146EF1CF9000F007C117D /* Products */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
97C146EE1CF9000F007C117D /* Runner.app */,
|
||||||
|
331C8081294A63A400263BE5 /* RunnerTests.xctest */,
|
||||||
|
);
|
||||||
|
name = Products;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
97C146F01CF9000F007C117D /* Runner */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
97C146FA1CF9000F007C117D /* Main.storyboard */,
|
||||||
|
97C146FD1CF9000F007C117D /* Assets.xcassets */,
|
||||||
|
97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */,
|
||||||
|
97C147021CF9000F007C117D /* Info.plist */,
|
||||||
|
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */,
|
||||||
|
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */,
|
||||||
|
74858FAE1ED2DC5600515810 /* AppDelegate.swift */,
|
||||||
|
7884E8672EC3CC0400C636F2 /* SceneDelegate.swift */,
|
||||||
|
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */,
|
||||||
|
);
|
||||||
|
path = Runner;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
/* End PBXGroup section */
|
||||||
|
|
||||||
|
/* Begin PBXNativeTarget section */
|
||||||
|
331C8080294A63A400263BE5 /* RunnerTests */ = {
|
||||||
|
isa = PBXNativeTarget;
|
||||||
|
buildConfigurationList = 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */;
|
||||||
|
buildPhases = (
|
||||||
|
331C807D294A63A400263BE5 /* Sources */,
|
||||||
|
331C807F294A63A400263BE5 /* Resources */,
|
||||||
|
);
|
||||||
|
buildRules = (
|
||||||
|
);
|
||||||
|
dependencies = (
|
||||||
|
331C8086294A63A400263BE5 /* PBXTargetDependency */,
|
||||||
|
);
|
||||||
|
name = RunnerTests;
|
||||||
|
productName = RunnerTests;
|
||||||
|
productReference = 331C8081294A63A400263BE5 /* RunnerTests.xctest */;
|
||||||
|
productType = "com.apple.product-type.bundle.unit-test";
|
||||||
|
};
|
||||||
|
97C146ED1CF9000F007C117D /* Runner */ = {
|
||||||
|
isa = PBXNativeTarget;
|
||||||
|
buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
|
||||||
|
buildPhases = (
|
||||||
|
9740EEB61CF901F6004384FC /* Run Script */,
|
||||||
|
97C146EA1CF9000F007C117D /* Sources */,
|
||||||
|
97C146EB1CF9000F007C117D /* Frameworks */,
|
||||||
|
97C146EC1CF9000F007C117D /* Resources */,
|
||||||
|
9705A1C41CF9048500538489 /* Embed Frameworks */,
|
||||||
|
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
|
||||||
|
);
|
||||||
|
buildRules = (
|
||||||
|
);
|
||||||
|
dependencies = (
|
||||||
|
);
|
||||||
|
name = Runner;
|
||||||
|
packageProductDependencies = (
|
||||||
|
78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */,
|
||||||
|
);
|
||||||
|
productName = Runner;
|
||||||
|
productReference = 97C146EE1CF9000F007C117D /* Runner.app */;
|
||||||
|
productType = "com.apple.product-type.application";
|
||||||
|
};
|
||||||
|
/* End PBXNativeTarget section */
|
||||||
|
|
||||||
|
/* Begin PBXProject section */
|
||||||
|
97C146E61CF9000F007C117D /* Project object */ = {
|
||||||
|
isa = PBXProject;
|
||||||
|
attributes = {
|
||||||
|
BuildIndependentTargetsInParallel = YES;
|
||||||
|
LastUpgradeCheck = 2620;
|
||||||
|
ORGANIZATIONNAME = "";
|
||||||
|
TargetAttributes = {
|
||||||
|
331C8080294A63A400263BE5 = {
|
||||||
|
CreatedOnToolsVersion = 14.0;
|
||||||
|
TestTargetID = 97C146ED1CF9000F007C117D;
|
||||||
|
};
|
||||||
|
97C146ED1CF9000F007C117D = {
|
||||||
|
CreatedOnToolsVersion = 7.3.1;
|
||||||
|
LastSwiftMigration = 1100;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */;
|
||||||
|
compatibilityVersion = "Xcode 9.3";
|
||||||
|
developmentRegion = en;
|
||||||
|
hasScannedForEncodings = 0;
|
||||||
|
knownRegions = (
|
||||||
|
en,
|
||||||
|
Base,
|
||||||
|
);
|
||||||
|
mainGroup = 97C146E51CF9000F007C117D;
|
||||||
|
packageReferences = (
|
||||||
|
781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage" */,
|
||||||
|
);
|
||||||
|
productRefGroup = 97C146EF1CF9000F007C117D /* Products */;
|
||||||
|
projectDirPath = "";
|
||||||
|
projectRoot = "";
|
||||||
|
targets = (
|
||||||
|
97C146ED1CF9000F007C117D /* Runner */,
|
||||||
|
331C8080294A63A400263BE5 /* RunnerTests */,
|
||||||
|
);
|
||||||
|
};
|
||||||
|
/* End PBXProject section */
|
||||||
|
|
||||||
|
/* Begin PBXResourcesBuildPhase section */
|
||||||
|
331C807F294A63A400263BE5 /* Resources */ = {
|
||||||
|
isa = PBXResourcesBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
|
97C146EC1CF9000F007C117D /* Resources */ = {
|
||||||
|
isa = PBXResourcesBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */,
|
||||||
|
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */,
|
||||||
|
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */,
|
||||||
|
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */,
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
|
/* End PBXResourcesBuildPhase section */
|
||||||
|
|
||||||
|
/* Begin PBXShellScriptBuildPhase section */
|
||||||
|
3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
|
||||||
|
isa = PBXShellScriptBuildPhase;
|
||||||
|
alwaysOutOfDate = 1;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
);
|
||||||
|
inputPaths = (
|
||||||
|
"${TARGET_BUILD_DIR}/${INFOPLIST_PATH}",
|
||||||
|
);
|
||||||
|
name = "Thin Binary";
|
||||||
|
outputPaths = (
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
shellPath = /bin/sh;
|
||||||
|
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin";
|
||||||
|
};
|
||||||
|
9740EEB61CF901F6004384FC /* Run Script */ = {
|
||||||
|
isa = PBXShellScriptBuildPhase;
|
||||||
|
alwaysOutOfDate = 1;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
);
|
||||||
|
inputPaths = (
|
||||||
|
);
|
||||||
|
name = "Run Script";
|
||||||
|
outputPaths = (
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
shellPath = /bin/sh;
|
||||||
|
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
|
||||||
|
};
|
||||||
|
/* End PBXShellScriptBuildPhase section */
|
||||||
|
|
||||||
|
/* Begin PBXSourcesBuildPhase section */
|
||||||
|
331C807D294A63A400263BE5 /* Sources */ = {
|
||||||
|
isa = PBXSourcesBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */,
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
|
97C146EA1CF9000F007C117D /* Sources */ = {
|
||||||
|
isa = PBXSourcesBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */,
|
||||||
|
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */,
|
||||||
|
7884E8682EC3CC0700C636F2 /* SceneDelegate.swift in Sources */,
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
|
/* End PBXSourcesBuildPhase section */
|
||||||
|
|
||||||
|
/* Begin PBXTargetDependency section */
|
||||||
|
331C8086294A63A400263BE5 /* PBXTargetDependency */ = {
|
||||||
|
isa = PBXTargetDependency;
|
||||||
|
target = 97C146ED1CF9000F007C117D /* Runner */;
|
||||||
|
targetProxy = 331C8085294A63A400263BE5 /* PBXContainerItemProxy */;
|
||||||
|
};
|
||||||
|
/* End PBXTargetDependency section */
|
||||||
|
|
||||||
|
/* Begin PBXVariantGroup section */
|
||||||
|
97C146FA1CF9000F007C117D /* Main.storyboard */ = {
|
||||||
|
isa = PBXVariantGroup;
|
||||||
|
children = (
|
||||||
|
97C146FB1CF9000F007C117D /* Base */,
|
||||||
|
);
|
||||||
|
name = Main.storyboard;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = {
|
||||||
|
isa = PBXVariantGroup;
|
||||||
|
children = (
|
||||||
|
97C147001CF9000F007C117D /* Base */,
|
||||||
|
);
|
||||||
|
name = LaunchScreen.storyboard;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
/* End PBXVariantGroup section */
|
||||||
|
|
||||||
|
/* Begin XCBuildConfiguration section */
|
||||||
|
249021D3217E4FDB00AE95B9 /* Profile */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||||
|
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
|
||||||
|
CLANG_ANALYZER_NONNULL = YES;
|
||||||
|
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||||
|
CLANG_CXX_LIBRARY = "libc++";
|
||||||
|
CLANG_ENABLE_MODULES = YES;
|
||||||
|
CLANG_ENABLE_OBJC_ARC = YES;
|
||||||
|
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||||
|
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_COMMA = YES;
|
||||||
|
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||||
|
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||||
|
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||||
|
CLANG_WARN_EMPTY_BODY = YES;
|
||||||
|
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||||
|
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||||
|
CLANG_WARN_INT_CONVERSION = YES;
|
||||||
|
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||||
|
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||||
|
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||||
|
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||||
|
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||||
|
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||||
|
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||||
|
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||||
|
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||||
|
COPY_PHASE_STRIP = NO;
|
||||||
|
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||||
|
ENABLE_NS_ASSERTIONS = NO;
|
||||||
|
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||||
|
ENABLE_USER_SCRIPT_SANDBOXING = NO;
|
||||||
|
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||||
|
GCC_NO_COMMON_BLOCKS = YES;
|
||||||
|
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||||
|
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||||
|
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||||
|
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||||
|
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||||
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
|
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
|
||||||
|
MTL_ENABLE_DEBUG_INFO = NO;
|
||||||
|
SDKROOT = iphoneos;
|
||||||
|
STRING_CATALOG_GENERATE_SYMBOLS = YES;
|
||||||
|
SUPPORTED_PLATFORMS = iphoneos;
|
||||||
|
TARGETED_DEVICE_FAMILY = "1,2";
|
||||||
|
VALIDATE_PRODUCT = YES;
|
||||||
|
};
|
||||||
|
name = Profile;
|
||||||
|
};
|
||||||
|
249021D4217E4FDB00AE95B9 /* Profile */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
|
||||||
|
buildSettings = {
|
||||||
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
|
CLANG_ENABLE_MODULES = YES;
|
||||||
|
CODE_SIGN_IDENTITY = "Apple Development";
|
||||||
|
CODE_SIGN_STYLE = Automatic;
|
||||||
|
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
||||||
|
DEVELOPMENT_TEAM = 37Z4F445LJ;
|
||||||
|
ENABLE_BITCODE = NO;
|
||||||
|
INFOPLIST_FILE = Runner/Info.plist;
|
||||||
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
|
"$(inherited)",
|
||||||
|
"@executable_path/Frameworks",
|
||||||
|
);
|
||||||
|
PRODUCT_BUNDLE_IDENTIFIER = com.davmar.ingtrakapp;
|
||||||
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||||
|
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||||
|
SWIFT_VERSION = 5.0;
|
||||||
|
VERSIONING_SYSTEM = "apple-generic";
|
||||||
|
};
|
||||||
|
name = Profile;
|
||||||
|
};
|
||||||
|
331C8088294A63A400263BE5 /* Debug */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||||
|
CODE_SIGN_STYLE = Automatic;
|
||||||
|
CURRENT_PROJECT_VERSION = 1;
|
||||||
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
|
MARKETING_VERSION = 1.0;
|
||||||
|
PRODUCT_BUNDLE_IDENTIFIER = com.ingtrak.myapp.RunnerTests;
|
||||||
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
|
||||||
|
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||||
|
SWIFT_VERSION = 5.0;
|
||||||
|
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
|
||||||
|
};
|
||||||
|
name = Debug;
|
||||||
|
};
|
||||||
|
331C8089294A63A400263BE5 /* Release */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||||
|
CODE_SIGN_STYLE = Automatic;
|
||||||
|
CURRENT_PROJECT_VERSION = 1;
|
||||||
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
|
MARKETING_VERSION = 1.0;
|
||||||
|
PRODUCT_BUNDLE_IDENTIFIER = com.ingtrak.myapp.RunnerTests;
|
||||||
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
SWIFT_VERSION = 5.0;
|
||||||
|
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
|
||||||
|
};
|
||||||
|
name = Release;
|
||||||
|
};
|
||||||
|
331C808A294A63A400263BE5 /* Profile */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||||
|
CODE_SIGN_STYLE = Automatic;
|
||||||
|
CURRENT_PROJECT_VERSION = 1;
|
||||||
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
|
MARKETING_VERSION = 1.0;
|
||||||
|
PRODUCT_BUNDLE_IDENTIFIER = com.ingtrak.myapp.RunnerTests;
|
||||||
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
SWIFT_VERSION = 5.0;
|
||||||
|
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
|
||||||
|
};
|
||||||
|
name = Profile;
|
||||||
|
};
|
||||||
|
97C147031CF9000F007C117D /* Debug */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||||
|
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
|
||||||
|
CLANG_ANALYZER_NONNULL = YES;
|
||||||
|
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||||
|
CLANG_CXX_LIBRARY = "libc++";
|
||||||
|
CLANG_ENABLE_MODULES = YES;
|
||||||
|
CLANG_ENABLE_OBJC_ARC = YES;
|
||||||
|
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||||
|
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_COMMA = YES;
|
||||||
|
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||||
|
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||||
|
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||||
|
CLANG_WARN_EMPTY_BODY = YES;
|
||||||
|
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||||
|
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||||
|
CLANG_WARN_INT_CONVERSION = YES;
|
||||||
|
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||||
|
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||||
|
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||||
|
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||||
|
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||||
|
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||||
|
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||||
|
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||||
|
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||||
|
COPY_PHASE_STRIP = NO;
|
||||||
|
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||||
|
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||||
|
ENABLE_TESTABILITY = YES;
|
||||||
|
ENABLE_USER_SCRIPT_SANDBOXING = NO;
|
||||||
|
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||||
|
GCC_DYNAMIC_NO_PIC = NO;
|
||||||
|
GCC_NO_COMMON_BLOCKS = YES;
|
||||||
|
GCC_OPTIMIZATION_LEVEL = 0;
|
||||||
|
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||||
|
"DEBUG=1",
|
||||||
|
"$(inherited)",
|
||||||
|
);
|
||||||
|
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||||
|
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||||
|
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||||
|
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||||
|
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||||
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
|
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
|
||||||
|
MTL_ENABLE_DEBUG_INFO = YES;
|
||||||
|
ONLY_ACTIVE_ARCH = YES;
|
||||||
|
SDKROOT = iphoneos;
|
||||||
|
STRING_CATALOG_GENERATE_SYMBOLS = YES;
|
||||||
|
TARGETED_DEVICE_FAMILY = "1,2";
|
||||||
|
};
|
||||||
|
name = Debug;
|
||||||
|
};
|
||||||
|
97C147041CF9000F007C117D /* Release */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||||
|
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
|
||||||
|
CLANG_ANALYZER_NONNULL = YES;
|
||||||
|
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||||
|
CLANG_CXX_LIBRARY = "libc++";
|
||||||
|
CLANG_ENABLE_MODULES = YES;
|
||||||
|
CLANG_ENABLE_OBJC_ARC = YES;
|
||||||
|
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||||
|
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_COMMA = YES;
|
||||||
|
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||||
|
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||||
|
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||||
|
CLANG_WARN_EMPTY_BODY = YES;
|
||||||
|
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||||
|
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||||
|
CLANG_WARN_INT_CONVERSION = YES;
|
||||||
|
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||||
|
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||||
|
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||||
|
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||||
|
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||||
|
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||||
|
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||||
|
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||||
|
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||||
|
COPY_PHASE_STRIP = NO;
|
||||||
|
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||||
|
ENABLE_NS_ASSERTIONS = NO;
|
||||||
|
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||||
|
ENABLE_USER_SCRIPT_SANDBOXING = NO;
|
||||||
|
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||||
|
GCC_NO_COMMON_BLOCKS = YES;
|
||||||
|
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||||
|
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||||
|
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||||
|
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||||
|
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||||
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
|
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
|
||||||
|
MTL_ENABLE_DEBUG_INFO = NO;
|
||||||
|
SDKROOT = iphoneos;
|
||||||
|
STRING_CATALOG_GENERATE_SYMBOLS = YES;
|
||||||
|
SUPPORTED_PLATFORMS = iphoneos;
|
||||||
|
SWIFT_COMPILATION_MODE = wholemodule;
|
||||||
|
SWIFT_OPTIMIZATION_LEVEL = "-O";
|
||||||
|
TARGETED_DEVICE_FAMILY = "1,2";
|
||||||
|
VALIDATE_PRODUCT = YES;
|
||||||
|
};
|
||||||
|
name = Release;
|
||||||
|
};
|
||||||
|
97C147061CF9000F007C117D /* Debug */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
|
||||||
|
buildSettings = {
|
||||||
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
|
CLANG_ENABLE_MODULES = YES;
|
||||||
|
CODE_SIGN_IDENTITY = "Apple Development";
|
||||||
|
CODE_SIGN_STYLE = Automatic;
|
||||||
|
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
||||||
|
DEVELOPMENT_TEAM = 37Z4F445LJ;
|
||||||
|
ENABLE_BITCODE = NO;
|
||||||
|
INFOPLIST_FILE = Runner/Info.plist;
|
||||||
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
|
"$(inherited)",
|
||||||
|
"@executable_path/Frameworks",
|
||||||
|
);
|
||||||
|
PRODUCT_BUNDLE_IDENTIFIER = com.davmar.ingtrakapp;
|
||||||
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||||
|
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||||
|
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||||
|
SWIFT_VERSION = 5.0;
|
||||||
|
VERSIONING_SYSTEM = "apple-generic";
|
||||||
|
};
|
||||||
|
name = Debug;
|
||||||
|
};
|
||||||
|
97C147071CF9000F007C117D /* Release */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
|
||||||
|
buildSettings = {
|
||||||
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
|
CLANG_ENABLE_MODULES = YES;
|
||||||
|
CODE_SIGN_IDENTITY = "Apple Development";
|
||||||
|
CODE_SIGN_STYLE = Automatic;
|
||||||
|
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
||||||
|
DEVELOPMENT_TEAM = 37Z4F445LJ;
|
||||||
|
ENABLE_BITCODE = NO;
|
||||||
|
INFOPLIST_FILE = Runner/Info.plist;
|
||||||
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
|
"$(inherited)",
|
||||||
|
"@executable_path/Frameworks",
|
||||||
|
);
|
||||||
|
PRODUCT_BUNDLE_IDENTIFIER = com.davmar.ingtrakapp;
|
||||||
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||||
|
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||||
|
SWIFT_VERSION = 5.0;
|
||||||
|
VERSIONING_SYSTEM = "apple-generic";
|
||||||
|
};
|
||||||
|
name = Release;
|
||||||
|
};
|
||||||
|
/* End XCBuildConfiguration section */
|
||||||
|
|
||||||
|
/* Begin XCConfigurationList section */
|
||||||
|
331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = {
|
||||||
|
isa = XCConfigurationList;
|
||||||
|
buildConfigurations = (
|
||||||
|
331C8088294A63A400263BE5 /* Debug */,
|
||||||
|
331C8089294A63A400263BE5 /* Release */,
|
||||||
|
331C808A294A63A400263BE5 /* Profile */,
|
||||||
|
);
|
||||||
|
defaultConfigurationIsVisible = 0;
|
||||||
|
defaultConfigurationName = Release;
|
||||||
|
};
|
||||||
|
97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = {
|
||||||
|
isa = XCConfigurationList;
|
||||||
|
buildConfigurations = (
|
||||||
|
97C147031CF9000F007C117D /* Debug */,
|
||||||
|
97C147041CF9000F007C117D /* Release */,
|
||||||
|
249021D3217E4FDB00AE95B9 /* Profile */,
|
||||||
|
);
|
||||||
|
defaultConfigurationIsVisible = 0;
|
||||||
|
defaultConfigurationName = Release;
|
||||||
|
};
|
||||||
|
97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = {
|
||||||
|
isa = XCConfigurationList;
|
||||||
|
buildConfigurations = (
|
||||||
|
97C147061CF9000F007C117D /* Debug */,
|
||||||
|
97C147071CF9000F007C117D /* Release */,
|
||||||
|
249021D4217E4FDB00AE95B9 /* Profile */,
|
||||||
|
);
|
||||||
|
defaultConfigurationIsVisible = 0;
|
||||||
|
defaultConfigurationName = Release;
|
||||||
|
};
|
||||||
|
/* End XCConfigurationList section */
|
||||||
|
|
||||||
|
/* Begin XCLocalSwiftPackageReference section */
|
||||||
|
781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage" */ = {
|
||||||
|
isa = XCLocalSwiftPackageReference;
|
||||||
|
relativePath = Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage;
|
||||||
|
};
|
||||||
|
/* End XCLocalSwiftPackageReference section */
|
||||||
|
|
||||||
|
/* Begin XCSwiftPackageProductDependency section */
|
||||||
|
78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */ = {
|
||||||
|
isa = XCSwiftPackageProductDependency;
|
||||||
|
productName = FlutterGeneratedPluginSwiftPackage;
|
||||||
|
};
|
||||||
|
/* End XCSwiftPackageProductDependency section */
|
||||||
|
};
|
||||||
|
rootObject = 97C146E61CF9000F007C117D /* Project object */;
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<Workspace
|
||||||
|
version = "1.0">
|
||||||
|
<FileRef
|
||||||
|
location = "self:">
|
||||||
|
</FileRef>
|
||||||
|
</Workspace>
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
<?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>IDEDidComputeMac32BitWarning</key>
|
||||||
|
<true/>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
<?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>PreviewsEnabled</key>
|
||||||
|
<false/>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
{
|
||||||
|
"pins" : [
|
||||||
|
{
|
||||||
|
"identity" : "dkcamera",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/zhangao0086/DKCamera",
|
||||||
|
"state" : {
|
||||||
|
"branch" : "master",
|
||||||
|
"revision" : "5c691d11014b910aff69f960475d70e65d9dcc96"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identity" : "dkimagepickercontroller",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/zhangao0086/DKImagePickerController",
|
||||||
|
"state" : {
|
||||||
|
"branch" : "4.3.9",
|
||||||
|
"revision" : "0bdfeacefa308545adde07bef86e349186335915"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identity" : "dkphotogallery",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/zhangao0086/DKPhotoGallery",
|
||||||
|
"state" : {
|
||||||
|
"branch" : "master",
|
||||||
|
"revision" : "311c1bc7a94f1538f82773a79c84374b12a2ef3d"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identity" : "sdwebimage",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/SDWebImage/SDWebImage",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "2de3a496eaf6df9a1312862adcfd54acd73c39c0",
|
||||||
|
"version" : "5.21.7"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identity" : "swiftygif",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/kirualex/SwiftyGif.git",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "4430cbc148baa3907651d40562d96325426f409a",
|
||||||
|
"version" : "5.4.5"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identity" : "tocropviewcontroller",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/TimOliver/TOCropViewController",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "d4a6d8100f4b886fdbc8ae399bf144ff3e9afb7e",
|
||||||
|
"version" : "2.8.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"version" : 2
|
||||||
|
}
|
||||||
@@ -0,0 +1,119 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<Scheme
|
||||||
|
LastUpgradeVersion = "2620"
|
||||||
|
version = "1.7">
|
||||||
|
<BuildAction
|
||||||
|
parallelizeBuildables = "YES"
|
||||||
|
buildImplicitDependencies = "YES">
|
||||||
|
<PreActions>
|
||||||
|
<ExecutionAction
|
||||||
|
ActionType = "Xcode.IDEStandardExecutionActionsCore.ExecutionActionType.ShellScriptAction">
|
||||||
|
<ActionContent
|
||||||
|
title = "Run Prepare Flutter Framework Script"
|
||||||
|
scriptText = "/bin/sh "$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh" prepare ">
|
||||||
|
<EnvironmentBuildable>
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
|
||||||
|
BuildableName = "Runner.app"
|
||||||
|
BlueprintName = "Runner"
|
||||||
|
ReferencedContainer = "container:Runner.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</EnvironmentBuildable>
|
||||||
|
</ActionContent>
|
||||||
|
</ExecutionAction>
|
||||||
|
</PreActions>
|
||||||
|
<BuildActionEntries>
|
||||||
|
<BuildActionEntry
|
||||||
|
buildForTesting = "YES"
|
||||||
|
buildForRunning = "YES"
|
||||||
|
buildForProfiling = "YES"
|
||||||
|
buildForArchiving = "YES"
|
||||||
|
buildForAnalyzing = "YES">
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
|
||||||
|
BuildableName = "Runner.app"
|
||||||
|
BlueprintName = "Runner"
|
||||||
|
ReferencedContainer = "container:Runner.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</BuildActionEntry>
|
||||||
|
</BuildActionEntries>
|
||||||
|
</BuildAction>
|
||||||
|
<TestAction
|
||||||
|
buildConfiguration = "Debug"
|
||||||
|
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||||
|
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||||
|
customLLDBInitFile = "$(SRCROOT)/Flutter/ephemeral/flutter_lldbinit"
|
||||||
|
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||||
|
<MacroExpansion>
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
|
||||||
|
BuildableName = "Runner.app"
|
||||||
|
BlueprintName = "Runner"
|
||||||
|
ReferencedContainer = "container:Runner.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</MacroExpansion>
|
||||||
|
<Testables>
|
||||||
|
<TestableReference
|
||||||
|
skipped = "NO"
|
||||||
|
parallelizable = "YES">
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "331C8080294A63A400263BE5"
|
||||||
|
BuildableName = "RunnerTests.xctest"
|
||||||
|
BlueprintName = "RunnerTests"
|
||||||
|
ReferencedContainer = "container:Runner.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</TestableReference>
|
||||||
|
</Testables>
|
||||||
|
</TestAction>
|
||||||
|
<LaunchAction
|
||||||
|
buildConfiguration = "Release"
|
||||||
|
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||||
|
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||||
|
customLLDBInitFile = "$(SRCROOT)/Flutter/ephemeral/flutter_lldbinit"
|
||||||
|
launchStyle = "0"
|
||||||
|
useCustomWorkingDirectory = "NO"
|
||||||
|
ignoresPersistentStateOnLaunch = "NO"
|
||||||
|
debugDocumentVersioning = "YES"
|
||||||
|
debugServiceExtension = "internal"
|
||||||
|
enableGPUValidationMode = "1"
|
||||||
|
allowLocationSimulation = "YES">
|
||||||
|
<BuildableProductRunnable
|
||||||
|
runnableDebuggingMode = "0">
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
|
||||||
|
BuildableName = "Runner.app"
|
||||||
|
BlueprintName = "Runner"
|
||||||
|
ReferencedContainer = "container:Runner.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</BuildableProductRunnable>
|
||||||
|
</LaunchAction>
|
||||||
|
<ProfileAction
|
||||||
|
buildConfiguration = "Profile"
|
||||||
|
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||||
|
savedToolIdentifier = ""
|
||||||
|
useCustomWorkingDirectory = "NO"
|
||||||
|
debugDocumentVersioning = "YES">
|
||||||
|
<BuildableProductRunnable
|
||||||
|
runnableDebuggingMode = "0">
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
|
||||||
|
BuildableName = "Runner.app"
|
||||||
|
BlueprintName = "Runner"
|
||||||
|
ReferencedContainer = "container:Runner.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</BuildableProductRunnable>
|
||||||
|
</ProfileAction>
|
||||||
|
<AnalyzeAction
|
||||||
|
buildConfiguration = "Debug">
|
||||||
|
</AnalyzeAction>
|
||||||
|
<ArchiveAction
|
||||||
|
buildConfiguration = "Release"
|
||||||
|
revealArchiveInOrganizer = "YES">
|
||||||
|
</ArchiveAction>
|
||||||
|
</Scheme>
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<Workspace
|
||||||
|
version = "1.0">
|
||||||
|
<FileRef
|
||||||
|
location = "group:Runner.xcodeproj">
|
||||||
|
</FileRef>
|
||||||
|
</Workspace>
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
<?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>IDEDidComputeMac32BitWarning</key>
|
||||||
|
<true/>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
<?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>PreviewsEnabled</key>
|
||||||
|
<false/>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
{
|
||||||
|
"pins" : [
|
||||||
|
{
|
||||||
|
"identity" : "dkcamera",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/zhangao0086/DKCamera",
|
||||||
|
"state" : {
|
||||||
|
"branch" : "master",
|
||||||
|
"revision" : "5c691d11014b910aff69f960475d70e65d9dcc96"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identity" : "dkimagepickercontroller",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/zhangao0086/DKImagePickerController",
|
||||||
|
"state" : {
|
||||||
|
"branch" : "4.3.9",
|
||||||
|
"revision" : "0bdfeacefa308545adde07bef86e349186335915"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identity" : "dkphotogallery",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/zhangao0086/DKPhotoGallery",
|
||||||
|
"state" : {
|
||||||
|
"branch" : "master",
|
||||||
|
"revision" : "311c1bc7a94f1538f82773a79c84374b12a2ef3d"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identity" : "sdwebimage",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/SDWebImage/SDWebImage",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "2de3a496eaf6df9a1312862adcfd54acd73c39c0",
|
||||||
|
"version" : "5.21.7"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identity" : "swiftygif",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/kirualex/SwiftyGif.git",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "4430cbc148baa3907651d40562d96325426f409a",
|
||||||
|
"version" : "5.4.5"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"identity" : "tocropviewcontroller",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/TimOliver/TOCropViewController",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "d4a6d8100f4b886fdbc8ae399bf144ff3e9afb7e",
|
||||||
|
"version" : "2.8.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"version" : 2
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
import Flutter
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
@main
|
||||||
|
@objc class AppDelegate: FlutterAppDelegate, FlutterImplicitEngineDelegate {
|
||||||
|
override func application(
|
||||||
|
_ application: UIApplication,
|
||||||
|
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
|
||||||
|
) -> Bool {
|
||||||
|
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
|
||||||
|
}
|
||||||
|
|
||||||
|
func didInitializeImplicitFlutterEngine(_ engineBridge: FlutterImplicitEngineBridge) {
|
||||||
|
GeneratedPluginRegistrant.register(with: engineBridge.pluginRegistry)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,122 @@
|
|||||||
|
{
|
||||||
|
"images" : [
|
||||||
|
{
|
||||||
|
"size" : "20x20",
|
||||||
|
"idiom" : "iphone",
|
||||||
|
"filename" : "[email protected]",
|
||||||
|
"scale" : "2x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"size" : "20x20",
|
||||||
|
"idiom" : "iphone",
|
||||||
|
"filename" : "[email protected]",
|
||||||
|
"scale" : "3x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"size" : "29x29",
|
||||||
|
"idiom" : "iphone",
|
||||||
|
"filename" : "[email protected]",
|
||||||
|
"scale" : "1x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"size" : "29x29",
|
||||||
|
"idiom" : "iphone",
|
||||||
|
"filename" : "[email protected]",
|
||||||
|
"scale" : "2x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"size" : "29x29",
|
||||||
|
"idiom" : "iphone",
|
||||||
|
"filename" : "[email protected]",
|
||||||
|
"scale" : "3x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"size" : "40x40",
|
||||||
|
"idiom" : "iphone",
|
||||||
|
"filename" : "[email protected]",
|
||||||
|
"scale" : "2x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"size" : "40x40",
|
||||||
|
"idiom" : "iphone",
|
||||||
|
"filename" : "[email protected]",
|
||||||
|
"scale" : "3x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"size" : "60x60",
|
||||||
|
"idiom" : "iphone",
|
||||||
|
"filename" : "[email protected]",
|
||||||
|
"scale" : "2x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"size" : "60x60",
|
||||||
|
"idiom" : "iphone",
|
||||||
|
"filename" : "[email protected]",
|
||||||
|
"scale" : "3x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"size" : "20x20",
|
||||||
|
"idiom" : "ipad",
|
||||||
|
"filename" : "[email protected]",
|
||||||
|
"scale" : "1x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"size" : "20x20",
|
||||||
|
"idiom" : "ipad",
|
||||||
|
"filename" : "[email protected]",
|
||||||
|
"scale" : "2x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"size" : "29x29",
|
||||||
|
"idiom" : "ipad",
|
||||||
|
"filename" : "[email protected]",
|
||||||
|
"scale" : "1x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"size" : "29x29",
|
||||||
|
"idiom" : "ipad",
|
||||||
|
"filename" : "[email protected]",
|
||||||
|
"scale" : "2x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"size" : "40x40",
|
||||||
|
"idiom" : "ipad",
|
||||||
|
"filename" : "[email protected]",
|
||||||
|
"scale" : "1x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"size" : "40x40",
|
||||||
|
"idiom" : "ipad",
|
||||||
|
"filename" : "[email protected]",
|
||||||
|
"scale" : "2x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"size" : "76x76",
|
||||||
|
"idiom" : "ipad",
|
||||||
|
"filename" : "[email protected]",
|
||||||
|
"scale" : "1x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"size" : "76x76",
|
||||||
|
"idiom" : "ipad",
|
||||||
|
"filename" : "[email protected]",
|
||||||
|
"scale" : "2x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"size" : "83.5x83.5",
|
||||||
|
"idiom" : "ipad",
|
||||||
|
"filename" : "[email protected]",
|
||||||
|
"scale" : "2x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"size" : "1024x1024",
|
||||||
|
"idiom" : "ios-marketing",
|
||||||
|
"filename" : "[email protected]",
|
||||||
|
"scale" : "1x"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"version" : 1,
|
||||||
|
"author" : "xcode"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 295 B |
|
After Width: | Height: | Size: 406 B |
|
After Width: | Height: | Size: 450 B |
|
After Width: | Height: | Size: 282 B |
|
After Width: | Height: | Size: 462 B |
|
After Width: | Height: | Size: 704 B |
|
After Width: | Height: | Size: 406 B |
|
After Width: | Height: | Size: 586 B |
|
After Width: | Height: | Size: 862 B |
|
After Width: | Height: | Size: 862 B |
|
After Width: | Height: | Size: 1.6 KiB |
|
After Width: | Height: | Size: 762 B |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 1.4 KiB |
@@ -0,0 +1,23 @@
|
|||||||
|
{
|
||||||
|
"images" : [
|
||||||
|
{
|
||||||
|
"idiom" : "universal",
|
||||||
|
"filename" : "LaunchImage.png",
|
||||||
|
"scale" : "1x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idiom" : "universal",
|
||||||
|
"filename" : "[email protected]",
|
||||||
|
"scale" : "2x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idiom" : "universal",
|
||||||
|
"filename" : "[email protected]",
|
||||||
|
"scale" : "3x"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"version" : 1,
|
||||||
|
"author" : "xcode"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
After Width: | Height: | Size: 68 B |
|
After Width: | Height: | Size: 68 B |
|
After Width: | Height: | Size: 68 B |
@@ -0,0 +1,5 @@
|
|||||||
|
# Launch Screen Assets
|
||||||
|
|
||||||
|
You can customize the launch screen with your own desired assets by replacing the image files in this directory.
|
||||||
|
|
||||||
|
You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images.
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="12121" systemVersion="16G29" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
|
||||||
|
<dependencies>
|
||||||
|
<deployment identifier="iOS"/>
|
||||||
|
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="12089"/>
|
||||||
|
</dependencies>
|
||||||
|
<scenes>
|
||||||
|
<!--View Controller-->
|
||||||
|
<scene sceneID="EHf-IW-A2E">
|
||||||
|
<objects>
|
||||||
|
<viewController id="01J-lp-oVM" sceneMemberID="viewController">
|
||||||
|
<layoutGuides>
|
||||||
|
<viewControllerLayoutGuide type="top" id="Ydg-fD-yQy"/>
|
||||||
|
<viewControllerLayoutGuide type="bottom" id="xbc-2k-c8Z"/>
|
||||||
|
</layoutGuides>
|
||||||
|
<view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
|
||||||
|
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||||
|
<subviews>
|
||||||
|
<imageView opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" image="LaunchImage" translatesAutoresizingMaskIntoConstraints="NO" id="YRO-k0-Ey4">
|
||||||
|
</imageView>
|
||||||
|
</subviews>
|
||||||
|
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||||
|
<constraints>
|
||||||
|
<constraint firstItem="YRO-k0-Ey4" firstAttribute="centerX" secondItem="Ze5-6b-2t3" secondAttribute="centerX" id="1a2-6s-vTC"/>
|
||||||
|
<constraint firstItem="YRO-k0-Ey4" firstAttribute="centerY" secondItem="Ze5-6b-2t3" secondAttribute="centerY" id="4X2-HB-R7a"/>
|
||||||
|
</constraints>
|
||||||
|
</view>
|
||||||
|
</viewController>
|
||||||
|
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||||
|
</objects>
|
||||||
|
<point key="canvasLocation" x="53" y="375"/>
|
||||||
|
</scene>
|
||||||
|
</scenes>
|
||||||
|
<resources>
|
||||||
|
<image name="LaunchImage" width="168" height="185"/>
|
||||||
|
</resources>
|
||||||
|
</document>
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="24506" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="BYZ-38-t0r">
|
||||||
|
<device id="retina6_12" orientation="portrait" appearance="light"/>
|
||||||
|
<dependencies>
|
||||||
|
<deployment identifier="iOS"/>
|
||||||
|
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="24504"/>
|
||||||
|
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||||
|
</dependencies>
|
||||||
|
<scenes>
|
||||||
|
<!--Flutter View Controller-->
|
||||||
|
<scene sceneID="tne-QT-ifu">
|
||||||
|
<objects>
|
||||||
|
<viewController id="BYZ-38-t0r" customClass="FlutterViewController" sceneMemberID="viewController">
|
||||||
|
<layoutGuides>
|
||||||
|
<viewControllerLayoutGuide type="top" id="y3c-jy-aDJ"/>
|
||||||
|
<viewControllerLayoutGuide type="bottom" id="wfy-db-euE"/>
|
||||||
|
</layoutGuides>
|
||||||
|
<view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
|
||||||
|
<rect key="frame" x="0.0" y="0.0" width="393" height="852"/>
|
||||||
|
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||||
|
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||||
|
</view>
|
||||||
|
</viewController>
|
||||||
|
<placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
|
||||||
|
</objects>
|
||||||
|
<point key="canvasLocation" x="-101" y="12"/>
|
||||||
|
</scene>
|
||||||
|
</scenes>
|
||||||
|
</document>
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
<?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>CADisableMinimumFrameDurationOnPhone</key>
|
||||||
|
<true/>
|
||||||
|
<key>CFBundleDevelopmentRegion</key>
|
||||||
|
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
||||||
|
<key>CFBundleDisplayName</key>
|
||||||
|
<string>Myapp</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>myapp</string>
|
||||||
|
<key>CFBundlePackageType</key>
|
||||||
|
<string>APPL</string>
|
||||||
|
<key>CFBundleShortVersionString</key>
|
||||||
|
<string>$(FLUTTER_BUILD_NAME)</string>
|
||||||
|
<key>CFBundleSignature</key>
|
||||||
|
<string>????</string>
|
||||||
|
<key>CFBundleVersion</key>
|
||||||
|
<string>$(FLUTTER_BUILD_NUMBER)</string>
|
||||||
|
<key>LSRequiresIPhoneOS</key>
|
||||||
|
<true/>
|
||||||
|
<key>UIApplicationSceneManifest</key>
|
||||||
|
<dict>
|
||||||
|
<key>UIApplicationSupportsMultipleScenes</key>
|
||||||
|
<false/>
|
||||||
|
<key>UISceneConfigurations</key>
|
||||||
|
<dict>
|
||||||
|
<key>UIWindowSceneSessionRoleApplication</key>
|
||||||
|
<array>
|
||||||
|
<dict>
|
||||||
|
<key>UISceneClassName</key>
|
||||||
|
<string>UIWindowScene</string>
|
||||||
|
<key>UISceneConfigurationName</key>
|
||||||
|
<string>flutter</string>
|
||||||
|
<key>UISceneDelegateClassName</key>
|
||||||
|
<string>$(PRODUCT_MODULE_NAME).SceneDelegate</string>
|
||||||
|
<key>UISceneStoryboardFile</key>
|
||||||
|
<string>Main</string>
|
||||||
|
</dict>
|
||||||
|
</array>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<key>UIApplicationSupportsIndirectInputEvents</key>
|
||||||
|
<true/>
|
||||||
|
<key>UILaunchStoryboardName</key>
|
||||||
|
<string>LaunchScreen</string>
|
||||||
|
<key>UIMainStoryboardFile</key>
|
||||||
|
<string>Main</string>
|
||||||
|
<key>UISupportedInterfaceOrientations</key>
|
||||||
|
<array>
|
||||||
|
<string>UIInterfaceOrientationPortrait</string>
|
||||||
|
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||||
|
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||||
|
</array>
|
||||||
|
<key>UISupportedInterfaceOrientations~ipad</key>
|
||||||
|
<array>
|
||||||
|
<string>UIInterfaceOrientationPortrait</string>
|
||||||
|
<string>UIInterfaceOrientationPortraitUpsideDown</string>
|
||||||
|
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||||
|
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||||
|
</array>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
#import "GeneratedPluginRegistrant.h"
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
import Flutter
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
class SceneDelegate: FlutterSceneDelegate {
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
import Flutter
|
||||||
|
import UIKit
|
||||||
|
import XCTest
|
||||||
|
|
||||||
|
class RunnerTests: XCTestCase {
|
||||||
|
|
||||||
|
func testExample() {
|
||||||
|
// If you add code to the Runner application, consider adding tests here.
|
||||||
|
// See https://developer.apple.com/documentation/xctest for more information about using XCTest.
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
**/dgph
|
||||||
|
*.mode1v3
|
||||||
|
*.mode2v3
|
||||||
|
*.moved-aside
|
||||||
|
*.pbxuser
|
||||||
|
*.perspectivev3
|
||||||
|
**/*sync/
|
||||||
|
.sconsign.dblite
|
||||||
|
.tags*
|
||||||
|
**/.vagrant/
|
||||||
|
**/DerivedData/
|
||||||
|
Icon?
|
||||||
|
**/Pods/
|
||||||
|
**/.symlinks/
|
||||||
|
profile
|
||||||
|
xcuserdata
|
||||||
|
**/.generated/
|
||||||
|
Flutter/App.framework
|
||||||
|
Flutter/Flutter.framework
|
||||||
|
Flutter/Flutter.podspec
|
||||||
|
Flutter/Generated.xcconfig
|
||||||
|
Flutter/ephemeral/
|
||||||
|
Flutter/app.flx
|
||||||
|
Flutter/app.zip
|
||||||
|
Flutter/flutter_assets/
|
||||||
|
Flutter/flutter_export_environment.sh
|
||||||
|
ServiceDefinitions.json
|
||||||
|
Runner/GeneratedPluginRegistrant.*
|
||||||
|
|
||||||
|
# Exceptions to above rules.
|
||||||
|
!default.mode1v3
|
||||||
|
!default.mode2v3
|
||||||
|
!default.pbxuser
|
||||||
|
!default.perspectivev3
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
<?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>en</string>
|
||||||
|
<key>CFBundleExecutable</key>
|
||||||
|
<string>App</string>
|
||||||
|
<key>CFBundleIdentifier</key>
|
||||||
|
<string>io.flutter.flutter.app</string>
|
||||||
|
<key>CFBundleInfoDictionaryVersion</key>
|
||||||
|
<string>6.0</string>
|
||||||
|
<key>CFBundleName</key>
|
||||||
|
<string>App</string>
|
||||||
|
<key>CFBundlePackageType</key>
|
||||||
|
<string>FMWK</string>
|
||||||
|
<key>CFBundleShortVersionString</key>
|
||||||
|
<string>1.0</string>
|
||||||
|
<key>CFBundleSignature</key>
|
||||||
|
<string>????</string>
|
||||||
|
<key>CFBundleVersion</key>
|
||||||
|
<string>1.0</string>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
#include "Generated.xcconfig"
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
#include "Generated.xcconfig"
|
||||||
@@ -0,0 +1,647 @@
|
|||||||
|
// !$*UTF8*$!
|
||||||
|
{
|
||||||
|
archiveVersion = 1;
|
||||||
|
classes = {
|
||||||
|
};
|
||||||
|
objectVersion = 54;
|
||||||
|
objects = {
|
||||||
|
|
||||||
|
/* Begin PBXBuildFile section */
|
||||||
|
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
|
||||||
|
331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; };
|
||||||
|
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
|
||||||
|
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
|
||||||
|
7884E8682EC3CC0700C636F2 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7884E8672EC3CC0400C636F2 /* SceneDelegate.swift */; };
|
||||||
|
78A318202AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage in Frameworks */ = {isa = PBXBuildFile; productRef = 78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */; };
|
||||||
|
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
|
||||||
|
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
|
||||||
|
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
|
||||||
|
/* End PBXBuildFile section */
|
||||||
|
|
||||||
|
/* Begin PBXContainerItemProxy section */
|
||||||
|
331C8085294A63A400263BE5 /* PBXContainerItemProxy */ = {
|
||||||
|
isa = PBXContainerItemProxy;
|
||||||
|
containerPortal = 97C146E61CF9000F007C117D /* Project object */;
|
||||||
|
proxyType = 1;
|
||||||
|
remoteGlobalIDString = 97C146ED1CF9000F007C117D;
|
||||||
|
remoteInfo = Runner;
|
||||||
|
};
|
||||||
|
/* End PBXContainerItemProxy section */
|
||||||
|
|
||||||
|
/* Begin PBXCopyFilesBuildPhase section */
|
||||||
|
9705A1C41CF9048500538489 /* Embed Frameworks */ = {
|
||||||
|
isa = PBXCopyFilesBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
dstPath = "";
|
||||||
|
dstSubfolderSpec = 10;
|
||||||
|
files = (
|
||||||
|
);
|
||||||
|
name = "Embed Frameworks";
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
|
/* End PBXCopyFilesBuildPhase section */
|
||||||
|
|
||||||
|
/* Begin PBXFileReference section */
|
||||||
|
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; };
|
||||||
|
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; };
|
||||||
|
331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = "<group>"; };
|
||||||
|
331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
|
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
|
||||||
|
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = "<group>"; };
|
||||||
|
74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
||||||
|
7884E8672EC3CC0400C636F2 /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = "<group>"; };
|
||||||
|
78E0A7A72DC9AD7400C4905E /* FlutterGeneratedPluginSwiftPackage */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = FlutterGeneratedPluginSwiftPackage; path = Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage; sourceTree = "<group>"; };
|
||||||
|
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; };
|
||||||
|
9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = "<group>"; };
|
||||||
|
9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = "<group>"; };
|
||||||
|
97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
|
97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
|
||||||
|
97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
||||||
|
97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
|
||||||
|
97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||||
|
/* End PBXFileReference section */
|
||||||
|
|
||||||
|
/* Begin PBXFrameworksBuildPhase section */
|
||||||
|
97C146EB1CF9000F007C117D /* Frameworks */ = {
|
||||||
|
isa = PBXFrameworksBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
78A318202AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage in Frameworks */,
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
|
/* End PBXFrameworksBuildPhase section */
|
||||||
|
|
||||||
|
/* Begin PBXGroup section */
|
||||||
|
331C8082294A63A400263BE5 /* RunnerTests */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
331C807B294A618700263BE5 /* RunnerTests.swift */,
|
||||||
|
);
|
||||||
|
path = RunnerTests;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
9740EEB11CF90186004384FC /* Flutter */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
78E0A7A72DC9AD7400C4905E /* FlutterGeneratedPluginSwiftPackage */,
|
||||||
|
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */,
|
||||||
|
9740EEB21CF90195004384FC /* Debug.xcconfig */,
|
||||||
|
7AFA3C8E1D35360C0083082E /* Release.xcconfig */,
|
||||||
|
9740EEB31CF90195004384FC /* Generated.xcconfig */,
|
||||||
|
);
|
||||||
|
name = Flutter;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
97C146E51CF9000F007C117D = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
9740EEB11CF90186004384FC /* Flutter */,
|
||||||
|
97C146F01CF9000F007C117D /* Runner */,
|
||||||
|
97C146EF1CF9000F007C117D /* Products */,
|
||||||
|
331C8082294A63A400263BE5 /* RunnerTests */,
|
||||||
|
);
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
97C146EF1CF9000F007C117D /* Products */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
97C146EE1CF9000F007C117D /* Runner.app */,
|
||||||
|
331C8081294A63A400263BE5 /* RunnerTests.xctest */,
|
||||||
|
);
|
||||||
|
name = Products;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
97C146F01CF9000F007C117D /* Runner */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
97C146FA1CF9000F007C117D /* Main.storyboard */,
|
||||||
|
97C146FD1CF9000F007C117D /* Assets.xcassets */,
|
||||||
|
97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */,
|
||||||
|
97C147021CF9000F007C117D /* Info.plist */,
|
||||||
|
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */,
|
||||||
|
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */,
|
||||||
|
74858FAE1ED2DC5600515810 /* AppDelegate.swift */,
|
||||||
|
7884E8672EC3CC0400C636F2 /* SceneDelegate.swift */,
|
||||||
|
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */,
|
||||||
|
);
|
||||||
|
path = Runner;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
/* End PBXGroup section */
|
||||||
|
|
||||||
|
/* Begin PBXNativeTarget section */
|
||||||
|
331C8080294A63A400263BE5 /* RunnerTests */ = {
|
||||||
|
isa = PBXNativeTarget;
|
||||||
|
buildConfigurationList = 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */;
|
||||||
|
buildPhases = (
|
||||||
|
331C807D294A63A400263BE5 /* Sources */,
|
||||||
|
331C807F294A63A400263BE5 /* Resources */,
|
||||||
|
);
|
||||||
|
buildRules = (
|
||||||
|
);
|
||||||
|
dependencies = (
|
||||||
|
331C8086294A63A400263BE5 /* PBXTargetDependency */,
|
||||||
|
);
|
||||||
|
name = RunnerTests;
|
||||||
|
productName = RunnerTests;
|
||||||
|
productReference = 331C8081294A63A400263BE5 /* RunnerTests.xctest */;
|
||||||
|
productType = "com.apple.product-type.bundle.unit-test";
|
||||||
|
};
|
||||||
|
97C146ED1CF9000F007C117D /* Runner */ = {
|
||||||
|
isa = PBXNativeTarget;
|
||||||
|
buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
|
||||||
|
buildPhases = (
|
||||||
|
9740EEB61CF901F6004384FC /* Run Script */,
|
||||||
|
97C146EA1CF9000F007C117D /* Sources */,
|
||||||
|
97C146EB1CF9000F007C117D /* Frameworks */,
|
||||||
|
97C146EC1CF9000F007C117D /* Resources */,
|
||||||
|
9705A1C41CF9048500538489 /* Embed Frameworks */,
|
||||||
|
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
|
||||||
|
);
|
||||||
|
buildRules = (
|
||||||
|
);
|
||||||
|
dependencies = (
|
||||||
|
);
|
||||||
|
name = Runner;
|
||||||
|
packageProductDependencies = (
|
||||||
|
78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */,
|
||||||
|
);
|
||||||
|
productName = Runner;
|
||||||
|
productReference = 97C146EE1CF9000F007C117D /* Runner.app */;
|
||||||
|
productType = "com.apple.product-type.application";
|
||||||
|
};
|
||||||
|
/* End PBXNativeTarget section */
|
||||||
|
|
||||||
|
/* Begin PBXProject section */
|
||||||
|
97C146E61CF9000F007C117D /* Project object */ = {
|
||||||
|
isa = PBXProject;
|
||||||
|
attributes = {
|
||||||
|
BuildIndependentTargetsInParallel = YES;
|
||||||
|
LastUpgradeCheck = 1510;
|
||||||
|
ORGANIZATIONNAME = "";
|
||||||
|
TargetAttributes = {
|
||||||
|
331C8080294A63A400263BE5 = {
|
||||||
|
CreatedOnToolsVersion = 14.0;
|
||||||
|
TestTargetID = 97C146ED1CF9000F007C117D;
|
||||||
|
};
|
||||||
|
97C146ED1CF9000F007C117D = {
|
||||||
|
CreatedOnToolsVersion = 7.3.1;
|
||||||
|
LastSwiftMigration = 1100;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */;
|
||||||
|
compatibilityVersion = "Xcode 9.3";
|
||||||
|
developmentRegion = en;
|
||||||
|
hasScannedForEncodings = 0;
|
||||||
|
knownRegions = (
|
||||||
|
en,
|
||||||
|
Base,
|
||||||
|
);
|
||||||
|
mainGroup = 97C146E51CF9000F007C117D;
|
||||||
|
packageReferences = (
|
||||||
|
781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage" */,
|
||||||
|
);
|
||||||
|
productRefGroup = 97C146EF1CF9000F007C117D /* Products */;
|
||||||
|
projectDirPath = "";
|
||||||
|
projectRoot = "";
|
||||||
|
targets = (
|
||||||
|
97C146ED1CF9000F007C117D /* Runner */,
|
||||||
|
331C8080294A63A400263BE5 /* RunnerTests */,
|
||||||
|
);
|
||||||
|
};
|
||||||
|
/* End PBXProject section */
|
||||||
|
|
||||||
|
/* Begin PBXResourcesBuildPhase section */
|
||||||
|
331C807F294A63A400263BE5 /* Resources */ = {
|
||||||
|
isa = PBXResourcesBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
|
97C146EC1CF9000F007C117D /* Resources */ = {
|
||||||
|
isa = PBXResourcesBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */,
|
||||||
|
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */,
|
||||||
|
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */,
|
||||||
|
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */,
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
|
/* End PBXResourcesBuildPhase section */
|
||||||
|
|
||||||
|
/* Begin PBXShellScriptBuildPhase section */
|
||||||
|
3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
|
||||||
|
isa = PBXShellScriptBuildPhase;
|
||||||
|
alwaysOutOfDate = 1;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
);
|
||||||
|
inputPaths = (
|
||||||
|
"${TARGET_BUILD_DIR}/${INFOPLIST_PATH}",
|
||||||
|
);
|
||||||
|
name = "Thin Binary";
|
||||||
|
outputPaths = (
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
shellPath = /bin/sh;
|
||||||
|
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin";
|
||||||
|
};
|
||||||
|
9740EEB61CF901F6004384FC /* Run Script */ = {
|
||||||
|
isa = PBXShellScriptBuildPhase;
|
||||||
|
alwaysOutOfDate = 1;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
);
|
||||||
|
inputPaths = (
|
||||||
|
);
|
||||||
|
name = "Run Script";
|
||||||
|
outputPaths = (
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
shellPath = /bin/sh;
|
||||||
|
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
|
||||||
|
};
|
||||||
|
/* End PBXShellScriptBuildPhase section */
|
||||||
|
|
||||||
|
/* Begin PBXSourcesBuildPhase section */
|
||||||
|
331C807D294A63A400263BE5 /* Sources */ = {
|
||||||
|
isa = PBXSourcesBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */,
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
|
97C146EA1CF9000F007C117D /* Sources */ = {
|
||||||
|
isa = PBXSourcesBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */,
|
||||||
|
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */,
|
||||||
|
7884E8682EC3CC0700C636F2 /* SceneDelegate.swift in Sources */,
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
|
/* End PBXSourcesBuildPhase section */
|
||||||
|
|
||||||
|
/* Begin PBXTargetDependency section */
|
||||||
|
331C8086294A63A400263BE5 /* PBXTargetDependency */ = {
|
||||||
|
isa = PBXTargetDependency;
|
||||||
|
target = 97C146ED1CF9000F007C117D /* Runner */;
|
||||||
|
targetProxy = 331C8085294A63A400263BE5 /* PBXContainerItemProxy */;
|
||||||
|
};
|
||||||
|
/* End PBXTargetDependency section */
|
||||||
|
|
||||||
|
/* Begin PBXVariantGroup section */
|
||||||
|
97C146FA1CF9000F007C117D /* Main.storyboard */ = {
|
||||||
|
isa = PBXVariantGroup;
|
||||||
|
children = (
|
||||||
|
97C146FB1CF9000F007C117D /* Base */,
|
||||||
|
);
|
||||||
|
name = Main.storyboard;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = {
|
||||||
|
isa = PBXVariantGroup;
|
||||||
|
children = (
|
||||||
|
97C147001CF9000F007C117D /* Base */,
|
||||||
|
);
|
||||||
|
name = LaunchScreen.storyboard;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
/* End PBXVariantGroup section */
|
||||||
|
|
||||||
|
/* Begin XCBuildConfiguration section */
|
||||||
|
249021D3217E4FDB00AE95B9 /* Profile */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||||
|
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
|
||||||
|
CLANG_ANALYZER_NONNULL = YES;
|
||||||
|
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||||
|
CLANG_CXX_LIBRARY = "libc++";
|
||||||
|
CLANG_ENABLE_MODULES = YES;
|
||||||
|
CLANG_ENABLE_OBJC_ARC = YES;
|
||||||
|
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||||
|
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_COMMA = YES;
|
||||||
|
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||||
|
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||||
|
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||||
|
CLANG_WARN_EMPTY_BODY = YES;
|
||||||
|
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||||
|
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||||
|
CLANG_WARN_INT_CONVERSION = YES;
|
||||||
|
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||||
|
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||||
|
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||||
|
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||||
|
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||||
|
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||||
|
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||||
|
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||||
|
COPY_PHASE_STRIP = NO;
|
||||||
|
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||||
|
ENABLE_NS_ASSERTIONS = NO;
|
||||||
|
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||||
|
ENABLE_USER_SCRIPT_SANDBOXING = NO;
|
||||||
|
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||||
|
GCC_NO_COMMON_BLOCKS = YES;
|
||||||
|
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||||
|
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||||
|
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||||
|
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||||
|
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||||
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
|
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
|
||||||
|
MTL_ENABLE_DEBUG_INFO = NO;
|
||||||
|
SDKROOT = iphoneos;
|
||||||
|
STRING_CATALOG_GENERATE_SYMBOLS = YES;
|
||||||
|
SUPPORTED_PLATFORMS = iphoneos;
|
||||||
|
TARGETED_DEVICE_FAMILY = "1,2";
|
||||||
|
VALIDATE_PRODUCT = YES;
|
||||||
|
};
|
||||||
|
name = Profile;
|
||||||
|
};
|
||||||
|
249021D4217E4FDB00AE95B9 /* Profile */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
|
||||||
|
buildSettings = {
|
||||||
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
|
CLANG_ENABLE_MODULES = YES;
|
||||||
|
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
||||||
|
ENABLE_BITCODE = NO;
|
||||||
|
INFOPLIST_FILE = Runner/Info.plist;
|
||||||
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
|
"$(inherited)",
|
||||||
|
"@executable_path/Frameworks",
|
||||||
|
);
|
||||||
|
PRODUCT_BUNDLE_IDENTIFIER = com.ingtrak.myapp;
|
||||||
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||||
|
SWIFT_VERSION = 5.0;
|
||||||
|
VERSIONING_SYSTEM = "apple-generic";
|
||||||
|
};
|
||||||
|
name = Profile;
|
||||||
|
};
|
||||||
|
331C8088294A63A400263BE5 /* Debug */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||||
|
CODE_SIGN_STYLE = Automatic;
|
||||||
|
CURRENT_PROJECT_VERSION = 1;
|
||||||
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
|
MARKETING_VERSION = 1.0;
|
||||||
|
PRODUCT_BUNDLE_IDENTIFIER = com.ingtrak.myapp.RunnerTests;
|
||||||
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
|
||||||
|
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||||
|
SWIFT_VERSION = 5.0;
|
||||||
|
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
|
||||||
|
};
|
||||||
|
name = Debug;
|
||||||
|
};
|
||||||
|
331C8089294A63A400263BE5 /* Release */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||||
|
CODE_SIGN_STYLE = Automatic;
|
||||||
|
CURRENT_PROJECT_VERSION = 1;
|
||||||
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
|
MARKETING_VERSION = 1.0;
|
||||||
|
PRODUCT_BUNDLE_IDENTIFIER = com.ingtrak.myapp.RunnerTests;
|
||||||
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
SWIFT_VERSION = 5.0;
|
||||||
|
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
|
||||||
|
};
|
||||||
|
name = Release;
|
||||||
|
};
|
||||||
|
331C808A294A63A400263BE5 /* Profile */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||||
|
CODE_SIGN_STYLE = Automatic;
|
||||||
|
CURRENT_PROJECT_VERSION = 1;
|
||||||
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
|
MARKETING_VERSION = 1.0;
|
||||||
|
PRODUCT_BUNDLE_IDENTIFIER = com.ingtrak.myapp.RunnerTests;
|
||||||
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
SWIFT_VERSION = 5.0;
|
||||||
|
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
|
||||||
|
};
|
||||||
|
name = Profile;
|
||||||
|
};
|
||||||
|
97C147031CF9000F007C117D /* Debug */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||||
|
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
|
||||||
|
CLANG_ANALYZER_NONNULL = YES;
|
||||||
|
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||||
|
CLANG_CXX_LIBRARY = "libc++";
|
||||||
|
CLANG_ENABLE_MODULES = YES;
|
||||||
|
CLANG_ENABLE_OBJC_ARC = YES;
|
||||||
|
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||||
|
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_COMMA = YES;
|
||||||
|
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||||
|
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||||
|
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||||
|
CLANG_WARN_EMPTY_BODY = YES;
|
||||||
|
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||||
|
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||||
|
CLANG_WARN_INT_CONVERSION = YES;
|
||||||
|
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||||
|
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||||
|
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||||
|
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||||
|
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||||
|
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||||
|
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||||
|
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||||
|
COPY_PHASE_STRIP = NO;
|
||||||
|
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||||
|
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||||
|
ENABLE_TESTABILITY = YES;
|
||||||
|
ENABLE_USER_SCRIPT_SANDBOXING = NO;
|
||||||
|
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||||
|
GCC_DYNAMIC_NO_PIC = NO;
|
||||||
|
GCC_NO_COMMON_BLOCKS = YES;
|
||||||
|
GCC_OPTIMIZATION_LEVEL = 0;
|
||||||
|
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||||
|
"DEBUG=1",
|
||||||
|
"$(inherited)",
|
||||||
|
);
|
||||||
|
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||||
|
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||||
|
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||||
|
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||||
|
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||||
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
|
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
|
||||||
|
MTL_ENABLE_DEBUG_INFO = YES;
|
||||||
|
ONLY_ACTIVE_ARCH = YES;
|
||||||
|
SDKROOT = iphoneos;
|
||||||
|
STRING_CATALOG_GENERATE_SYMBOLS = YES;
|
||||||
|
TARGETED_DEVICE_FAMILY = "1,2";
|
||||||
|
};
|
||||||
|
name = Debug;
|
||||||
|
};
|
||||||
|
97C147041CF9000F007C117D /* Release */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||||
|
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
|
||||||
|
CLANG_ANALYZER_NONNULL = YES;
|
||||||
|
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||||
|
CLANG_CXX_LIBRARY = "libc++";
|
||||||
|
CLANG_ENABLE_MODULES = YES;
|
||||||
|
CLANG_ENABLE_OBJC_ARC = YES;
|
||||||
|
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||||
|
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_COMMA = YES;
|
||||||
|
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||||
|
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||||
|
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||||
|
CLANG_WARN_EMPTY_BODY = YES;
|
||||||
|
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||||
|
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||||
|
CLANG_WARN_INT_CONVERSION = YES;
|
||||||
|
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||||
|
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||||
|
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||||
|
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||||
|
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||||
|
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||||
|
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||||
|
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||||
|
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||||
|
COPY_PHASE_STRIP = NO;
|
||||||
|
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||||
|
ENABLE_NS_ASSERTIONS = NO;
|
||||||
|
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||||
|
ENABLE_USER_SCRIPT_SANDBOXING = NO;
|
||||||
|
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||||
|
GCC_NO_COMMON_BLOCKS = YES;
|
||||||
|
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||||
|
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||||
|
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||||
|
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||||
|
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||||
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
|
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
|
||||||
|
MTL_ENABLE_DEBUG_INFO = NO;
|
||||||
|
SDKROOT = iphoneos;
|
||||||
|
STRING_CATALOG_GENERATE_SYMBOLS = YES;
|
||||||
|
SUPPORTED_PLATFORMS = iphoneos;
|
||||||
|
SWIFT_COMPILATION_MODE = wholemodule;
|
||||||
|
SWIFT_OPTIMIZATION_LEVEL = "-O";
|
||||||
|
TARGETED_DEVICE_FAMILY = "1,2";
|
||||||
|
VALIDATE_PRODUCT = YES;
|
||||||
|
};
|
||||||
|
name = Release;
|
||||||
|
};
|
||||||
|
97C147061CF9000F007C117D /* Debug */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
|
||||||
|
buildSettings = {
|
||||||
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
|
CLANG_ENABLE_MODULES = YES;
|
||||||
|
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
||||||
|
ENABLE_BITCODE = NO;
|
||||||
|
INFOPLIST_FILE = Runner/Info.plist;
|
||||||
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
|
"$(inherited)",
|
||||||
|
"@executable_path/Frameworks",
|
||||||
|
);
|
||||||
|
PRODUCT_BUNDLE_IDENTIFIER = com.ingtrak.myapp;
|
||||||
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||||
|
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||||
|
SWIFT_VERSION = 5.0;
|
||||||
|
VERSIONING_SYSTEM = "apple-generic";
|
||||||
|
};
|
||||||
|
name = Debug;
|
||||||
|
};
|
||||||
|
97C147071CF9000F007C117D /* Release */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
|
||||||
|
buildSettings = {
|
||||||
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
|
CLANG_ENABLE_MODULES = YES;
|
||||||
|
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
||||||
|
ENABLE_BITCODE = NO;
|
||||||
|
INFOPLIST_FILE = Runner/Info.plist;
|
||||||
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
|
"$(inherited)",
|
||||||
|
"@executable_path/Frameworks",
|
||||||
|
);
|
||||||
|
PRODUCT_BUNDLE_IDENTIFIER = com.ingtrak.myapp;
|
||||||
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||||
|
SWIFT_VERSION = 5.0;
|
||||||
|
VERSIONING_SYSTEM = "apple-generic";
|
||||||
|
};
|
||||||
|
name = Release;
|
||||||
|
};
|
||||||
|
/* End XCBuildConfiguration section */
|
||||||
|
|
||||||
|
/* Begin XCConfigurationList section */
|
||||||
|
331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = {
|
||||||
|
isa = XCConfigurationList;
|
||||||
|
buildConfigurations = (
|
||||||
|
331C8088294A63A400263BE5 /* Debug */,
|
||||||
|
331C8089294A63A400263BE5 /* Release */,
|
||||||
|
331C808A294A63A400263BE5 /* Profile */,
|
||||||
|
);
|
||||||
|
defaultConfigurationIsVisible = 0;
|
||||||
|
defaultConfigurationName = Release;
|
||||||
|
};
|
||||||
|
97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = {
|
||||||
|
isa = XCConfigurationList;
|
||||||
|
buildConfigurations = (
|
||||||
|
97C147031CF9000F007C117D /* Debug */,
|
||||||
|
97C147041CF9000F007C117D /* Release */,
|
||||||
|
249021D3217E4FDB00AE95B9 /* Profile */,
|
||||||
|
);
|
||||||
|
defaultConfigurationIsVisible = 0;
|
||||||
|
defaultConfigurationName = Release;
|
||||||
|
};
|
||||||
|
97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = {
|
||||||
|
isa = XCConfigurationList;
|
||||||
|
buildConfigurations = (
|
||||||
|
97C147061CF9000F007C117D /* Debug */,
|
||||||
|
97C147071CF9000F007C117D /* Release */,
|
||||||
|
249021D4217E4FDB00AE95B9 /* Profile */,
|
||||||
|
);
|
||||||
|
defaultConfigurationIsVisible = 0;
|
||||||
|
defaultConfigurationName = Release;
|
||||||
|
};
|
||||||
|
/* End XCConfigurationList section */
|
||||||
|
|
||||||
|
/* Begin XCLocalSwiftPackageReference section */
|
||||||
|
781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage" */ = {
|
||||||
|
isa = XCLocalSwiftPackageReference;
|
||||||
|
relativePath = Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage;
|
||||||
|
};
|
||||||
|
/* End XCLocalSwiftPackageReference section */
|
||||||
|
|
||||||
|
/* Begin XCSwiftPackageProductDependency section */
|
||||||
|
78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */ = {
|
||||||
|
isa = XCSwiftPackageProductDependency;
|
||||||
|
productName = FlutterGeneratedPluginSwiftPackage;
|
||||||
|
};
|
||||||
|
/* End XCSwiftPackageProductDependency section */
|
||||||
|
};
|
||||||
|
rootObject = 97C146E61CF9000F007C117D /* Project object */;
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<Workspace
|
||||||
|
version = "1.0">
|
||||||
|
<FileRef
|
||||||
|
location = "self:">
|
||||||
|
</FileRef>
|
||||||
|
</Workspace>
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
<?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>IDEDidComputeMac32BitWarning</key>
|
||||||
|
<true/>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
<?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>PreviewsEnabled</key>
|
||||||
|
<false/>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
@@ -0,0 +1,119 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<Scheme
|
||||||
|
LastUpgradeVersion = "1510"
|
||||||
|
version = "1.3">
|
||||||
|
<BuildAction
|
||||||
|
parallelizeBuildables = "YES"
|
||||||
|
buildImplicitDependencies = "YES">
|
||||||
|
<PreActions>
|
||||||
|
<ExecutionAction
|
||||||
|
ActionType = "Xcode.IDEStandardExecutionActionsCore.ExecutionActionType.ShellScriptAction">
|
||||||
|
<ActionContent
|
||||||
|
title = "Run Prepare Flutter Framework Script"
|
||||||
|
scriptText = "/bin/sh "$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh" prepare ">
|
||||||
|
<EnvironmentBuildable>
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
|
||||||
|
BuildableName = "Runner.app"
|
||||||
|
BlueprintName = "Runner"
|
||||||
|
ReferencedContainer = "container:Runner.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</EnvironmentBuildable>
|
||||||
|
</ActionContent>
|
||||||
|
</ExecutionAction>
|
||||||
|
</PreActions>
|
||||||
|
<BuildActionEntries>
|
||||||
|
<BuildActionEntry
|
||||||
|
buildForTesting = "YES"
|
||||||
|
buildForRunning = "YES"
|
||||||
|
buildForProfiling = "YES"
|
||||||
|
buildForArchiving = "YES"
|
||||||
|
buildForAnalyzing = "YES">
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
|
||||||
|
BuildableName = "Runner.app"
|
||||||
|
BlueprintName = "Runner"
|
||||||
|
ReferencedContainer = "container:Runner.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</BuildActionEntry>
|
||||||
|
</BuildActionEntries>
|
||||||
|
</BuildAction>
|
||||||
|
<TestAction
|
||||||
|
buildConfiguration = "Debug"
|
||||||
|
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||||
|
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||||
|
customLLDBInitFile = "$(SRCROOT)/Flutter/ephemeral/flutter_lldbinit"
|
||||||
|
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||||
|
<MacroExpansion>
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
|
||||||
|
BuildableName = "Runner.app"
|
||||||
|
BlueprintName = "Runner"
|
||||||
|
ReferencedContainer = "container:Runner.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</MacroExpansion>
|
||||||
|
<Testables>
|
||||||
|
<TestableReference
|
||||||
|
skipped = "NO"
|
||||||
|
parallelizable = "YES">
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "331C8080294A63A400263BE5"
|
||||||
|
BuildableName = "RunnerTests.xctest"
|
||||||
|
BlueprintName = "RunnerTests"
|
||||||
|
ReferencedContainer = "container:Runner.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</TestableReference>
|
||||||
|
</Testables>
|
||||||
|
</TestAction>
|
||||||
|
<LaunchAction
|
||||||
|
buildConfiguration = "Debug"
|
||||||
|
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||||
|
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||||
|
customLLDBInitFile = "$(SRCROOT)/Flutter/ephemeral/flutter_lldbinit"
|
||||||
|
launchStyle = "0"
|
||||||
|
useCustomWorkingDirectory = "NO"
|
||||||
|
ignoresPersistentStateOnLaunch = "NO"
|
||||||
|
debugDocumentVersioning = "YES"
|
||||||
|
debugServiceExtension = "internal"
|
||||||
|
enableGPUValidationMode = "1"
|
||||||
|
allowLocationSimulation = "YES">
|
||||||
|
<BuildableProductRunnable
|
||||||
|
runnableDebuggingMode = "0">
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
|
||||||
|
BuildableName = "Runner.app"
|
||||||
|
BlueprintName = "Runner"
|
||||||
|
ReferencedContainer = "container:Runner.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</BuildableProductRunnable>
|
||||||
|
</LaunchAction>
|
||||||
|
<ProfileAction
|
||||||
|
buildConfiguration = "Profile"
|
||||||
|
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||||
|
savedToolIdentifier = ""
|
||||||
|
useCustomWorkingDirectory = "NO"
|
||||||
|
debugDocumentVersioning = "YES">
|
||||||
|
<BuildableProductRunnable
|
||||||
|
runnableDebuggingMode = "0">
|
||||||
|
<BuildableReference
|
||||||
|
BuildableIdentifier = "primary"
|
||||||
|
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
|
||||||
|
BuildableName = "Runner.app"
|
||||||
|
BlueprintName = "Runner"
|
||||||
|
ReferencedContainer = "container:Runner.xcodeproj">
|
||||||
|
</BuildableReference>
|
||||||
|
</BuildableProductRunnable>
|
||||||
|
</ProfileAction>
|
||||||
|
<AnalyzeAction
|
||||||
|
buildConfiguration = "Debug">
|
||||||
|
</AnalyzeAction>
|
||||||
|
<ArchiveAction
|
||||||
|
buildConfiguration = "Release"
|
||||||
|
revealArchiveInOrganizer = "YES">
|
||||||
|
</ArchiveAction>
|
||||||
|
</Scheme>
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<Workspace
|
||||||
|
version = "1.0">
|
||||||
|
<FileRef
|
||||||
|
location = "group:Runner.xcodeproj">
|
||||||
|
</FileRef>
|
||||||
|
</Workspace>
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
<?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>IDEDidComputeMac32BitWarning</key>
|
||||||
|
<true/>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
<?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>PreviewsEnabled</key>
|
||||||
|
<false/>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
import Flutter
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
@main
|
||||||
|
@objc class AppDelegate: FlutterAppDelegate, FlutterImplicitEngineDelegate {
|
||||||
|
override func application(
|
||||||
|
_ application: UIApplication,
|
||||||
|
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
|
||||||
|
) -> Bool {
|
||||||
|
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
|
||||||
|
}
|
||||||
|
|
||||||
|
func didInitializeImplicitFlutterEngine(_ engineBridge: FlutterImplicitEngineBridge) {
|
||||||
|
GeneratedPluginRegistrant.register(with: engineBridge.pluginRegistry)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,122 @@
|
|||||||
|
{
|
||||||
|
"images" : [
|
||||||
|
{
|
||||||
|
"size" : "20x20",
|
||||||
|
"idiom" : "iphone",
|
||||||
|
"filename" : "[email protected]",
|
||||||
|
"scale" : "2x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"size" : "20x20",
|
||||||
|
"idiom" : "iphone",
|
||||||
|
"filename" : "[email protected]",
|
||||||
|
"scale" : "3x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"size" : "29x29",
|
||||||
|
"idiom" : "iphone",
|
||||||
|
"filename" : "[email protected]",
|
||||||
|
"scale" : "1x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"size" : "29x29",
|
||||||
|
"idiom" : "iphone",
|
||||||
|
"filename" : "[email protected]",
|
||||||
|
"scale" : "2x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"size" : "29x29",
|
||||||
|
"idiom" : "iphone",
|
||||||
|
"filename" : "[email protected]",
|
||||||
|
"scale" : "3x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"size" : "40x40",
|
||||||
|
"idiom" : "iphone",
|
||||||
|
"filename" : "[email protected]",
|
||||||
|
"scale" : "2x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"size" : "40x40",
|
||||||
|
"idiom" : "iphone",
|
||||||
|
"filename" : "[email protected]",
|
||||||
|
"scale" : "3x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"size" : "60x60",
|
||||||
|
"idiom" : "iphone",
|
||||||
|
"filename" : "[email protected]",
|
||||||
|
"scale" : "2x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"size" : "60x60",
|
||||||
|
"idiom" : "iphone",
|
||||||
|
"filename" : "[email protected]",
|
||||||
|
"scale" : "3x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"size" : "20x20",
|
||||||
|
"idiom" : "ipad",
|
||||||
|
"filename" : "[email protected]",
|
||||||
|
"scale" : "1x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"size" : "20x20",
|
||||||
|
"idiom" : "ipad",
|
||||||
|
"filename" : "[email protected]",
|
||||||
|
"scale" : "2x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"size" : "29x29",
|
||||||
|
"idiom" : "ipad",
|
||||||
|
"filename" : "[email protected]",
|
||||||
|
"scale" : "1x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"size" : "29x29",
|
||||||
|
"idiom" : "ipad",
|
||||||
|
"filename" : "[email protected]",
|
||||||
|
"scale" : "2x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"size" : "40x40",
|
||||||
|
"idiom" : "ipad",
|
||||||
|
"filename" : "[email protected]",
|
||||||
|
"scale" : "1x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"size" : "40x40",
|
||||||
|
"idiom" : "ipad",
|
||||||
|
"filename" : "[email protected]",
|
||||||
|
"scale" : "2x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"size" : "76x76",
|
||||||
|
"idiom" : "ipad",
|
||||||
|
"filename" : "[email protected]",
|
||||||
|
"scale" : "1x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"size" : "76x76",
|
||||||
|
"idiom" : "ipad",
|
||||||
|
"filename" : "[email protected]",
|
||||||
|
"scale" : "2x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"size" : "83.5x83.5",
|
||||||
|
"idiom" : "ipad",
|
||||||
|
"filename" : "[email protected]",
|
||||||
|
"scale" : "2x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"size" : "1024x1024",
|
||||||
|
"idiom" : "ios-marketing",
|
||||||
|
"filename" : "[email protected]",
|
||||||
|
"scale" : "1x"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"version" : 1,
|
||||||
|
"author" : "xcode"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 295 B |
|
After Width: | Height: | Size: 406 B |
|
After Width: | Height: | Size: 450 B |
|
After Width: | Height: | Size: 282 B |
|
After Width: | Height: | Size: 462 B |
|
After Width: | Height: | Size: 704 B |
|
After Width: | Height: | Size: 406 B |
|
After Width: | Height: | Size: 586 B |
|
After Width: | Height: | Size: 862 B |
|
After Width: | Height: | Size: 862 B |
|
After Width: | Height: | Size: 1.6 KiB |
|
After Width: | Height: | Size: 762 B |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 1.4 KiB |
@@ -0,0 +1,23 @@
|
|||||||
|
{
|
||||||
|
"images" : [
|
||||||
|
{
|
||||||
|
"idiom" : "universal",
|
||||||
|
"filename" : "LaunchImage.png",
|
||||||
|
"scale" : "1x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idiom" : "universal",
|
||||||
|
"filename" : "[email protected]",
|
||||||
|
"scale" : "2x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idiom" : "universal",
|
||||||
|
"filename" : "[email protected]",
|
||||||
|
"scale" : "3x"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"version" : 1,
|
||||||
|
"author" : "xcode"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
After Width: | Height: | Size: 68 B |
|
After Width: | Height: | Size: 68 B |
|
After Width: | Height: | Size: 68 B |
@@ -0,0 +1,5 @@
|
|||||||
|
# Launch Screen Assets
|
||||||
|
|
||||||
|
You can customize the launch screen with your own desired assets by replacing the image files in this directory.
|
||||||
|
|
||||||
|
You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images.
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="12121" systemVersion="16G29" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
|
||||||
|
<dependencies>
|
||||||
|
<deployment identifier="iOS"/>
|
||||||
|
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="12089"/>
|
||||||
|
</dependencies>
|
||||||
|
<scenes>
|
||||||
|
<!--View Controller-->
|
||||||
|
<scene sceneID="EHf-IW-A2E">
|
||||||
|
<objects>
|
||||||
|
<viewController id="01J-lp-oVM" sceneMemberID="viewController">
|
||||||
|
<layoutGuides>
|
||||||
|
<viewControllerLayoutGuide type="top" id="Ydg-fD-yQy"/>
|
||||||
|
<viewControllerLayoutGuide type="bottom" id="xbc-2k-c8Z"/>
|
||||||
|
</layoutGuides>
|
||||||
|
<view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
|
||||||
|
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||||
|
<subviews>
|
||||||
|
<imageView opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" image="LaunchImage" translatesAutoresizingMaskIntoConstraints="NO" id="YRO-k0-Ey4">
|
||||||
|
</imageView>
|
||||||
|
</subviews>
|
||||||
|
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||||
|
<constraints>
|
||||||
|
<constraint firstItem="YRO-k0-Ey4" firstAttribute="centerX" secondItem="Ze5-6b-2t3" secondAttribute="centerX" id="1a2-6s-vTC"/>
|
||||||
|
<constraint firstItem="YRO-k0-Ey4" firstAttribute="centerY" secondItem="Ze5-6b-2t3" secondAttribute="centerY" id="4X2-HB-R7a"/>
|
||||||
|
</constraints>
|
||||||
|
</view>
|
||||||
|
</viewController>
|
||||||
|
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||||
|
</objects>
|
||||||
|
<point key="canvasLocation" x="53" y="375"/>
|
||||||
|
</scene>
|
||||||
|
</scenes>
|
||||||
|
<resources>
|
||||||
|
<image name="LaunchImage" width="168" height="185"/>
|
||||||
|
</resources>
|
||||||
|
</document>
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="10117" systemVersion="15F34" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" initialViewController="BYZ-38-t0r">
|
||||||
|
<dependencies>
|
||||||
|
<deployment identifier="iOS"/>
|
||||||
|
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="10085"/>
|
||||||
|
</dependencies>
|
||||||
|
<scenes>
|
||||||
|
<!--Flutter View Controller-->
|
||||||
|
<scene sceneID="tne-QT-ifu">
|
||||||
|
<objects>
|
||||||
|
<viewController id="BYZ-38-t0r" customClass="FlutterViewController" sceneMemberID="viewController">
|
||||||
|
<layoutGuides>
|
||||||
|
<viewControllerLayoutGuide type="top" id="y3c-jy-aDJ"/>
|
||||||
|
<viewControllerLayoutGuide type="bottom" id="wfy-db-euE"/>
|
||||||
|
</layoutGuides>
|
||||||
|
<view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
|
||||||
|
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
|
||||||
|
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||||
|
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
|
||||||
|
</view>
|
||||||
|
</viewController>
|
||||||
|
<placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
|
||||||
|
</objects>
|
||||||
|
</scene>
|
||||||
|
</scenes>
|
||||||
|
</document>
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
<?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>CADisableMinimumFrameDurationOnPhone</key>
|
||||||
|
<true/>
|
||||||
|
<key>CFBundleDevelopmentRegion</key>
|
||||||
|
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
||||||
|
<key>CFBundleDisplayName</key>
|
||||||
|
<string>Myapp</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>myapp</string>
|
||||||
|
<key>CFBundlePackageType</key>
|
||||||
|
<string>APPL</string>
|
||||||
|
<key>CFBundleShortVersionString</key>
|
||||||
|
<string>$(FLUTTER_BUILD_NAME)</string>
|
||||||
|
<key>CFBundleSignature</key>
|
||||||
|
<string>????</string>
|
||||||
|
<key>CFBundleVersion</key>
|
||||||
|
<string>$(FLUTTER_BUILD_NUMBER)</string>
|
||||||
|
<key>LSRequiresIPhoneOS</key>
|
||||||
|
<true/>
|
||||||
|
<key>UIApplicationSceneManifest</key>
|
||||||
|
<dict>
|
||||||
|
<key>UIApplicationSupportsMultipleScenes</key>
|
||||||
|
<false/>
|
||||||
|
<key>UISceneConfigurations</key>
|
||||||
|
<dict>
|
||||||
|
<key>UIWindowSceneSessionRoleApplication</key>
|
||||||
|
<array>
|
||||||
|
<dict>
|
||||||
|
<key>UISceneClassName</key>
|
||||||
|
<string>UIWindowScene</string>
|
||||||
|
<key>UISceneConfigurationName</key>
|
||||||
|
<string>flutter</string>
|
||||||
|
<key>UISceneDelegateClassName</key>
|
||||||
|
<string>$(PRODUCT_MODULE_NAME).SceneDelegate</string>
|
||||||
|
<key>UISceneStoryboardFile</key>
|
||||||
|
<string>Main</string>
|
||||||
|
</dict>
|
||||||
|
</array>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<key>UIApplicationSupportsIndirectInputEvents</key>
|
||||||
|
<true/>
|
||||||
|
<key>UILaunchStoryboardName</key>
|
||||||
|
<string>LaunchScreen</string>
|
||||||
|
<key>UIMainStoryboardFile</key>
|
||||||
|
<string>Main</string>
|
||||||
|
<key>UISupportedInterfaceOrientations</key>
|
||||||
|
<array>
|
||||||
|
<string>UIInterfaceOrientationPortrait</string>
|
||||||
|
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||||
|
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||||
|
</array>
|
||||||
|
<key>UISupportedInterfaceOrientations~ipad</key>
|
||||||
|
<array>
|
||||||
|
<string>UIInterfaceOrientationPortrait</string>
|
||||||
|
<string>UIInterfaceOrientationPortraitUpsideDown</string>
|
||||||
|
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||||
|
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||||
|
</array>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
#import "GeneratedPluginRegistrant.h"
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
import Flutter
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
class SceneDelegate: FlutterSceneDelegate {
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
import Flutter
|
||||||
|
import UIKit
|
||||||
|
import XCTest
|
||||||
|
|
||||||
|
class RunnerTests: XCTestCase {
|
||||||
|
|
||||||
|
func testExample() {
|
||||||
|
// If you add code to the Runner application, consider adding tests here.
|
||||||
|
// See https://developer.apple.com/documentation/xctest for more information about using XCTest.
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -94,6 +94,8 @@ class HomeFilterWidget {
|
|||||||
this.showAmountIn = true,
|
this.showAmountIn = true,
|
||||||
this.showAmountOut = true,
|
this.showAmountOut = true,
|
||||||
this.showCount = true,
|
this.showCount = true,
|
||||||
|
this.updatedAt = 0,
|
||||||
|
this.deleted = false,
|
||||||
});
|
});
|
||||||
|
|
||||||
final String id;
|
final String id;
|
||||||
@@ -129,6 +131,12 @@ class HomeFilterWidget {
|
|||||||
final bool showAmountOut;
|
final bool showAmountOut;
|
||||||
final bool showCount;
|
final bool showCount;
|
||||||
|
|
||||||
|
/// Epoch ms; used for last-write-wins sync across devices.
|
||||||
|
final int updatedAt;
|
||||||
|
|
||||||
|
/// Soft-delete so removals propagate via sync instead of being recreated.
|
||||||
|
final bool deleted;
|
||||||
|
|
||||||
IconData get icon => HomeWidgetIcons.iconFor(iconId);
|
IconData get icon => HomeWidgetIcons.iconFor(iconId);
|
||||||
|
|
||||||
TransactionFilterSelection get filter => TransactionFilterSelection(
|
TransactionFilterSelection get filter => TransactionFilterSelection(
|
||||||
@@ -161,6 +169,9 @@ class HomeFilterWidget {
|
|||||||
bool? showAmountIn,
|
bool? showAmountIn,
|
||||||
bool? showAmountOut,
|
bool? showAmountOut,
|
||||||
bool? showCount,
|
bool? showCount,
|
||||||
|
int? updatedAt,
|
||||||
|
bool? deleted,
|
||||||
|
bool touchUpdatedAt = false,
|
||||||
}) {
|
}) {
|
||||||
return HomeFilterWidget(
|
return HomeFilterWidget(
|
||||||
id: id ?? this.id,
|
id: id ?? this.id,
|
||||||
@@ -183,6 +194,10 @@ class HomeFilterWidget {
|
|||||||
showAmountIn: showAmountIn ?? this.showAmountIn,
|
showAmountIn: showAmountIn ?? this.showAmountIn,
|
||||||
showAmountOut: showAmountOut ?? this.showAmountOut,
|
showAmountOut: showAmountOut ?? this.showAmountOut,
|
||||||
showCount: showCount ?? this.showCount,
|
showCount: showCount ?? this.showCount,
|
||||||
|
updatedAt: touchUpdatedAt
|
||||||
|
? DateTime.now().millisecondsSinceEpoch
|
||||||
|
: (updatedAt ?? this.updatedAt),
|
||||||
|
deleted: deleted ?? this.deleted,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -208,6 +223,7 @@ class HomeFilterWidget {
|
|||||||
showAmountIn: showIn,
|
showAmountIn: showIn,
|
||||||
showAmountOut: showOut,
|
showAmountOut: showOut,
|
||||||
showCount: true,
|
showCount: true,
|
||||||
|
updatedAt: DateTime.now().millisecondsSinceEpoch,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -236,6 +252,8 @@ class HomeFilterWidget {
|
|||||||
'showAmountIn': showAmountIn,
|
'showAmountIn': showAmountIn,
|
||||||
'showAmountOut': showAmountOut,
|
'showAmountOut': showAmountOut,
|
||||||
'showCount': showCount,
|
'showCount': showCount,
|
||||||
|
'updatedAt': updatedAt,
|
||||||
|
'deleted': deleted,
|
||||||
};
|
};
|
||||||
|
|
||||||
factory HomeFilterWidget.fromJson(Map<String, dynamic> json) {
|
factory HomeFilterWidget.fromJson(Map<String, dynamic> json) {
|
||||||
@@ -302,20 +320,30 @@ class HomeFilterWidget {
|
|||||||
showAmountIn: json['showAmountIn'] as bool? ?? true,
|
showAmountIn: json['showAmountIn'] as bool? ?? true,
|
||||||
showAmountOut: json['showAmountOut'] as bool? ?? true,
|
showAmountOut: json['showAmountOut'] as bool? ?? true,
|
||||||
showCount: json['showCount'] as bool? ?? true,
|
showCount: json['showCount'] as bool? ?? true,
|
||||||
|
updatedAt: asInt(json['updatedAt'] ?? json['updated_at'], 0),
|
||||||
|
deleted: json['deleted'] as bool? ?? false,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Union home widgets by id (local wins on conflict).
|
/// Union home widgets by id with last-write-wins on [HomeFilterWidget.updatedAt].
|
||||||
List<HomeFilterWidget> mergeHomeFilterWidgets(
|
List<HomeFilterWidget> mergeHomeFilterWidgets(
|
||||||
List<HomeFilterWidget> local,
|
List<HomeFilterWidget> local,
|
||||||
List<HomeFilterWidget> remote,
|
List<HomeFilterWidget> remote,
|
||||||
) {
|
) {
|
||||||
final byId = <String, HomeFilterWidget>{
|
final byId = <String, HomeFilterWidget>{};
|
||||||
for (final w in remote) w.id: w,
|
void put(HomeFilterWidget w) {
|
||||||
};
|
final existing = byId[w.id];
|
||||||
|
if (existing == null || w.updatedAt >= existing.updatedAt) {
|
||||||
|
byId[w.id] = w;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (final w in remote) {
|
||||||
|
put(w);
|
||||||
|
}
|
||||||
for (final w in local) {
|
for (final w in local) {
|
||||||
byId[w.id] = w;
|
put(w);
|
||||||
}
|
}
|
||||||
final merged = byId.values.toList()
|
final merged = byId.values.toList()
|
||||||
..sort((a, b) => a.sortOrder.compareTo(b.sortOrder));
|
..sort((a, b) => a.sortOrder.compareTo(b.sortOrder));
|
||||||
|
|||||||
@@ -16,6 +16,8 @@ class OverviewFavourite {
|
|||||||
this.flow = TxFlowFilter.expense,
|
this.flow = TxFlowFilter.expense,
|
||||||
this.barStyle = LabelChartBarStyle.parallel,
|
this.barStyle = LabelChartBarStyle.parallel,
|
||||||
this.invertExpensePerspective = false,
|
this.invertExpensePerspective = false,
|
||||||
|
this.updatedAt = 0,
|
||||||
|
this.deleted = false,
|
||||||
});
|
});
|
||||||
|
|
||||||
final String id;
|
final String id;
|
||||||
@@ -34,6 +36,12 @@ class OverviewFavourite {
|
|||||||
final LabelChartBarStyle barStyle;
|
final LabelChartBarStyle barStyle;
|
||||||
final bool invertExpensePerspective;
|
final bool invertExpensePerspective;
|
||||||
|
|
||||||
|
/// Epoch ms; used for last-write-wins sync across devices.
|
||||||
|
final int updatedAt;
|
||||||
|
|
||||||
|
/// Soft-delete so removals propagate via sync instead of being recreated.
|
||||||
|
final bool deleted;
|
||||||
|
|
||||||
OverviewFavourite copyWith({
|
OverviewFavourite copyWith({
|
||||||
String? id,
|
String? id,
|
||||||
String? name,
|
String? name,
|
||||||
@@ -44,6 +52,9 @@ class OverviewFavourite {
|
|||||||
TxFlowFilter? flow,
|
TxFlowFilter? flow,
|
||||||
LabelChartBarStyle? barStyle,
|
LabelChartBarStyle? barStyle,
|
||||||
bool? invertExpensePerspective,
|
bool? invertExpensePerspective,
|
||||||
|
int? updatedAt,
|
||||||
|
bool? deleted,
|
||||||
|
bool touchUpdatedAt = false,
|
||||||
}) {
|
}) {
|
||||||
return OverviewFavourite(
|
return OverviewFavourite(
|
||||||
id: id ?? this.id,
|
id: id ?? this.id,
|
||||||
@@ -56,6 +67,10 @@ class OverviewFavourite {
|
|||||||
barStyle: barStyle ?? this.barStyle,
|
barStyle: barStyle ?? this.barStyle,
|
||||||
invertExpensePerspective:
|
invertExpensePerspective:
|
||||||
invertExpensePerspective ?? this.invertExpensePerspective,
|
invertExpensePerspective ?? this.invertExpensePerspective,
|
||||||
|
updatedAt: touchUpdatedAt
|
||||||
|
? DateTime.now().millisecondsSinceEpoch
|
||||||
|
: (updatedAt ?? this.updatedAt),
|
||||||
|
deleted: deleted ?? this.deleted,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -69,9 +84,18 @@ class OverviewFavourite {
|
|||||||
'flow': flow.name,
|
'flow': flow.name,
|
||||||
'barStyle': barStyle.name,
|
'barStyle': barStyle.name,
|
||||||
'invertExpensePerspective': invertExpensePerspective,
|
'invertExpensePerspective': invertExpensePerspective,
|
||||||
|
'updatedAt': updatedAt,
|
||||||
|
'deleted': deleted,
|
||||||
};
|
};
|
||||||
|
|
||||||
factory OverviewFavourite.fromJson(Map<String, dynamic> json) {
|
factory OverviewFavourite.fromJson(Map<String, dynamic> json) {
|
||||||
|
final rawUpdated = json['updatedAt'] ?? json['updated_at'];
|
||||||
|
final updatedAt = switch (rawUpdated) {
|
||||||
|
int n => n,
|
||||||
|
num n => n.round(),
|
||||||
|
String s => int.tryParse(s) ?? 0,
|
||||||
|
_ => 0,
|
||||||
|
};
|
||||||
return OverviewFavourite(
|
return OverviewFavourite(
|
||||||
id: json['id'] as String? ?? 'fav_${DateTime.now().millisecondsSinceEpoch}',
|
id: json['id'] as String? ?? 'fav_${DateTime.now().millisecondsSinceEpoch}',
|
||||||
name: (json['name'] as String?)?.trim().isNotEmpty == true
|
name: (json['name'] as String?)?.trim().isNotEmpty == true
|
||||||
@@ -100,6 +124,8 @@ class OverviewFavourite {
|
|||||||
),
|
),
|
||||||
invertExpensePerspective:
|
invertExpensePerspective:
|
||||||
json['invertExpensePerspective'] as bool? ?? false,
|
json['invertExpensePerspective'] as bool? ?? false,
|
||||||
|
updatedAt: updatedAt,
|
||||||
|
deleted: json['deleted'] as bool? ?? false,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -107,3 +133,25 @@ class OverviewFavourite {
|
|||||||
enum OverviewMetricMode { flow, labels }
|
enum OverviewMetricMode { flow, labels }
|
||||||
|
|
||||||
enum OverviewPeriodMode { monthly, yearly }
|
enum OverviewPeriodMode { monthly, yearly }
|
||||||
|
|
||||||
|
/// Union favourites by id with last-write-wins on [OverviewFavourite.updatedAt].
|
||||||
|
List<OverviewFavourite> mergeOverviewFavourites(
|
||||||
|
List<OverviewFavourite> local,
|
||||||
|
List<OverviewFavourite> remote,
|
||||||
|
) {
|
||||||
|
final byId = <String, OverviewFavourite>{};
|
||||||
|
void put(OverviewFavourite fav) {
|
||||||
|
final existing = byId[fav.id];
|
||||||
|
if (existing == null || fav.updatedAt >= existing.updatedAt) {
|
||||||
|
byId[fav.id] = fav;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (final fav in remote) {
|
||||||
|
put(fav);
|
||||||
|
}
|
||||||
|
for (final fav in local) {
|
||||||
|
put(fav);
|
||||||
|
}
|
||||||
|
return byId.values.toList(growable: false);
|
||||||
|
}
|
||||||
|
|||||||
@@ -423,7 +423,9 @@ class BankController extends ChangeNotifier {
|
|||||||
|
|
||||||
final manuals = _collectManualIds(incoming);
|
final manuals = _collectManualIds(incoming);
|
||||||
if (incoming.isNotEmpty) {
|
if (incoming.isNotEmpty) {
|
||||||
_remoteTransactions = mergeTransactions(_remoteTransactions, incoming);
|
_remoteTransactions = dropSettledPendingDuplicates(
|
||||||
|
mergeTransactions(_remoteTransactions, incoming),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
// Strip any local copies that match a pending delete (defensive).
|
// Strip any local copies that match a pending delete (defensive).
|
||||||
if (_pendingRemoteDeletes.isNotEmpty) {
|
if (_pendingRemoteDeletes.isNotEmpty) {
|
||||||
@@ -522,8 +524,10 @@ class BankController extends ChangeNotifier {
|
|||||||
final apiTxs = results[1] as List<BankTransaction>;
|
final apiTxs = results[1] as List<BankTransaction>;
|
||||||
// Bank API is ~89 days. Prefer API rows for overlaps, but keep any
|
// Bank API is ~89 days. Prefer API rows for overlaps, but keep any
|
||||||
// cloud/CSV history that the API window does not include.
|
// cloud/CSV history that the API window does not include.
|
||||||
|
// Pending rows are not kept from cache — they must still be on the feed.
|
||||||
final manuals = _collectManualIds();
|
final manuals = _collectManualIds();
|
||||||
_remoteTransactions = mergeTransactions(apiTxs, _remoteTransactions);
|
_remoteTransactions =
|
||||||
|
mergeApiTransactionsWithCache(apiTxs, _remoteTransactions);
|
||||||
if (!_status.linked) {
|
if (!_status.linked) {
|
||||||
_status = ConnectStatus(
|
_status = ConnectStatus(
|
||||||
status: 'linked',
|
status: 'linked',
|
||||||
|
|||||||
@@ -42,26 +42,40 @@ class PreferencesController extends ChangeNotifier {
|
|||||||
);
|
);
|
||||||
|
|
||||||
List<OverviewFavourite> get overviewFavourites =>
|
List<OverviewFavourite> get overviewFavourites =>
|
||||||
|
List.unmodifiable([
|
||||||
|
for (final fav in _overviewFavourites)
|
||||||
|
if (!fav.deleted) fav,
|
||||||
|
]);
|
||||||
|
|
||||||
|
/// Full list including soft-deleted rows (for PocketBase push).
|
||||||
|
List<OverviewFavourite> get overviewFavouritesForSync =>
|
||||||
List.unmodifiable(_overviewFavourites);
|
List.unmodifiable(_overviewFavourites);
|
||||||
|
|
||||||
List<OverviewFavourite> get displayedOverviewFavourites => [
|
List<OverviewFavourite> get displayedOverviewFavourites => [
|
||||||
for (final fav in _overviewFavourites)
|
for (final fav in _overviewFavourites)
|
||||||
if (fav.display) fav,
|
if (!fav.deleted && fav.display) fav,
|
||||||
];
|
];
|
||||||
|
|
||||||
bool get hasDisplayedOverviewFavourites =>
|
bool get hasDisplayedOverviewFavourites =>
|
||||||
_overviewFavourites.any((f) => f.display);
|
_overviewFavourites.any((f) => !f.deleted && f.display);
|
||||||
|
|
||||||
List<HomeFilterWidget> get homeFilterWidgets =>
|
List<HomeFilterWidget> get homeFilterWidgets =>
|
||||||
|
List.unmodifiable([
|
||||||
|
for (final w in _homeFilterWidgets)
|
||||||
|
if (!w.deleted) w,
|
||||||
|
]);
|
||||||
|
|
||||||
|
/// Full list including soft-deleted rows (for PocketBase push).
|
||||||
|
List<HomeFilterWidget> get homeFilterWidgetsForSync =>
|
||||||
List.unmodifiable(_homeFilterWidgets);
|
List.unmodifiable(_homeFilterWidgets);
|
||||||
|
|
||||||
List<HomeFilterWidget> get displayedHomeFilterWidgets => [
|
List<HomeFilterWidget> get displayedHomeFilterWidgets => [
|
||||||
for (final w in _homeFilterWidgets)
|
for (final w in _homeFilterWidgets)
|
||||||
if (w.display) w,
|
if (!w.deleted && w.display) w,
|
||||||
];
|
];
|
||||||
|
|
||||||
bool get hasDisplayedHomeFilterWidgets =>
|
bool get hasDisplayedHomeFilterWidgets =>
|
||||||
_homeFilterWidgets.any((w) => w.display);
|
_homeFilterWidgets.any((w) => !w.deleted && w.display);
|
||||||
|
|
||||||
HomeBuiltInSections get homeBuiltInSections => _homeBuiltInSections;
|
HomeBuiltInSections get homeBuiltInSections => _homeBuiltInSections;
|
||||||
|
|
||||||
@@ -118,7 +132,10 @@ class PreferencesController extends ChangeNotifier {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<void> addOverviewFavourite(OverviewFavourite favourite) async {
|
Future<void> addOverviewFavourite(OverviewFavourite favourite) async {
|
||||||
_overviewFavourites = [..._overviewFavourites, favourite];
|
final stamped = favourite.updatedAt == 0
|
||||||
|
? favourite.copyWith(touchUpdatedAt: true)
|
||||||
|
: favourite;
|
||||||
|
_overviewFavourites = [..._overviewFavourites, stamped];
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
await _persistFavourites();
|
await _persistFavourites();
|
||||||
}
|
}
|
||||||
@@ -127,18 +144,19 @@ class PreferencesController extends ChangeNotifier {
|
|||||||
final index = _overviewFavourites.indexWhere((f) => f.id == favourite.id);
|
final index = _overviewFavourites.indexWhere((f) => f.id == favourite.id);
|
||||||
if (index < 0) return;
|
if (index < 0) return;
|
||||||
final next = [..._overviewFavourites];
|
final next = [..._overviewFavourites];
|
||||||
next[index] = favourite;
|
next[index] = favourite.copyWith(touchUpdatedAt: true);
|
||||||
_overviewFavourites = next;
|
_overviewFavourites = next;
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
await _persistFavourites();
|
await _persistFavourites();
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> removeOverviewFavourite(String id) async {
|
Future<void> removeOverviewFavourite(String id) async {
|
||||||
final next = [
|
final index = _overviewFavourites.indexWhere((f) => f.id == id);
|
||||||
for (final fav in _overviewFavourites)
|
if (index < 0) return;
|
||||||
if (fav.id != id) fav,
|
final current = _overviewFavourites[index];
|
||||||
];
|
if (current.deleted) return;
|
||||||
if (next.length == _overviewFavourites.length) return;
|
final next = [..._overviewFavourites];
|
||||||
|
next[index] = current.copyWith(deleted: true, touchUpdatedAt: true);
|
||||||
_overviewFavourites = next;
|
_overviewFavourites = next;
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
await _persistFavourites();
|
await _persistFavourites();
|
||||||
@@ -148,7 +166,7 @@ class PreferencesController extends ChangeNotifier {
|
|||||||
final index = _overviewFavourites.indexWhere((f) => f.id == id);
|
final index = _overviewFavourites.indexWhere((f) => f.id == id);
|
||||||
if (index < 0) return;
|
if (index < 0) return;
|
||||||
final current = _overviewFavourites[index];
|
final current = _overviewFavourites[index];
|
||||||
if (current.display == display) return;
|
if (current.deleted || current.display == display) return;
|
||||||
await updateOverviewFavourite(current.copyWith(display: display));
|
await updateOverviewFavourite(current.copyWith(display: display));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -164,16 +182,20 @@ class PreferencesController extends ChangeNotifier {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<void> addHomeFilterWidget(HomeFilterWidget widget) async {
|
Future<void> addHomeFilterWidget(HomeFilterWidget widget) async {
|
||||||
final order = _homeFilterWidgets.isEmpty
|
final order = _homeFilterWidgets.where((w) => !w.deleted).isEmpty
|
||||||
? 0
|
? 0
|
||||||
: _homeFilterWidgets
|
: _homeFilterWidgets
|
||||||
|
.where((w) => !w.deleted)
|
||||||
.map((w) => w.sortOrder)
|
.map((w) => w.sortOrder)
|
||||||
.reduce((a, b) => a > b ? a : b) +
|
.reduce((a, b) => a > b ? a : b) +
|
||||||
1;
|
1;
|
||||||
_homeFilterWidgets = [
|
final stamped = (widget.updatedAt == 0
|
||||||
..._homeFilterWidgets,
|
? widget.copyWith(touchUpdatedAt: true)
|
||||||
widget.copyWith(sortOrder: widget.sortOrder == 0 ? order : widget.sortOrder),
|
: widget)
|
||||||
];
|
.copyWith(
|
||||||
|
sortOrder: widget.sortOrder == 0 ? order : widget.sortOrder,
|
||||||
|
);
|
||||||
|
_homeFilterWidgets = [..._homeFilterWidgets, stamped];
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
await _persistHomeWidgets();
|
await _persistHomeWidgets();
|
||||||
}
|
}
|
||||||
@@ -182,7 +204,7 @@ class PreferencesController extends ChangeNotifier {
|
|||||||
final index = _homeFilterWidgets.indexWhere((w) => w.id == widget.id);
|
final index = _homeFilterWidgets.indexWhere((w) => w.id == widget.id);
|
||||||
if (index < 0) return;
|
if (index < 0) return;
|
||||||
final next = [..._homeFilterWidgets];
|
final next = [..._homeFilterWidgets];
|
||||||
next[index] = widget;
|
next[index] = widget.copyWith(touchUpdatedAt: true);
|
||||||
next.sort((a, b) => a.sortOrder.compareTo(b.sortOrder));
|
next.sort((a, b) => a.sortOrder.compareTo(b.sortOrder));
|
||||||
_homeFilterWidgets = next;
|
_homeFilterWidgets = next;
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
@@ -190,11 +212,12 @@ class PreferencesController extends ChangeNotifier {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<void> removeHomeFilterWidget(String id) async {
|
Future<void> removeHomeFilterWidget(String id) async {
|
||||||
final next = [
|
final index = _homeFilterWidgets.indexWhere((w) => w.id == id);
|
||||||
for (final w in _homeFilterWidgets)
|
if (index < 0) return;
|
||||||
if (w.id != id) w,
|
final current = _homeFilterWidgets[index];
|
||||||
];
|
if (current.deleted) return;
|
||||||
if (next.length == _homeFilterWidgets.length) return;
|
final next = [..._homeFilterWidgets];
|
||||||
|
next[index] = current.copyWith(deleted: true, touchUpdatedAt: true);
|
||||||
_homeFilterWidgets = next;
|
_homeFilterWidgets = next;
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
await _persistHomeWidgets();
|
await _persistHomeWidgets();
|
||||||
@@ -204,19 +227,32 @@ class PreferencesController extends ChangeNotifier {
|
|||||||
final index = _homeFilterWidgets.indexWhere((w) => w.id == id);
|
final index = _homeFilterWidgets.indexWhere((w) => w.id == id);
|
||||||
if (index < 0) return;
|
if (index < 0) return;
|
||||||
final current = _homeFilterWidgets[index];
|
final current = _homeFilterWidgets[index];
|
||||||
if (current.display == display) return;
|
if (current.deleted || current.display == display) return;
|
||||||
await updateHomeFilterWidget(current.copyWith(display: display));
|
await updateHomeFilterWidget(current.copyWith(display: display));
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> reorderHomeFilterWidgets(int oldIndex, int newIndex) async {
|
Future<void> reorderHomeFilterWidgets(int oldIndex, int newIndex) async {
|
||||||
if (oldIndex == newIndex) return;
|
if (oldIndex == newIndex) return;
|
||||||
final next = [..._homeFilterWidgets];
|
final visible = [
|
||||||
final item = next.removeAt(oldIndex);
|
for (final w in _homeFilterWidgets)
|
||||||
final target = newIndex.clamp(0, next.length);
|
if (!w.deleted) w,
|
||||||
next.insert(target, item);
|
|
||||||
_homeFilterWidgets = [
|
|
||||||
for (var i = 0; i < next.length; i++) next[i].copyWith(sortOrder: i),
|
|
||||||
];
|
];
|
||||||
|
if (oldIndex < 0 || oldIndex >= visible.length) return;
|
||||||
|
final nextVisible = [...visible];
|
||||||
|
final item = nextVisible.removeAt(oldIndex);
|
||||||
|
final target = newIndex.clamp(0, nextVisible.length);
|
||||||
|
nextVisible.insert(target, item);
|
||||||
|
final orderById = <String, int>{
|
||||||
|
for (var i = 0; i < nextVisible.length; i++) nextVisible[i].id: i,
|
||||||
|
};
|
||||||
|
final now = DateTime.now().millisecondsSinceEpoch;
|
||||||
|
_homeFilterWidgets = [
|
||||||
|
for (final w in _homeFilterWidgets)
|
||||||
|
if (w.deleted)
|
||||||
|
w
|
||||||
|
else
|
||||||
|
w.copyWith(sortOrder: orderById[w.id] ?? w.sortOrder, updatedAt: now),
|
||||||
|
]..sort((a, b) => a.sortOrder.compareTo(b.sortOrder));
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
await _persistHomeWidgets();
|
await _persistHomeWidgets();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -372,7 +372,7 @@ class SyncController extends ChangeNotifier {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
final mergedFavourites = mergeOverviewFavourites(
|
final mergedFavourites = mergeOverviewFavourites(
|
||||||
_prefs.overviewFavourites,
|
_prefs.overviewFavouritesForSync,
|
||||||
remoteFavourites,
|
remoteFavourites,
|
||||||
);
|
);
|
||||||
List<HomeFilterWidget> remoteHomeWidgets = const [];
|
List<HomeFilterWidget> remoteHomeWidgets = const [];
|
||||||
@@ -386,7 +386,7 @@ class SyncController extends ChangeNotifier {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
final mergedHomeWidgets = mergeHomeFilterWidgets(
|
final mergedHomeWidgets = mergeHomeFilterWidgets(
|
||||||
_prefs.homeFilterWidgets,
|
_prefs.homeFilterWidgetsForSync,
|
||||||
remoteHomeWidgets,
|
remoteHomeWidgets,
|
||||||
);
|
);
|
||||||
AppCloudPrefs? remoteAppPrefs;
|
AppCloudPrefs? remoteAppPrefs;
|
||||||
@@ -576,7 +576,7 @@ class SyncController extends ChangeNotifier {
|
|||||||
_setStatus('Pushing favourites…');
|
_setStatus('Pushing favourites…');
|
||||||
try {
|
try {
|
||||||
await service.pushOverviewFavourites(
|
await service.pushOverviewFavourites(
|
||||||
_prefs.overviewFavourites,
|
_prefs.overviewFavouritesForSync,
|
||||||
onStatus: _setStatus,
|
onStatus: _setStatus,
|
||||||
);
|
);
|
||||||
parts.add('Favourites updated');
|
parts.add('Favourites updated');
|
||||||
@@ -584,6 +584,7 @@ class SyncController extends ChangeNotifier {
|
|||||||
debugPrint(
|
debugPrint(
|
||||||
'SyncController: overview_favourites push skipped ($error)',
|
'SyncController: overview_favourites push skipped ($error)',
|
||||||
);
|
);
|
||||||
|
_pushFavouritesPending = true;
|
||||||
}
|
}
|
||||||
bump();
|
bump();
|
||||||
}
|
}
|
||||||
@@ -591,7 +592,7 @@ class SyncController extends ChangeNotifier {
|
|||||||
_setStatus('Pushing home widgets…');
|
_setStatus('Pushing home widgets…');
|
||||||
try {
|
try {
|
||||||
await service.pushHomeFilterWidgets(
|
await service.pushHomeFilterWidgets(
|
||||||
_prefs.homeFilterWidgets,
|
_prefs.homeFilterWidgetsForSync,
|
||||||
onStatus: _setStatus,
|
onStatus: _setStatus,
|
||||||
);
|
);
|
||||||
parts.add('Home widgets updated');
|
parts.add('Home widgets updated');
|
||||||
@@ -599,6 +600,7 @@ class SyncController extends ChangeNotifier {
|
|||||||
debugPrint(
|
debugPrint(
|
||||||
'SyncController: home_filter_widgets push skipped ($error)',
|
'SyncController: home_filter_widgets push skipped ($error)',
|
||||||
);
|
);
|
||||||
|
_pushHomeWidgetsPending = true;
|
||||||
}
|
}
|
||||||
bump();
|
bump();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -474,7 +474,29 @@ class _OverviewScreenState extends State<OverviewScreen> {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
onMonthTap: (month) => _openPeriod(context, month),
|
onMonthTap: (month, {labelId, flow}) => _openPeriod(
|
||||||
|
context,
|
||||||
|
month,
|
||||||
|
labelId: labelId,
|
||||||
|
labelIds: {
|
||||||
|
for (final id in favourite.labelIds) id,
|
||||||
|
},
|
||||||
|
flow: flow ??
|
||||||
|
(favourite.metric == OverviewMetricMode.labels
|
||||||
|
? favourite.flow
|
||||||
|
: null),
|
||||||
|
periodMode: favourite.period,
|
||||||
|
),
|
||||||
|
onChartTap: () => _openChartFilter(
|
||||||
|
context,
|
||||||
|
labelIds: {
|
||||||
|
for (final id in favourite.labelIds) id,
|
||||||
|
},
|
||||||
|
flow: favourite.metric == OverviewMetricMode.labels
|
||||||
|
? favourite.flow
|
||||||
|
: null,
|
||||||
|
periodMode: favourite.period,
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -590,7 +612,17 @@ class _OverviewScreenState extends State<OverviewScreen> {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
onMonthTap: (month) => _openPeriod(context, month),
|
onMonthTap: (month, {labelId, flow}) => _openPeriod(
|
||||||
|
context,
|
||||||
|
month,
|
||||||
|
labelId: labelId,
|
||||||
|
flow: flow ??
|
||||||
|
(_metric == OverviewMetricMode.labels ? _labelFlow : null),
|
||||||
|
),
|
||||||
|
onChartTap: () => _openChartFilter(
|
||||||
|
context,
|
||||||
|
flow: _metric == OverviewMetricMode.labels ? _labelFlow : null,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 14),
|
const SizedBox(height: 14),
|
||||||
if (_metric == OverviewMetricMode.flow) ...[
|
if (_metric == OverviewMetricMode.flow) ...[
|
||||||
@@ -739,27 +771,61 @@ class _OverviewScreenState extends State<OverviewScreen> {
|
|||||||
BuildContext context,
|
BuildContext context,
|
||||||
DateTime period, {
|
DateTime period, {
|
||||||
String? labelId,
|
String? labelId,
|
||||||
|
Set<String>? labelIds,
|
||||||
|
TxFlowFilter? flow,
|
||||||
|
OverviewPeriodMode? periodMode,
|
||||||
}) {
|
}) {
|
||||||
final yearly = _period == OverviewPeriodMode.yearly;
|
final mode = periodMode ?? _period;
|
||||||
|
final yearly = mode == OverviewPeriodMode.yearly;
|
||||||
final initial = yearly ? DateTime(period.year, 12) : period;
|
final initial = yearly ? DateTime(period.year, 12) : period;
|
||||||
final labelIds = labelId != null
|
final resolvedLabelIds = labelId != null
|
||||||
? {labelId}
|
? {labelId}
|
||||||
: {
|
: (labelIds ??
|
||||||
// Open with the same labels currently shown on the chart.
|
{
|
||||||
for (final id in _includedLabelIds) id,
|
// Open with the same labels currently shown on the chart.
|
||||||
};
|
for (final id in _includedLabelIds) id,
|
||||||
|
});
|
||||||
Navigator.of(context).push(
|
Navigator.of(context).push(
|
||||||
MaterialPageRoute<void>(
|
MaterialPageRoute<void>(
|
||||||
builder: (_) => TransactionsScreen(
|
builder: (_) => TransactionsScreen(
|
||||||
initialMonth: initial,
|
initialMonth: initial,
|
||||||
initialLabelIds: labelIds,
|
initialLabelIds: resolvedLabelIds,
|
||||||
initialLabelMatch: LabelMatchMode.or,
|
initialLabelMatch: LabelMatchMode.or,
|
||||||
initialSearchInMonthOnly: !yearly && labelIds.isNotEmpty,
|
initialFlow: flow,
|
||||||
|
initialSearchInMonthOnly: !yearly && resolvedLabelIds.isNotEmpty,
|
||||||
initialYear: yearly ? period.year : null,
|
initialYear: yearly ? period.year : null,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Open Transactions with this chart's filters (no specific bar/column).
|
||||||
|
void _openChartFilter(
|
||||||
|
BuildContext context, {
|
||||||
|
Set<String>? labelIds,
|
||||||
|
TxFlowFilter? flow,
|
||||||
|
OverviewPeriodMode? periodMode,
|
||||||
|
}) {
|
||||||
|
final mode = periodMode ?? _period;
|
||||||
|
final yearly = mode == OverviewPeriodMode.yearly;
|
||||||
|
final resolvedLabelIds = labelIds ??
|
||||||
|
{
|
||||||
|
for (final id in _includedLabelIds) id,
|
||||||
|
};
|
||||||
|
Navigator.of(context).push(
|
||||||
|
MaterialPageRoute<void>(
|
||||||
|
builder: (_) => TransactionsScreen(
|
||||||
|
// Monthly charts show a year — open that whole year with the chart filter.
|
||||||
|
initialMonth: yearly ? null : DateTime(_cursor.year, 12),
|
||||||
|
initialYear: yearly ? null : _cursor.year,
|
||||||
|
initialLabelIds: resolvedLabelIds,
|
||||||
|
initialLabelMatch: LabelMatchMode.or,
|
||||||
|
initialFlow: flow,
|
||||||
|
initialSearchInMonthOnly: false,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class _MonthBucket {
|
class _MonthBucket {
|
||||||
@@ -1159,6 +1225,7 @@ class _ChartCard extends StatelessWidget {
|
|||||||
required this.availableLabelCount,
|
required this.availableLabelCount,
|
||||||
required this.onLabelTap,
|
required this.onLabelTap,
|
||||||
required this.onMonthTap,
|
required this.onMonthTap,
|
||||||
|
required this.onChartTap,
|
||||||
this.onPeriodModeChanged,
|
this.onPeriodModeChanged,
|
||||||
this.onEdit,
|
this.onEdit,
|
||||||
});
|
});
|
||||||
@@ -1182,7 +1249,12 @@ class _ChartCard extends StatelessWidget {
|
|||||||
final int? includedLabelCount;
|
final int? includedLabelCount;
|
||||||
final int availableLabelCount;
|
final int availableLabelCount;
|
||||||
final void Function(TxLabel label) onLabelTap;
|
final void Function(TxLabel label) onLabelTap;
|
||||||
final void Function(DateTime month) onMonthTap;
|
final void Function(
|
||||||
|
DateTime month, {
|
||||||
|
String? labelId,
|
||||||
|
TxFlowFilter? flow,
|
||||||
|
}) onMonthTap;
|
||||||
|
final VoidCallback onChartTap;
|
||||||
final ValueChanged<OverviewPeriodMode>? onPeriodModeChanged;
|
final ValueChanged<OverviewPeriodMode>? onPeriodModeChanged;
|
||||||
final VoidCallback? onEdit;
|
final VoidCallback? onEdit;
|
||||||
|
|
||||||
@@ -1277,7 +1349,7 @@ class _ChartCard extends StatelessWidget {
|
|||||||
runSpacing: 2,
|
runSpacing: 2,
|
||||||
alignment: WrapAlignment.end,
|
alignment: WrapAlignment.end,
|
||||||
children: [
|
children: [
|
||||||
for (final row in labelSpend.take(compact ? 3 : 5))
|
for (final row in labelSpend.take(6))
|
||||||
GestureDetector(
|
GestureDetector(
|
||||||
onTap: () => onLabelTap(row.label),
|
onTap: () => onLabelTap(row.label),
|
||||||
child: _LegendDot(
|
child: _LegendDot(
|
||||||
@@ -1286,7 +1358,7 @@ class _ChartCard extends StatelessWidget {
|
|||||||
compact: compact,
|
compact: compact,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
if (labelSpend.length > (compact ? 3 : 5))
|
if (labelSpend.length > 6)
|
||||||
_LegendDot(
|
_LegendDot(
|
||||||
color: colors.outline,
|
color: colors.outline,
|
||||||
label: 'Other',
|
label: 'Other',
|
||||||
@@ -1359,189 +1431,198 @@ class _ChartCard extends StatelessWidget {
|
|||||||
final hasLegend = metric == OverviewMetricMode.flow ||
|
final hasLegend = metric == OverviewMetricMode.flow ||
|
||||||
labelSpend.isNotEmpty;
|
labelSpend.isNotEmpty;
|
||||||
|
|
||||||
|
final radius = BorderRadius.circular(compact ? 16 : 20);
|
||||||
|
|
||||||
return Card(
|
return Card(
|
||||||
color: colors.surfaceContainer,
|
color: colors.surfaceContainer,
|
||||||
elevation: 0,
|
elevation: 0,
|
||||||
margin: EdgeInsets.zero,
|
margin: EdgeInsets.zero,
|
||||||
shape: RoundedRectangleBorder(
|
clipBehavior: Clip.antiAlias,
|
||||||
borderRadius: BorderRadius.circular(compact ? 16 : 20),
|
shape: RoundedRectangleBorder(borderRadius: radius),
|
||||||
),
|
// Whole card opens the chart filter; nested buttons/legend keep their own taps.
|
||||||
child: Padding(
|
child: InkWell(
|
||||||
padding: EdgeInsets.fromLTRB(
|
onTap: onChartTap,
|
||||||
compact ? 12 : 14,
|
borderRadius: radius,
|
||||||
compact ? 10 : 12,
|
child: Padding(
|
||||||
compact ? 10 : 14,
|
padding: EdgeInsets.fromLTRB(
|
||||||
compact ? 12 : 16,
|
compact ? 12 : 14,
|
||||||
),
|
compact ? 10 : 12,
|
||||||
child: Column(
|
compact ? 10 : 14,
|
||||||
children: [
|
compact ? 12 : 16,
|
||||||
if (compact) ...[
|
),
|
||||||
Row(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
if (onPeriodModeChanged != null)
|
if (compact) ...[
|
||||||
SegmentedButton<OverviewPeriodMode>(
|
|
||||||
showSelectedIcon: false,
|
|
||||||
style: _compactSegmentStyle,
|
|
||||||
segments: const [
|
|
||||||
ButtonSegment(
|
|
||||||
value: OverviewPeriodMode.monthly,
|
|
||||||
label: Text('Month'),
|
|
||||||
),
|
|
||||||
ButtonSegment(
|
|
||||||
value: OverviewPeriodMode.yearly,
|
|
||||||
label: Text('Year'),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
selected: {period},
|
|
||||||
onSelectionChanged: (selection) {
|
|
||||||
onPeriodModeChanged!(selection.first);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
if (heading != null) ...[
|
|
||||||
const SizedBox(width: 8),
|
|
||||||
Expanded(
|
|
||||||
child: Text(
|
|
||||||
heading!,
|
|
||||||
maxLines: 1,
|
|
||||||
overflow: TextOverflow.ellipsis,
|
|
||||||
style: theme.textTheme.titleSmall?.copyWith(
|
|
||||||
fontWeight: FontWeight.w700,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
] else
|
|
||||||
const Spacer(),
|
|
||||||
if (showFilter) ...[
|
|
||||||
const SizedBox(width: 4),
|
|
||||||
_filterButton(colors),
|
|
||||||
],
|
|
||||||
if (onEdit != null) ...[
|
|
||||||
const SizedBox(width: 2),
|
|
||||||
_editButton(colors, compact: true),
|
|
||||||
],
|
|
||||||
],
|
|
||||||
),
|
|
||||||
const SizedBox(height: 4),
|
|
||||||
Row(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
|
||||||
children: [
|
|
||||||
Expanded(
|
|
||||||
child: _periodControls(theme, compact: true),
|
|
||||||
),
|
|
||||||
if (hasLegend) ...[
|
|
||||||
const SizedBox(width: 8),
|
|
||||||
Flexible(child: legend),
|
|
||||||
],
|
|
||||||
],
|
|
||||||
),
|
|
||||||
const SizedBox(height: 6),
|
|
||||||
] else ...[
|
|
||||||
if (heading != null) ...[
|
|
||||||
Align(
|
|
||||||
alignment: Alignment.centerLeft,
|
|
||||||
child: Text(
|
|
||||||
heading!,
|
|
||||||
style: theme.textTheme.titleMedium?.copyWith(
|
|
||||||
fontWeight: FontWeight.w700,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(height: 8),
|
|
||||||
],
|
|
||||||
if (period == OverviewPeriodMode.monthly)
|
|
||||||
Row(
|
Row(
|
||||||
children: [
|
children: [
|
||||||
IconButton(
|
if (onPeriodModeChanged != null)
|
||||||
tooltip: 'Previous year',
|
SegmentedButton<OverviewPeriodMode>(
|
||||||
onPressed: canGoBack ? onBack : null,
|
showSelectedIcon: false,
|
||||||
visualDensity: const VisualDensity(
|
style: _compactSegmentStyle,
|
||||||
horizontal: -4,
|
segments: const [
|
||||||
vertical: -4,
|
ButtonSegment(
|
||||||
|
value: OverviewPeriodMode.monthly,
|
||||||
|
label: Text('Month'),
|
||||||
|
),
|
||||||
|
ButtonSegment(
|
||||||
|
value: OverviewPeriodMode.yearly,
|
||||||
|
label: Text('Year'),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
selected: {period},
|
||||||
|
onSelectionChanged: (selection) {
|
||||||
|
onPeriodModeChanged!(selection.first);
|
||||||
|
},
|
||||||
),
|
),
|
||||||
constraints: const BoxConstraints(
|
if (heading != null) ...[
|
||||||
minWidth: 32,
|
const SizedBox(width: 8),
|
||||||
minHeight: 32,
|
Expanded(
|
||||||
),
|
child: Text(
|
||||||
padding: EdgeInsets.zero,
|
heading!,
|
||||||
icon: const Icon(Icons.chevron_left, size: 22),
|
maxLines: 1,
|
||||||
),
|
overflow: TextOverflow.ellipsis,
|
||||||
Expanded(
|
style: theme.textTheme.titleSmall?.copyWith(
|
||||||
child: Text(
|
fontWeight: FontWeight.w700,
|
||||||
periodTitle,
|
),
|
||||||
textAlign: TextAlign.center,
|
|
||||||
style: theme.textTheme.titleMedium?.copyWith(
|
|
||||||
fontWeight: FontWeight.w700,
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
] else
|
||||||
IconButton(
|
const Spacer(),
|
||||||
tooltip: 'Next year',
|
|
||||||
onPressed: canGoForward ? onForward : null,
|
|
||||||
visualDensity: const VisualDensity(
|
|
||||||
horizontal: -4,
|
|
||||||
vertical: -4,
|
|
||||||
),
|
|
||||||
constraints: const BoxConstraints(
|
|
||||||
minWidth: 32,
|
|
||||||
minHeight: 32,
|
|
||||||
),
|
|
||||||
padding: EdgeInsets.zero,
|
|
||||||
icon: const Icon(Icons.chevron_right, size: 22),
|
|
||||||
),
|
|
||||||
if (showFilter) ...[
|
if (showFilter) ...[
|
||||||
const SizedBox(width: 2),
|
const SizedBox(width: 4),
|
||||||
_filterButton(colors),
|
_filterButton(colors),
|
||||||
],
|
],
|
||||||
|
if (onEdit != null) ...[
|
||||||
|
const SizedBox(width: 2),
|
||||||
|
_editButton(colors, compact: true),
|
||||||
|
],
|
||||||
],
|
],
|
||||||
)
|
),
|
||||||
else
|
const SizedBox(height: 4),
|
||||||
Row(
|
Row(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
SizedBox(width: showFilter ? 36 : 0),
|
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Text(
|
child: _periodControls(theme, compact: true),
|
||||||
periodTitle,
|
),
|
||||||
textAlign: TextAlign.center,
|
if (hasLegend) ...[
|
||||||
style: theme.textTheme.titleMedium?.copyWith(
|
const SizedBox(width: 8),
|
||||||
fontWeight: FontWeight.w700,
|
Flexible(child: legend),
|
||||||
),
|
],
|
||||||
|
],
|
||||||
|
),
|
||||||
|
const SizedBox(height: 6),
|
||||||
|
] else ...[
|
||||||
|
if (heading != null) ...[
|
||||||
|
Align(
|
||||||
|
alignment: Alignment.centerLeft,
|
||||||
|
child: Text(
|
||||||
|
heading!,
|
||||||
|
style: theme.textTheme.titleMedium?.copyWith(
|
||||||
|
fontWeight: FontWeight.w700,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
if (showFilter)
|
),
|
||||||
_filterButton(colors)
|
const SizedBox(height: 8),
|
||||||
else
|
],
|
||||||
const SizedBox(width: 0),
|
if (period == OverviewPeriodMode.monthly)
|
||||||
],
|
Row(
|
||||||
),
|
children: [
|
||||||
if (hasLegend) ...[
|
IconButton(
|
||||||
Align(
|
tooltip: 'Previous year',
|
||||||
alignment: Alignment.centerRight,
|
onPressed: canGoBack ? onBack : null,
|
||||||
child: legend,
|
visualDensity: const VisualDensity(
|
||||||
),
|
horizontal: -4,
|
||||||
const SizedBox(height: 8),
|
vertical: -4,
|
||||||
|
),
|
||||||
|
constraints: const BoxConstraints(
|
||||||
|
minWidth: 32,
|
||||||
|
minHeight: 32,
|
||||||
|
),
|
||||||
|
padding: EdgeInsets.zero,
|
||||||
|
icon: const Icon(Icons.chevron_left, size: 22),
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: Text(
|
||||||
|
periodTitle,
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
style: theme.textTheme.titleMedium?.copyWith(
|
||||||
|
fontWeight: FontWeight.w700,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
IconButton(
|
||||||
|
tooltip: 'Next year',
|
||||||
|
onPressed: canGoForward ? onForward : null,
|
||||||
|
visualDensity: const VisualDensity(
|
||||||
|
horizontal: -4,
|
||||||
|
vertical: -4,
|
||||||
|
),
|
||||||
|
constraints: const BoxConstraints(
|
||||||
|
minWidth: 32,
|
||||||
|
minHeight: 32,
|
||||||
|
),
|
||||||
|
padding: EdgeInsets.zero,
|
||||||
|
icon: const Icon(Icons.chevron_right, size: 22),
|
||||||
|
),
|
||||||
|
if (showFilter) ...[
|
||||||
|
const SizedBox(width: 2),
|
||||||
|
_filterButton(colors),
|
||||||
|
],
|
||||||
|
],
|
||||||
|
)
|
||||||
|
else
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
SizedBox(width: showFilter ? 36 : 0),
|
||||||
|
Expanded(
|
||||||
|
child: Text(
|
||||||
|
periodTitle,
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
style: theme.textTheme.titleMedium?.copyWith(
|
||||||
|
fontWeight: FontWeight.w700,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (showFilter)
|
||||||
|
_filterButton(colors)
|
||||||
|
else
|
||||||
|
const SizedBox(width: 0),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
if (hasLegend) ...[
|
||||||
|
Align(
|
||||||
|
alignment: Alignment.centerRight,
|
||||||
|
child: legend,
|
||||||
|
),
|
||||||
|
const SizedBox(height: 8),
|
||||||
|
],
|
||||||
],
|
],
|
||||||
|
SizedBox(
|
||||||
|
height: chartHeight,
|
||||||
|
child: metric == OverviewMetricMode.flow
|
||||||
|
? _FlowBars(
|
||||||
|
months: months,
|
||||||
|
monthly: monthly,
|
||||||
|
currency: currency,
|
||||||
|
period: period,
|
||||||
|
onMonthTap: onMonthTap,
|
||||||
|
onChartTap: onChartTap,
|
||||||
|
)
|
||||||
|
: _LabelMonthBars(
|
||||||
|
months: months,
|
||||||
|
labelSpend: labelSpend,
|
||||||
|
amountByMonth: labelAmountByMonth,
|
||||||
|
currency: currency,
|
||||||
|
period: period,
|
||||||
|
barStyle: labelBarStyle,
|
||||||
|
invertChart: invertChart,
|
||||||
|
onMonthTap: onMonthTap,
|
||||||
|
onChartTap: onChartTap,
|
||||||
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
SizedBox(
|
),
|
||||||
height: chartHeight,
|
|
||||||
child: metric == OverviewMetricMode.flow
|
|
||||||
? _FlowBars(
|
|
||||||
months: months,
|
|
||||||
monthly: monthly,
|
|
||||||
currency: currency,
|
|
||||||
period: period,
|
|
||||||
)
|
|
||||||
: _LabelMonthBars(
|
|
||||||
months: months,
|
|
||||||
labelSpend: labelSpend,
|
|
||||||
amountByMonth: labelAmountByMonth,
|
|
||||||
currency: currency,
|
|
||||||
period: period,
|
|
||||||
barStyle: labelBarStyle,
|
|
||||||
invertChart: invertChart,
|
|
||||||
onMonthTap: onMonthTap,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@@ -1554,12 +1635,20 @@ class _FlowBars extends StatelessWidget {
|
|||||||
required this.monthly,
|
required this.monthly,
|
||||||
required this.currency,
|
required this.currency,
|
||||||
required this.period,
|
required this.period,
|
||||||
|
required this.onMonthTap,
|
||||||
|
required this.onChartTap,
|
||||||
});
|
});
|
||||||
|
|
||||||
final List<DateTime> months;
|
final List<DateTime> months;
|
||||||
final Map<DateTime, _MonthBucket> monthly;
|
final Map<DateTime, _MonthBucket> monthly;
|
||||||
final String currency;
|
final String currency;
|
||||||
final OverviewPeriodMode period;
|
final OverviewPeriodMode period;
|
||||||
|
final void Function(
|
||||||
|
DateTime month, {
|
||||||
|
String? labelId,
|
||||||
|
TxFlowFilter? flow,
|
||||||
|
}) onMonthTap;
|
||||||
|
final VoidCallback onChartTap;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
@@ -1578,121 +1667,119 @@ class _FlowBars extends StatelessWidget {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (empty) {
|
if (empty) {
|
||||||
return Center(
|
return GestureDetector(
|
||||||
child: Text(
|
behavior: HitTestBehavior.opaque,
|
||||||
period == OverviewPeriodMode.yearly
|
onTap: onChartTap,
|
||||||
? 'No income or expenses in these years'
|
child: Center(
|
||||||
: 'No income or expenses in this year',
|
child: Text(
|
||||||
style: theme.textTheme.bodyMedium,
|
period == OverviewPeriodMode.yearly
|
||||||
textAlign: TextAlign.center,
|
? 'No income or expenses in these years'
|
||||||
|
: 'No income or expenses in this year',
|
||||||
|
style: theme.textTheme.bodyMedium,
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return BarChart(
|
return GestureDetector(
|
||||||
BarChartData(
|
behavior: HitTestBehavior.opaque,
|
||||||
maxY: safeMax,
|
onTap: onChartTap,
|
||||||
groupsSpace: period == OverviewPeriodMode.yearly ? 16 : 10,
|
child: IgnorePointer(
|
||||||
barTouchData: BarTouchData(
|
// fl_chart otherwise owns the gesture arena and empty taps go nowhere.
|
||||||
touchTooltipData: BarTouchTooltipData(
|
// Tap opens this chart's filters; legend / history still open columns.
|
||||||
getTooltipItem: (group, groupIndex, rod, rodIndex) {
|
child: BarChart(
|
||||||
final month = months[group.x.toInt()];
|
BarChartData(
|
||||||
final bucket = monthly[_periodKey(month, period)]!;
|
maxY: safeMax,
|
||||||
final isIncome = rodIndex == 1;
|
groupsSpace: period == OverviewPeriodMode.yearly ? 16 : 10,
|
||||||
final value = isIncome ? bucket.income : bucket.expense;
|
barTouchData: const BarTouchData(enabled: false),
|
||||||
return BarTooltipItem(
|
titlesData: FlTitlesData(
|
||||||
'${_periodAxisLabel(month, period)}\n'
|
topTitles:
|
||||||
'${isIncome ? 'Income' : 'Expense'}\n'
|
const AxisTitles(sideTitles: SideTitles(showTitles: false)),
|
||||||
'${formatMoney(value, currency)}',
|
rightTitles:
|
||||||
TextStyle(color: colors.onInverseSurface),
|
const AxisTitles(sideTitles: SideTitles(showTitles: false)),
|
||||||
);
|
leftTitles: AxisTitles(
|
||||||
},
|
sideTitles: SideTitles(
|
||||||
),
|
showTitles: true,
|
||||||
),
|
reservedSize: 42,
|
||||||
titlesData: FlTitlesData(
|
interval: safeMax / 3,
|
||||||
topTitles: const AxisTitles(sideTitles: SideTitles(showTitles: false)),
|
getTitlesWidget: (value, meta) {
|
||||||
rightTitles:
|
if (value <= 0) {
|
||||||
const AxisTitles(sideTitles: SideTitles(showTitles: false)),
|
return Text('0', style: theme.textTheme.labelSmall);
|
||||||
leftTitles: AxisTitles(
|
}
|
||||||
sideTitles: SideTitles(
|
if ((value - safeMax).abs() < 0.01) {
|
||||||
showTitles: true,
|
return const SizedBox.shrink();
|
||||||
reservedSize: 42,
|
}
|
||||||
interval: safeMax / 3,
|
return Text(
|
||||||
getTitlesWidget: (value, meta) {
|
_compactMoney(value),
|
||||||
if (value <= 0) {
|
style: theme.textTheme.labelSmall,
|
||||||
return Text('0', style: theme.textTheme.labelSmall);
|
);
|
||||||
}
|
},
|
||||||
if ((value - safeMax).abs() < 0.01) {
|
|
||||||
return const SizedBox.shrink();
|
|
||||||
}
|
|
||||||
return Text(
|
|
||||||
_compactMoney(value),
|
|
||||||
style: theme.textTheme.labelSmall,
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
bottomTitles: AxisTitles(
|
|
||||||
sideTitles: SideTitles(
|
|
||||||
showTitles: true,
|
|
||||||
reservedSize: 28,
|
|
||||||
getTitlesWidget: (value, meta) {
|
|
||||||
final index = value.toInt();
|
|
||||||
if (index < 0 || index >= months.length) {
|
|
||||||
return const SizedBox.shrink();
|
|
||||||
}
|
|
||||||
if (period == OverviewPeriodMode.monthly &&
|
|
||||||
index % 2 == 1 &&
|
|
||||||
months.length > 8) {
|
|
||||||
return const SizedBox.shrink();
|
|
||||||
}
|
|
||||||
return Padding(
|
|
||||||
padding: const EdgeInsets.only(top: 8),
|
|
||||||
child: Text(
|
|
||||||
_periodAxisLabel(months[index], period),
|
|
||||||
style: theme.textTheme.labelSmall,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
gridData: FlGridData(
|
|
||||||
show: true,
|
|
||||||
drawVerticalLine: false,
|
|
||||||
horizontalInterval: safeMax / 3,
|
|
||||||
getDrawingHorizontalLine: (value) => FlLine(
|
|
||||||
color: colors.outlineVariant.withValues(alpha: 0.35),
|
|
||||||
strokeWidth: 1,
|
|
||||||
dashArray: const [4, 4],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
borderData: FlBorderData(show: false),
|
|
||||||
barGroups: [
|
|
||||||
for (var i = 0; i < months.length; i++)
|
|
||||||
BarChartGroupData(
|
|
||||||
x: i,
|
|
||||||
barsSpace: 3,
|
|
||||||
barRods: [
|
|
||||||
BarChartRodData(
|
|
||||||
toY: monthly[_periodKey(months[i], period)]!.expense,
|
|
||||||
width: period == OverviewPeriodMode.yearly ? 14 : 9,
|
|
||||||
borderRadius:
|
|
||||||
const BorderRadius.vertical(top: Radius.circular(6)),
|
|
||||||
color: _kExpenseColor,
|
|
||||||
),
|
),
|
||||||
BarChartRodData(
|
),
|
||||||
toY: monthly[_periodKey(months[i], period)]!.income,
|
bottomTitles: AxisTitles(
|
||||||
width: period == OverviewPeriodMode.yearly ? 14 : 9,
|
sideTitles: SideTitles(
|
||||||
borderRadius:
|
showTitles: true,
|
||||||
const BorderRadius.vertical(top: Radius.circular(6)),
|
reservedSize: 28,
|
||||||
color: _kIncomeColor,
|
getTitlesWidget: (value, meta) {
|
||||||
|
final index = value.toInt();
|
||||||
|
if (index < 0 || index >= months.length) {
|
||||||
|
return const SizedBox.shrink();
|
||||||
|
}
|
||||||
|
if (period == OverviewPeriodMode.monthly &&
|
||||||
|
index % 2 == 1 &&
|
||||||
|
months.length > 8) {
|
||||||
|
return const SizedBox.shrink();
|
||||||
|
}
|
||||||
|
return Padding(
|
||||||
|
padding: const EdgeInsets.only(top: 8),
|
||||||
|
child: Text(
|
||||||
|
_periodAxisLabel(months[index], period),
|
||||||
|
style: theme.textTheme.labelSmall,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
),
|
),
|
||||||
],
|
),
|
||||||
),
|
),
|
||||||
],
|
gridData: FlGridData(
|
||||||
|
show: true,
|
||||||
|
drawVerticalLine: false,
|
||||||
|
horizontalInterval: safeMax / 3,
|
||||||
|
getDrawingHorizontalLine: (value) => FlLine(
|
||||||
|
color: colors.outlineVariant.withValues(alpha: 0.35),
|
||||||
|
strokeWidth: 1,
|
||||||
|
dashArray: const [4, 4],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
borderData: FlBorderData(show: false),
|
||||||
|
barGroups: [
|
||||||
|
for (var i = 0; i < months.length; i++)
|
||||||
|
BarChartGroupData(
|
||||||
|
x: i,
|
||||||
|
barsSpace: 3,
|
||||||
|
barRods: [
|
||||||
|
BarChartRodData(
|
||||||
|
toY: monthly[_periodKey(months[i], period)]!.expense,
|
||||||
|
width: period == OverviewPeriodMode.yearly ? 14 : 9,
|
||||||
|
borderRadius:
|
||||||
|
const BorderRadius.vertical(top: Radius.circular(6)),
|
||||||
|
color: _kExpenseColor,
|
||||||
|
),
|
||||||
|
BarChartRodData(
|
||||||
|
toY: monthly[_periodKey(months[i], period)]!.income,
|
||||||
|
width: period == OverviewPeriodMode.yearly ? 14 : 9,
|
||||||
|
borderRadius:
|
||||||
|
const BorderRadius.vertical(top: Radius.circular(6)),
|
||||||
|
color: _kIncomeColor,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
duration: Duration.zero,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
duration: Duration.zero,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1707,9 +1794,10 @@ class _LabelMonthBars extends StatelessWidget {
|
|||||||
required this.barStyle,
|
required this.barStyle,
|
||||||
required this.invertChart,
|
required this.invertChart,
|
||||||
required this.onMonthTap,
|
required this.onMonthTap,
|
||||||
|
required this.onChartTap,
|
||||||
});
|
});
|
||||||
|
|
||||||
static const _maxSeriesLabels = 5;
|
static const _maxSeriesLabels = 6;
|
||||||
|
|
||||||
final List<DateTime> months;
|
final List<DateTime> months;
|
||||||
final List<_LabelSpend> labelSpend;
|
final List<_LabelSpend> labelSpend;
|
||||||
@@ -1718,7 +1806,12 @@ class _LabelMonthBars extends StatelessWidget {
|
|||||||
final OverviewPeriodMode period;
|
final OverviewPeriodMode period;
|
||||||
final LabelChartBarStyle barStyle;
|
final LabelChartBarStyle barStyle;
|
||||||
final bool invertChart;
|
final bool invertChart;
|
||||||
final void Function(DateTime month) onMonthTap;
|
final void Function(
|
||||||
|
DateTime month, {
|
||||||
|
String? labelId,
|
||||||
|
TxFlowFilter? flow,
|
||||||
|
}) onMonthTap;
|
||||||
|
final VoidCallback onChartTap;
|
||||||
|
|
||||||
double _plot(double value) => invertChart ? -value : value;
|
double _plot(double value) => invertChart ? -value : value;
|
||||||
|
|
||||||
@@ -1727,11 +1820,15 @@ class _LabelMonthBars extends StatelessWidget {
|
|||||||
final theme = Theme.of(context);
|
final theme = Theme.of(context);
|
||||||
final colors = theme.colorScheme;
|
final colors = theme.colorScheme;
|
||||||
if (labelSpend.isEmpty) {
|
if (labelSpend.isEmpty) {
|
||||||
return Center(
|
return GestureDetector(
|
||||||
child: Text(
|
behavior: HitTestBehavior.opaque,
|
||||||
'No labeled activity in this period.\nTag transactions to see them here.',
|
onTap: onChartTap,
|
||||||
style: theme.textTheme.bodyMedium,
|
child: Center(
|
||||||
textAlign: TextAlign.center,
|
child: Text(
|
||||||
|
'No labeled activity in this period.\nTag transactions to see them here.',
|
||||||
|
style: theme.textTheme.bodyMedium,
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -1789,11 +1886,15 @@ class _LabelMonthBars extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (maxY == 0 && minY == 0) {
|
if (maxY == 0 && minY == 0) {
|
||||||
return Center(
|
return GestureDetector(
|
||||||
child: Text(
|
behavior: HitTestBehavior.opaque,
|
||||||
'No labeled activity in this period.\nTag transactions to see them here.',
|
onTap: onChartTap,
|
||||||
style: theme.textTheme.bodyMedium,
|
child: Center(
|
||||||
textAlign: TextAlign.center,
|
child: Text(
|
||||||
|
'No labeled activity in this period.\nTag transactions to see them here.',
|
||||||
|
style: theme.textTheme.bodyMedium,
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -1805,12 +1906,12 @@ class _LabelMonthBars extends StatelessWidget {
|
|||||||
final rodWidth = stacked
|
final rodWidth = stacked
|
||||||
? (period == OverviewPeriodMode.yearly ? 18.0 : 14.0)
|
? (period == OverviewPeriodMode.yearly ? 18.0 : 14.0)
|
||||||
: period == OverviewPeriodMode.yearly
|
: period == OverviewPeriodMode.yearly
|
||||||
? (seriesCount <= 3 ? 12.0 : 8.0)
|
? (seriesCount <= 3 ? 12.0 : seriesCount <= 6 ? 8.0 : 6.0)
|
||||||
: (seriesCount <= 3
|
: (seriesCount <= 3
|
||||||
? 7.0
|
? 7.0
|
||||||
: seriesCount <= 5
|
: seriesCount <= 6
|
||||||
? 5.0
|
? 4.5
|
||||||
: 4.0);
|
: 3.5);
|
||||||
|
|
||||||
List<BarChartRodData> rodsFor(DateTime month) {
|
List<BarChartRodData> rodsFor(DateTime month) {
|
||||||
final bucket =
|
final bucket =
|
||||||
@@ -1888,59 +1989,16 @@ class _LabelMonthBars extends StatelessWidget {
|
|||||||
final axisInterval = ((safeMax - safeMin) / 3).abs();
|
final axisInterval = ((safeMax - safeMin) / 3).abs();
|
||||||
final interval = axisInterval <= 0 ? 1.0 : axisInterval;
|
final interval = axisInterval <= 0 ? 1.0 : axisInterval;
|
||||||
|
|
||||||
return BarChart(
|
return GestureDetector(
|
||||||
BarChartData(
|
behavior: HitTestBehavior.opaque,
|
||||||
minY: safeMin,
|
onTap: onChartTap,
|
||||||
maxY: safeMax,
|
child: IgnorePointer(
|
||||||
groupsSpace: period == OverviewPeriodMode.yearly ? 16 : 10,
|
child: BarChart(
|
||||||
barTouchData: BarTouchData(
|
BarChartData(
|
||||||
touchCallback: (event, response) {
|
minY: safeMin,
|
||||||
if (event is! FlTapUpEvent) return;
|
maxY: safeMax,
|
||||||
final index = response?.spot?.touchedBarGroupIndex;
|
groupsSpace: period == OverviewPeriodMode.yearly ? 16 : 10,
|
||||||
if (index == null || index < 0 || index >= months.length) return;
|
barTouchData: const BarTouchData(enabled: false),
|
||||||
onMonthTap(months[index]);
|
|
||||||
},
|
|
||||||
touchTooltipData: BarTouchTooltipData(
|
|
||||||
getTooltipItem: (group, groupIndex, rod, rodIndex) {
|
|
||||||
final month = months[group.x.toInt()];
|
|
||||||
if (stacked && rod.rodStackItems.isNotEmpty) {
|
|
||||||
final bucket =
|
|
||||||
amountByMonth[_periodKey(month, period)] ?? const {};
|
|
||||||
final buffer = StringBuffer(
|
|
||||||
'${_periodAxisLabel(month, period)}\n',
|
|
||||||
);
|
|
||||||
var total = 0.0;
|
|
||||||
for (final row in topLabels) {
|
|
||||||
final amount = bucket[row.label.id] ?? 0;
|
|
||||||
if (amount == 0) continue;
|
|
||||||
total += amount;
|
|
||||||
buffer.writeln(
|
|
||||||
'${row.label.name}: ${formatMoney(amount, currency)}',
|
|
||||||
);
|
|
||||||
}
|
|
||||||
final other = otherFor(month);
|
|
||||||
if (other != 0) {
|
|
||||||
total += other;
|
|
||||||
buffer.writeln('Other: ${formatMoney(other, currency)}');
|
|
||||||
}
|
|
||||||
buffer.write('Total: ${formatMoney(total, currency)}');
|
|
||||||
return BarTooltipItem(
|
|
||||||
buffer.toString(),
|
|
||||||
TextStyle(color: colors.onInverseSurface),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
final name = rodIndex < topLabels.length
|
|
||||||
? topLabels[rodIndex].label.name
|
|
||||||
: 'Other';
|
|
||||||
return BarTooltipItem(
|
|
||||||
'${_periodAxisLabel(month, period)}\n'
|
|
||||||
'$name\n'
|
|
||||||
'${formatMoney(invertChart ? -rod.toY : rod.toY, currency)}',
|
|
||||||
TextStyle(color: colors.onInverseSurface),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
titlesData: FlTitlesData(
|
titlesData: FlTitlesData(
|
||||||
topTitles: const AxisTitles(sideTitles: SideTitles(showTitles: false)),
|
topTitles: const AxisTitles(sideTitles: SideTitles(showTitles: false)),
|
||||||
rightTitles:
|
rightTitles:
|
||||||
@@ -2003,16 +2061,18 @@ class _LabelMonthBars extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
borderData: FlBorderData(show: false),
|
borderData: FlBorderData(show: false),
|
||||||
barGroups: [
|
barGroups: [
|
||||||
for (var i = 0; i < months.length; i++)
|
for (var i = 0; i < months.length; i++)
|
||||||
BarChartGroupData(
|
BarChartGroupData(
|
||||||
x: i,
|
x: i,
|
||||||
barsSpace: stacked ? 0 : 2,
|
barsSpace: stacked ? 0 : 2,
|
||||||
barRods: rodsFor(months[i]),
|
barRods: rodsFor(months[i]),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
),
|
||||||
|
duration: Duration.zero,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
duration: Duration.zero,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,7 +27,31 @@ bool isSameTransaction(BankTransaction a, BankTransaction b) {
|
|||||||
if (a.date != b.date) return false;
|
if (a.date != b.date) return false;
|
||||||
if (a.currency.toUpperCase() != b.currency.toUpperCase()) return false;
|
if (a.currency.toUpperCase() != b.currency.toUpperCase()) return false;
|
||||||
if (_amountCents(a.amount) != _amountCents(b.amount)) return false;
|
if (_amountCents(a.amount) != _amountCents(b.amount)) return false;
|
||||||
|
return _descriptionsLikelyMatch(a, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// True when a cached/API [pending] row is the unsettled form of [booked].
|
||||||
|
///
|
||||||
|
/// Banks often change booking date (and sometimes wording) when a payment
|
||||||
|
/// settles, so this allows a small date window unlike [isSameTransaction].
|
||||||
|
bool isPendingSettledBy(
|
||||||
|
BankTransaction pending,
|
||||||
|
BankTransaction booked, {
|
||||||
|
int maxDayGap = 10,
|
||||||
|
}) {
|
||||||
|
if (!pending.pending || booked.pending) return false;
|
||||||
|
if (pending.isManual || booked.isManual) return false;
|
||||||
|
if (pending.currency.toUpperCase() != booked.currency.toUpperCase()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (_amountCents(pending.amount) != _amountCents(booked.amount)) return false;
|
||||||
|
if (!_descriptionsLikelyMatch(pending, booked)) return false;
|
||||||
|
final gap = _dateDiffDays(pending.date, booked.date);
|
||||||
|
if (gap == null) return false;
|
||||||
|
return gap.abs() <= maxDayGap;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool _descriptionsLikelyMatch(BankTransaction a, BankTransaction b) {
|
||||||
if (a.descriptionKey == b.descriptionKey) return true;
|
if (a.descriptionKey == b.descriptionKey) return true;
|
||||||
|
|
||||||
final ma = a.merchantKey;
|
final ma = a.merchantKey;
|
||||||
@@ -47,10 +71,62 @@ bool isSameTransaction(BankTransaction a, BankTransaction b) {
|
|||||||
|
|
||||||
int _amountCents(double amount) => (amount * 100).round();
|
int _amountCents(double amount) => (amount * 100).round();
|
||||||
|
|
||||||
|
int? _dateDiffDays(String a, String b) {
|
||||||
|
final da = DateTime.tryParse(a);
|
||||||
|
final db = DateTime.tryParse(b);
|
||||||
|
if (da == null || db == null) return null;
|
||||||
|
return da.difference(db).inDays;
|
||||||
|
}
|
||||||
|
|
||||||
/// Coarse bucket so fuzzy [isSameTransaction] only compares likely peers.
|
/// Coarse bucket so fuzzy [isSameTransaction] only compares likely peers.
|
||||||
String _dedupeBucket(BankTransaction tx) =>
|
String _dedupeBucket(BankTransaction tx) =>
|
||||||
'${tx.date}|${tx.currency.toUpperCase()}|${_amountCents(tx.amount)}';
|
'${tx.date}|${tx.currency.toUpperCase()}|${_amountCents(tx.amount)}';
|
||||||
|
|
||||||
|
String _amountCurrencyBucket(BankTransaction tx) =>
|
||||||
|
'${tx.currency.toUpperCase()}|${_amountCents(tx.amount)}';
|
||||||
|
|
||||||
|
/// Drop pending rows that already have a booked twin (same money + merchant).
|
||||||
|
List<BankTransaction> dropSettledPendingDuplicates(
|
||||||
|
List<BankTransaction> txs,
|
||||||
|
) {
|
||||||
|
final booked = [for (final tx in txs) if (!tx.pending) tx];
|
||||||
|
if (booked.isEmpty) return txs;
|
||||||
|
|
||||||
|
final bookedBuckets = <String, List<BankTransaction>>{};
|
||||||
|
for (final tx in booked) {
|
||||||
|
bookedBuckets.putIfAbsent(_amountCurrencyBucket(tx), () => []).add(tx);
|
||||||
|
}
|
||||||
|
|
||||||
|
final out = <BankTransaction>[];
|
||||||
|
for (final tx in txs) {
|
||||||
|
if (!tx.pending || tx.isManual) {
|
||||||
|
out.add(tx);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
final peers = bookedBuckets[_amountCurrencyBucket(tx)];
|
||||||
|
final settled =
|
||||||
|
peers != null && peers.any((b) => isPendingSettledBy(tx, b));
|
||||||
|
if (!settled) out.add(tx);
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Merge a fresh bank API page with locally cached history.
|
||||||
|
///
|
||||||
|
/// Pending rows are ephemeral: only the current API list may keep them
|
||||||
|
/// (except admin manuals). That stops settled/cancelled pendings from
|
||||||
|
/// living forever in the on-device cache after the bank drops them.
|
||||||
|
List<BankTransaction> mergeApiTransactionsWithCache(
|
||||||
|
List<BankTransaction> apiTxs,
|
||||||
|
List<BankTransaction> cached,
|
||||||
|
) {
|
||||||
|
final history = [
|
||||||
|
for (final tx in cached)
|
||||||
|
if (!tx.pending || tx.isManual) tx,
|
||||||
|
];
|
||||||
|
return dropSettledPendingDuplicates(mergeTransactions(apiTxs, history));
|
||||||
|
}
|
||||||
|
|
||||||
/// Merge [extra] into [existing], skipping duplicates. Newest date first.
|
/// Merge [extra] into [existing], skipping duplicates. Newest date first.
|
||||||
List<BankTransaction> mergeTransactions(
|
List<BankTransaction> mergeTransactions(
|
||||||
List<BankTransaction> existing,
|
List<BankTransaction> existing,
|
||||||
|
|||||||
@@ -25,20 +25,6 @@ List<BankTransaction> mergeBankTransactionLists(
|
|||||||
return mergeTransactions(local, remote);
|
return mergeTransactions(local, remote);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Union Overview favourites by client id (local wins on conflict).
|
|
||||||
List<OverviewFavourite> mergeOverviewFavourites(
|
|
||||||
List<OverviewFavourite> local,
|
|
||||||
List<OverviewFavourite> remote,
|
|
||||||
) {
|
|
||||||
final byId = <String, OverviewFavourite>{
|
|
||||||
for (final fav in remote) fav.id: fav,
|
|
||||||
};
|
|
||||||
for (final fav in local) {
|
|
||||||
byId[fav.id] = fav;
|
|
||||||
}
|
|
||||||
return byId.values.toList(growable: false);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Union-merge so neither device loses annotations on first sync.
|
/// Union-merge so neither device loses annotations on first sync.
|
||||||
TxMetaStoreData mergeTxMetaStores(TxMetaStoreData a, TxMetaStoreData b) {
|
TxMetaStoreData mergeTxMetaStores(TxMetaStoreData a, TxMetaStoreData b) {
|
||||||
final byId = <String, TxMeta>{...a.byId};
|
final byId = <String, TxMeta>{...a.byId};
|
||||||
@@ -485,6 +471,8 @@ class PbSyncService {
|
|||||||
),
|
),
|
||||||
invertExpensePerspective:
|
invertExpensePerspective:
|
||||||
r.getBoolValue('invert_expense_perspective'),
|
r.getBoolValue('invert_expense_perspective'),
|
||||||
|
updatedAt: _recordUpdatedAtMs(r),
|
||||||
|
deleted: r.getBoolValue('deleted'),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -544,6 +532,8 @@ class PbSyncService {
|
|||||||
'showAmountIn': r.getBoolValue('show_amount_in', true),
|
'showAmountIn': r.getBoolValue('show_amount_in', true),
|
||||||
'showAmountOut': r.getBoolValue('show_amount_out', true),
|
'showAmountOut': r.getBoolValue('show_amount_out', true),
|
||||||
'showCount': r.getBoolValue('show_count', true),
|
'showCount': r.getBoolValue('show_count', true),
|
||||||
|
'updatedAt': _recordUpdatedAtMs(r),
|
||||||
|
'deleted': r.getBoolValue('deleted'),
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -1364,6 +1354,8 @@ class PbSyncService {
|
|||||||
'flow': fav.flow.name,
|
'flow': fav.flow.name,
|
||||||
'bar_style': fav.barStyle.name,
|
'bar_style': fav.barStyle.name,
|
||||||
'invert_expense_perspective': fav.invertExpensePerspective,
|
'invert_expense_perspective': fav.invertExpensePerspective,
|
||||||
|
'updated_at': fav.updatedAt,
|
||||||
|
'deleted': fav.deleted,
|
||||||
};
|
};
|
||||||
final remote = existing[clientId];
|
final remote = existing[clientId];
|
||||||
if (remote == null) {
|
if (remote == null) {
|
||||||
@@ -1428,6 +1420,8 @@ class PbSyncService {
|
|||||||
'show_amount_in': w.showAmountIn,
|
'show_amount_in': w.showAmountIn,
|
||||||
'show_amount_out': w.showAmountOut,
|
'show_amount_out': w.showAmountOut,
|
||||||
'show_count': w.showCount,
|
'show_count': w.showCount,
|
||||||
|
'updated_at': w.updatedAt,
|
||||||
|
'deleted': w.deleted,
|
||||||
};
|
};
|
||||||
final remote = existing[clientId];
|
final remote = existing[clientId];
|
||||||
if (remote == null) {
|
if (remote == null) {
|
||||||
@@ -1533,7 +1527,9 @@ class PbSyncService {
|
|||||||
remote.getStringValue('flow') == fav.flow.name &&
|
remote.getStringValue('flow') == fav.flow.name &&
|
||||||
remote.getStringValue('bar_style') == fav.barStyle.name &&
|
remote.getStringValue('bar_style') == fav.barStyle.name &&
|
||||||
remote.getBoolValue('invert_expense_perspective') ==
|
remote.getBoolValue('invert_expense_perspective') ==
|
||||||
fav.invertExpensePerspective;
|
fav.invertExpensePerspective &&
|
||||||
|
remote.getBoolValue('deleted') == fav.deleted &&
|
||||||
|
_recordUpdatedAtMs(remote) == fav.updatedAt;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool _homeFilterWidgetUnchanged(RecordModel remote, HomeFilterWidget w) {
|
bool _homeFilterWidgetUnchanged(RecordModel remote, HomeFilterWidget w) {
|
||||||
@@ -1572,7 +1568,9 @@ class PbSyncService {
|
|||||||
remote.getBoolValue('month_only') == w.monthOnly &&
|
remote.getBoolValue('month_only') == w.monthOnly &&
|
||||||
remote.getBoolValue('show_amount_in', true) == w.showAmountIn &&
|
remote.getBoolValue('show_amount_in', true) == w.showAmountIn &&
|
||||||
remote.getBoolValue('show_amount_out', true) == w.showAmountOut &&
|
remote.getBoolValue('show_amount_out', true) == w.showAmountOut &&
|
||||||
remote.getBoolValue('show_count', true) == w.showCount;
|
remote.getBoolValue('show_count', true) == w.showCount &&
|
||||||
|
remote.getBoolValue('deleted') == w.deleted &&
|
||||||
|
_recordUpdatedAtMs(remote) == w.updatedAt;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool _appPrefsUnchanged(RecordModel remote, AppCloudPrefs prefs) {
|
bool _appPrefsUnchanged(RecordModel remote, AppCloudPrefs prefs) {
|
||||||
@@ -1585,6 +1583,20 @@ class PbSyncService {
|
|||||||
remote.getIntValue('look_ahead_max_years', 5) ==
|
remote.getIntValue('look_ahead_max_years', 5) ==
|
||||||
prefs.lookAheadMaxYears.clamp(1, 30);
|
prefs.lookAheadMaxYears.clamp(1, 30);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Prefer custom `updated_at`, else PocketBase system `updated`.
|
||||||
|
int _recordUpdatedAtMs(RecordModel r) {
|
||||||
|
final raw = r.get<dynamic>('updated_at');
|
||||||
|
final custom = switch (raw) {
|
||||||
|
int n => n,
|
||||||
|
num n => n.round(),
|
||||||
|
String s => int.tryParse(s) ?? 0,
|
||||||
|
_ => 0,
|
||||||
|
};
|
||||||
|
if (custom > 0) return custom;
|
||||||
|
final system = DateTime.tryParse(r.getStringValue('updated'));
|
||||||
|
return system?.millisecondsSinceEpoch ?? 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
RecurringTemplateSource _parseTemplateSource(String raw) {
|
RecurringTemplateSource _parseTemplateSource(String raw) {
|
||||||
|
|||||||
@@ -288,9 +288,80 @@ class _StatsBody extends StatelessWidget {
|
|||||||
final spentOnly = widgetConfig.showAmountOut &&
|
final spentOnly = widgetConfig.showAmountOut &&
|
||||||
!widgetConfig.showAmountIn &&
|
!widgetConfig.showAmountIn &&
|
||||||
!widgetConfig.showCount;
|
!widgetConfig.showCount;
|
||||||
|
final half = widgetConfig.halfWidth;
|
||||||
|
|
||||||
|
Widget metricsBlock({required bool alignEnd}) {
|
||||||
|
if (spentOnly) {
|
||||||
|
return Column(
|
||||||
|
crossAxisAlignment:
|
||||||
|
alignEnd ? CrossAxisAlignment.end : CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
'Spent',
|
||||||
|
style: theme.textTheme.labelMedium?.copyWith(
|
||||||
|
color: colors.onSurfaceVariant,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 2),
|
||||||
|
Text(
|
||||||
|
formatMoney(metrics.amountOut, currency),
|
||||||
|
style: theme.textTheme.titleMedium?.copyWith(
|
||||||
|
color: AppTheme.expense,
|
||||||
|
fontWeight: FontWeight.w700,
|
||||||
|
height: 1.15,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return Wrap(
|
||||||
|
spacing: 16,
|
||||||
|
runSpacing: 8,
|
||||||
|
alignment: alignEnd ? WrapAlignment.end : WrapAlignment.start,
|
||||||
|
children: [
|
||||||
|
if (widgetConfig.showAmountIn)
|
||||||
|
_Metric(
|
||||||
|
label: 'In',
|
||||||
|
value: formatMoney(metrics.amountIn, currency),
|
||||||
|
color: AppTheme.accent,
|
||||||
|
),
|
||||||
|
if (widgetConfig.showAmountOut)
|
||||||
|
_Metric(
|
||||||
|
label: 'Spent',
|
||||||
|
value: formatMoney(metrics.amountOut, currency),
|
||||||
|
color: AppTheme.expense,
|
||||||
|
),
|
||||||
|
if (widgetConfig.showCount)
|
||||||
|
_Metric(
|
||||||
|
label: 'Transactions',
|
||||||
|
value: '${metrics.count}',
|
||||||
|
color: colors.primary,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// Avoid LayoutBuilder/Spacer/Expanded here: half-width rows use
|
// Avoid LayoutBuilder/Spacer/Expanded here: half-width rows use
|
||||||
// IntrinsicHeight, which cannot measure those widgets.
|
// IntrinsicHeight, which cannot measure those widgets.
|
||||||
|
if (!half) {
|
||||||
|
return Row(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: _CardHeader(
|
||||||
|
icon: widgetConfig.icon,
|
||||||
|
title: widgetConfig.name,
|
||||||
|
subtitle: _subtitleFor(widgetConfig),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(width: 12),
|
||||||
|
Flexible(
|
||||||
|
child: metricsBlock(alignEnd: true),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return Column(
|
return Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
@@ -299,50 +370,8 @@ class _StatsBody extends StatelessWidget {
|
|||||||
title: widgetConfig.name,
|
title: widgetConfig.name,
|
||||||
subtitle: _subtitleFor(widgetConfig),
|
subtitle: _subtitleFor(widgetConfig),
|
||||||
),
|
),
|
||||||
if (spentOnly) ...[
|
SizedBox(height: spentOnly ? 32 : 14),
|
||||||
const SizedBox(height: 32),
|
metricsBlock(alignEnd: false),
|
||||||
Text(
|
|
||||||
'Spent',
|
|
||||||
style: theme.textTheme.labelMedium?.copyWith(
|
|
||||||
color: colors.onSurfaceVariant,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(height: 2),
|
|
||||||
Text(
|
|
||||||
formatMoney(metrics.amountOut, currency),
|
|
||||||
style: theme.textTheme.titleMedium?.copyWith(
|
|
||||||
color: AppTheme.expense,
|
|
||||||
fontWeight: FontWeight.w700,
|
|
||||||
height: 1.15,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
] else ...[
|
|
||||||
const SizedBox(height: 14),
|
|
||||||
Wrap(
|
|
||||||
spacing: 16,
|
|
||||||
runSpacing: 8,
|
|
||||||
children: [
|
|
||||||
if (widgetConfig.showAmountIn)
|
|
||||||
_Metric(
|
|
||||||
label: 'In',
|
|
||||||
value: formatMoney(metrics.amountIn, currency),
|
|
||||||
color: AppTheme.accent,
|
|
||||||
),
|
|
||||||
if (widgetConfig.showAmountOut)
|
|
||||||
_Metric(
|
|
||||||
label: 'Spent',
|
|
||||||
value: formatMoney(metrics.amountOut, currency),
|
|
||||||
color: AppTheme.expense,
|
|
||||||
),
|
|
||||||
if (widgetConfig.showCount)
|
|
||||||
_Metric(
|
|
||||||
label: 'Txs',
|
|
||||||
value: '${metrics.count}',
|
|
||||||
color: colors.primary,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
],
|
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,48 @@
|
|||||||
|
/// PocketBase migration: `updated_at` + `deleted` on overview favourites and
|
||||||
|
/// home filter widgets for cross-device last-write-wins sync.
|
||||||
|
///
|
||||||
|
/// Apply on the server:
|
||||||
|
///
|
||||||
|
/// sudo cp this_file /opt/pocketbase/pb_migrations/
|
||||||
|
/// sudo chown pocketbase:pocketbase /opt/pocketbase/pb_migrations/*.js
|
||||||
|
/// sudo -u pocketbase /opt/pocketbase/pocketbase migrate up
|
||||||
|
/// sudo systemctl restart pocketbase
|
||||||
|
migrate((app) => {
|
||||||
|
function addSyncFields(collectionName) {
|
||||||
|
const col = app.findCollectionByNameOrId(collectionName);
|
||||||
|
let changed = false;
|
||||||
|
if (!col.fields.getByName("updated_at")) {
|
||||||
|
col.fields.add(new Field({
|
||||||
|
type: "number",
|
||||||
|
name: "updated_at",
|
||||||
|
required: false,
|
||||||
|
}));
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
if (!col.fields.getByName("deleted")) {
|
||||||
|
col.fields.add(new Field({
|
||||||
|
type: "bool",
|
||||||
|
name: "deleted",
|
||||||
|
required: false,
|
||||||
|
}));
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
if (changed) app.save(col);
|
||||||
|
}
|
||||||
|
|
||||||
|
addSyncFields("overview_favourites");
|
||||||
|
addSyncFields("home_filter_widgets");
|
||||||
|
}, (app) => {
|
||||||
|
function removeSyncFields(collectionName) {
|
||||||
|
try {
|
||||||
|
const col = app.findCollectionByNameOrId(collectionName);
|
||||||
|
const updated = col.fields.getByName("updated_at");
|
||||||
|
if (updated) col.fields.removeById(updated.id);
|
||||||
|
const deleted = col.fields.getByName("deleted");
|
||||||
|
if (deleted) col.fields.removeById(deleted.id);
|
||||||
|
app.save(col);
|
||||||
|
} catch (_) {}
|
||||||
|
}
|
||||||
|
removeSyncFields("overview_favourites");
|
||||||
|
removeSyncFields("home_filter_widgets");
|
||||||
|
});
|
||||||
@@ -93,10 +93,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: clock
|
name: clock
|
||||||
sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b
|
sha256: e51d50bca3217c9a9fa2b41a30e4a38971133f5f9ec7a3d57bae095007f1d28e
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.1.2"
|
version: "1.1.3"
|
||||||
collection:
|
collection:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -356,10 +356,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: platform
|
name: platform
|
||||||
sha256: "5d6b1b0036a5f331ebc77c850ebc8506cbc1e9416c27e59b439f917a902a4984"
|
sha256: a36d119c13416516a7b5913fbe8af8531e11633d784c550b2125f76c758524ec
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.1.6"
|
version: "3.2.0"
|
||||||
plugin_platform_interface:
|
plugin_platform_interface:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -465,10 +465,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: stack_trace
|
name: stack_trace
|
||||||
sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1"
|
sha256: "277654b3034d17ac6f9f1cb5595db011b1d5d41e8806866db28e0abaa101c490"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.12.1"
|
version: "1.12.2"
|
||||||
stream_channel:
|
stream_channel:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|||||||
@@ -58,4 +58,71 @@ Datum,Naam / Omschrijving,Rekening,Tegenrekening,Code,Af Bij,Bedrag (EUR),Mutati
|
|||||||
);
|
);
|
||||||
expect(isSameTransaction(api, csv), isTrue);
|
expect(isSameTransaction(api, csv), isTrue);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('API merge drops stale pending not returned by the bank', () {
|
||||||
|
const stalePending = BankTransaction(
|
||||||
|
date: '2026-09-01',
|
||||||
|
description: 'AH CAMPUS DIEMEN',
|
||||||
|
amount: -12.5,
|
||||||
|
currency: 'EUR',
|
||||||
|
pending: true,
|
||||||
|
);
|
||||||
|
const settled = BankTransaction(
|
||||||
|
date: '2026-09-03',
|
||||||
|
description: 'BCK*AH CAMPUS DIEMEN ZUID NLD',
|
||||||
|
amount: -12.5,
|
||||||
|
currency: 'EUR',
|
||||||
|
pending: false,
|
||||||
|
);
|
||||||
|
const olderBooked = BankTransaction(
|
||||||
|
date: '2026-08-01',
|
||||||
|
description: 'SALARIS',
|
||||||
|
amount: 2000,
|
||||||
|
currency: 'EUR',
|
||||||
|
pending: false,
|
||||||
|
);
|
||||||
|
|
||||||
|
final merged = mergeApiTransactionsWithCache(
|
||||||
|
[settled],
|
||||||
|
[stalePending, olderBooked],
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(merged, hasLength(2));
|
||||||
|
expect(merged.any((tx) => tx.pending), isFalse);
|
||||||
|
expect(merged.any((tx) => tx.description.contains('SALARIS')), isTrue);
|
||||||
|
expect(merged.any((tx) => tx.description.contains('AH CAMPUS')), isTrue);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('API merge keeps live pending from the feed', () {
|
||||||
|
const livePending = BankTransaction(
|
||||||
|
date: '2026-09-10',
|
||||||
|
description: 'PENDING COFFEE',
|
||||||
|
amount: -4.0,
|
||||||
|
currency: 'EUR',
|
||||||
|
pending: true,
|
||||||
|
);
|
||||||
|
final merged = mergeApiTransactionsWithCache([livePending], const []);
|
||||||
|
expect(merged, hasLength(1));
|
||||||
|
expect(merged.single.pending, isTrue);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('dropSettledPendingDuplicates removes pending twin of booked', () {
|
||||||
|
const pending = BankTransaction(
|
||||||
|
date: '2026-09-01',
|
||||||
|
description: 'AH CAMPUS DIEMEN',
|
||||||
|
amount: -12.5,
|
||||||
|
currency: 'EUR',
|
||||||
|
pending: true,
|
||||||
|
);
|
||||||
|
const booked = BankTransaction(
|
||||||
|
date: '2026-09-02',
|
||||||
|
description: 'BCK*AH CAMPUS DIEMEN ZUID',
|
||||||
|
amount: -12.5,
|
||||||
|
currency: 'EUR',
|
||||||
|
pending: false,
|
||||||
|
);
|
||||||
|
final cleaned = dropSettledPendingDuplicates([pending, booked]);
|
||||||
|
expect(cleaned, hasLength(1));
|
||||||
|
expect(cleaned.single.pending, isFalse);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import 'package:flutter_test/flutter_test.dart';
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
import 'package:myapp/models/overview_favourite.dart';
|
import 'package:myapp/models/overview_favourite.dart';
|
||||||
import 'package:myapp/models/transaction_meta.dart';
|
import 'package:myapp/models/transaction_meta.dart';
|
||||||
import 'package:myapp/services/pb_sync_service.dart';
|
|
||||||
import 'package:myapp/widgets/label_filter_dialog.dart';
|
import 'package:myapp/widgets/label_filter_dialog.dart';
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
@@ -16,6 +15,8 @@ void main() {
|
|||||||
flow: TxFlowFilter.expense,
|
flow: TxFlowFilter.expense,
|
||||||
barStyle: LabelChartBarStyle.stacked,
|
barStyle: LabelChartBarStyle.stacked,
|
||||||
invertExpensePerspective: false,
|
invertExpensePerspective: false,
|
||||||
|
updatedAt: 100,
|
||||||
|
deleted: false,
|
||||||
);
|
);
|
||||||
|
|
||||||
final restored = OverviewFavourite.fromJson(fav.toJson());
|
final restored = OverviewFavourite.fromJson(fav.toJson());
|
||||||
@@ -27,35 +28,53 @@ void main() {
|
|||||||
expect(restored.labelIds, ['groceries', 'custom_ah']);
|
expect(restored.labelIds, ['groceries', 'custom_ah']);
|
||||||
expect(restored.flow, TxFlowFilter.expense);
|
expect(restored.flow, TxFlowFilter.expense);
|
||||||
expect(restored.barStyle, LabelChartBarStyle.stacked);
|
expect(restored.barStyle, LabelChartBarStyle.stacked);
|
||||||
|
expect(restored.updatedAt, 100);
|
||||||
|
expect(restored.deleted, isFalse);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('mergeOverviewFavourites unions by id with local wins', () {
|
test('mergeOverviewFavourites unions by id with last-write-wins', () {
|
||||||
const local = OverviewFavourite(
|
const local = OverviewFavourite(
|
||||||
id: 'fav_1',
|
id: 'fav_1',
|
||||||
name: 'Local name',
|
name: 'Local name',
|
||||||
display: true,
|
display: true,
|
||||||
|
updatedAt: 200,
|
||||||
);
|
);
|
||||||
const remoteOnly = OverviewFavourite(
|
const remoteOnly = OverviewFavourite(
|
||||||
id: 'fav_2',
|
id: 'fav_2',
|
||||||
name: 'Remote only',
|
name: 'Remote only',
|
||||||
display: false,
|
display: false,
|
||||||
metric: OverviewMetricMode.labels,
|
metric: OverviewMetricMode.labels,
|
||||||
|
updatedAt: 50,
|
||||||
);
|
);
|
||||||
const remoteConflict = OverviewFavourite(
|
const remoteConflictOlder = OverviewFavourite(
|
||||||
id: 'fav_1',
|
id: 'fav_1',
|
||||||
name: 'Remote name',
|
name: 'Remote name',
|
||||||
display: false,
|
display: false,
|
||||||
|
updatedAt: 100,
|
||||||
|
);
|
||||||
|
const remoteConflictNewer = OverviewFavourite(
|
||||||
|
id: 'fav_3',
|
||||||
|
name: 'Remote newer',
|
||||||
|
display: true,
|
||||||
|
updatedAt: 300,
|
||||||
|
);
|
||||||
|
const localOlder = OverviewFavourite(
|
||||||
|
id: 'fav_3',
|
||||||
|
name: 'Local older',
|
||||||
|
display: false,
|
||||||
|
updatedAt: 10,
|
||||||
);
|
);
|
||||||
|
|
||||||
final merged = mergeOverviewFavourites(
|
final merged = mergeOverviewFavourites(
|
||||||
[local],
|
[local, localOlder],
|
||||||
[remoteConflict, remoteOnly],
|
[remoteConflictOlder, remoteOnly, remoteConflictNewer],
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(merged.length, 2);
|
expect(merged.length, 3);
|
||||||
final byId = {for (final f in merged) f.id: f};
|
final byId = {for (final f in merged) f.id: f};
|
||||||
expect(byId['fav_1']!.name, 'Local name');
|
expect(byId['fav_1']!.name, 'Local name');
|
||||||
expect(byId['fav_1']!.display, isTrue);
|
expect(byId['fav_1']!.display, isTrue);
|
||||||
expect(byId['fav_2']!.name, 'Remote only');
|
expect(byId['fav_2']!.name, 'Remote only');
|
||||||
|
expect(byId['fav_3']!.name, 'Remote newer');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||