Added custom tour ordering

This commit is contained in:
Dennis Nemec
2025-12-20 21:00:33 +01:00
parent 0c61f65961
commit edb8676f5a
13 changed files with 502 additions and 166 deletions

View File

@ -14,6 +14,8 @@
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
997C0E4FB7B2C67AB8388B3F /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FB0CFA44E0F4A317CC3E8B41 /* Pods_RunnerTests.framework */; };
CAFC9CC8D4DE6A37AF21BCD7 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0F2499FC75E94DB5A00A1507 /* Pods_Runner.framework */; };
/* End PBXBuildFile section */ /* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */ /* Begin PBXContainerItemProxy section */
@ -40,14 +42,20 @@
/* End PBXCopyFilesBuildPhase section */ /* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */ /* Begin PBXFileReference section */
0F2499FC75E94DB5A00A1507 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; }; 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>"; }; 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; };
20C61E69ACC59657689C39B0 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = "<group>"; };
2504B6EAF74460EDFF2C3034 /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = "<group>"; };
2F591058654CE4129294673B /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = "<group>"; };
331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; 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; }; 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>"; }; 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
6E068ED7E85C34D749C5FEEC /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = "<group>"; };
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; 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>"; }; 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; };
85C723A0EDD97FFF5B2BD758 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = "<group>"; };
9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.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>"; }; 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; }; 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
@ -55,13 +63,24 @@
97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; 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>"; }; 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>"; }; 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
F632AF4257FECE6E4D6B8524 /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = "<group>"; };
FB0CFA44E0F4A317CC3E8B41 /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
/* End PBXFileReference section */ /* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */ /* Begin PBXFrameworksBuildPhase section */
8C070AF792EDA6C56B543C6F /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
997C0E4FB7B2C67AB8388B3F /* Pods_RunnerTests.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
97C146EB1CF9000F007C117D /* Frameworks */ = { 97C146EB1CF9000F007C117D /* Frameworks */ = {
isa = PBXFrameworksBuildPhase; isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
CAFC9CC8D4DE6A37AF21BCD7 /* Pods_Runner.framework in Frameworks */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
@ -76,6 +95,15 @@
path = RunnerTests; path = RunnerTests;
sourceTree = "<group>"; sourceTree = "<group>";
}; };
7A92659C1D86874FFAC72EDC /* Frameworks */ = {
isa = PBXGroup;
children = (
0F2499FC75E94DB5A00A1507 /* Pods_Runner.framework */,
FB0CFA44E0F4A317CC3E8B41 /* Pods_RunnerTests.framework */,
);
name = Frameworks;
sourceTree = "<group>";
};
9740EEB11CF90186004384FC /* Flutter */ = { 9740EEB11CF90186004384FC /* Flutter */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
@ -94,6 +122,8 @@
97C146F01CF9000F007C117D /* Runner */, 97C146F01CF9000F007C117D /* Runner */,
97C146EF1CF9000F007C117D /* Products */, 97C146EF1CF9000F007C117D /* Products */,
331C8082294A63A400263BE5 /* RunnerTests */, 331C8082294A63A400263BE5 /* RunnerTests */,
ED39057CEE7CA15DEFF8D2EE /* Pods */,
7A92659C1D86874FFAC72EDC /* Frameworks */,
); );
sourceTree = "<group>"; sourceTree = "<group>";
}; };
@ -121,6 +151,19 @@
path = Runner; path = Runner;
sourceTree = "<group>"; sourceTree = "<group>";
}; };
ED39057CEE7CA15DEFF8D2EE /* Pods */ = {
isa = PBXGroup;
children = (
85C723A0EDD97FFF5B2BD758 /* Pods-Runner.debug.xcconfig */,
6E068ED7E85C34D749C5FEEC /* Pods-Runner.release.xcconfig */,
20C61E69ACC59657689C39B0 /* Pods-Runner.profile.xcconfig */,
2F591058654CE4129294673B /* Pods-RunnerTests.debug.xcconfig */,
F632AF4257FECE6E4D6B8524 /* Pods-RunnerTests.release.xcconfig */,
2504B6EAF74460EDFF2C3034 /* Pods-RunnerTests.profile.xcconfig */,
);
path = Pods;
sourceTree = "<group>";
};
/* End PBXGroup section */ /* End PBXGroup section */
/* Begin PBXNativeTarget section */ /* Begin PBXNativeTarget section */
@ -128,8 +171,10 @@
isa = PBXNativeTarget; isa = PBXNativeTarget;
buildConfigurationList = 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; buildConfigurationList = 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */;
buildPhases = ( buildPhases = (
2682F75C0133161F95975778 /* [CP] Check Pods Manifest.lock */,
331C807D294A63A400263BE5 /* Sources */, 331C807D294A63A400263BE5 /* Sources */,
331C807F294A63A400263BE5 /* Resources */, 331C807F294A63A400263BE5 /* Resources */,
8C070AF792EDA6C56B543C6F /* Frameworks */,
); );
buildRules = ( buildRules = (
); );
@ -145,12 +190,14 @@
isa = PBXNativeTarget; isa = PBXNativeTarget;
buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
buildPhases = ( buildPhases = (
4C53ED7C58784643594B286A /* [CP] Check Pods Manifest.lock */,
9740EEB61CF901F6004384FC /* Run Script */, 9740EEB61CF901F6004384FC /* Run Script */,
97C146EA1CF9000F007C117D /* Sources */, 97C146EA1CF9000F007C117D /* Sources */,
97C146EB1CF9000F007C117D /* Frameworks */, 97C146EB1CF9000F007C117D /* Frameworks */,
97C146EC1CF9000F007C117D /* Resources */, 97C146EC1CF9000F007C117D /* Resources */,
9705A1C41CF9048500538489 /* Embed Frameworks */, 9705A1C41CF9048500538489 /* Embed Frameworks */,
3B06AD1E1E4923F5004D2608 /* Thin Binary */, 3B06AD1E1E4923F5004D2608 /* Thin Binary */,
174761F3B03AFDA6621CD1D2 /* [CP] Embed Pods Frameworks */,
); );
buildRules = ( buildRules = (
); );
@ -222,6 +269,45 @@
/* End PBXResourcesBuildPhase section */ /* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */
174761F3B03AFDA6621CD1D2 /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist",
);
name = "[CP] Embed Pods Frameworks";
outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
2682F75C0133161F95975778 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
"${PODS_ROOT}/Manifest.lock",
);
name = "[CP] Check Pods Manifest.lock";
outputFileListPaths = (
);
outputPaths = (
"$(DERIVED_FILE_DIR)/Pods-RunnerTests-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
isa = PBXShellScriptBuildPhase; isa = PBXShellScriptBuildPhase;
alwaysOutOfDate = 1; alwaysOutOfDate = 1;
@ -238,6 +324,28 @@
shellPath = /bin/sh; shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin";
}; };
4C53ED7C58784643594B286A /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
"${PODS_ROOT}/Manifest.lock",
);
name = "[CP] Check Pods Manifest.lock";
outputFileListPaths = (
);
outputPaths = (
"$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
9740EEB61CF901F6004384FC /* Run Script */ = { 9740EEB61CF901F6004384FC /* Run Script */ = {
isa = PBXShellScriptBuildPhase; isa = PBXShellScriptBuildPhase;
alwaysOutOfDate = 1; alwaysOutOfDate = 1;
@ -365,6 +473,7 @@
DEVELOPMENT_TEAM = 37Z4ZA4QU2; DEVELOPMENT_TEAM = 37Z4ZA4QU2;
ENABLE_BITCODE = NO; ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist; INFOPLIST_FILE = Runner/Info.plist;
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.business";
LD_RUNPATH_SEARCH_PATHS = ( LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",
@ -379,6 +488,7 @@
}; };
331C8088294A63A400263BE5 /* Debug */ = { 331C8088294A63A400263BE5 /* Debug */ = {
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
baseConfigurationReference = 2F591058654CE4129294673B /* Pods-RunnerTests.debug.xcconfig */;
buildSettings = { buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)"; BUNDLE_LOADER = "$(TEST_HOST)";
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
@ -396,6 +506,7 @@
}; };
331C8089294A63A400263BE5 /* Release */ = { 331C8089294A63A400263BE5 /* Release */ = {
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
baseConfigurationReference = F632AF4257FECE6E4D6B8524 /* Pods-RunnerTests.release.xcconfig */;
buildSettings = { buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)"; BUNDLE_LOADER = "$(TEST_HOST)";
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
@ -411,6 +522,7 @@
}; };
331C808A294A63A400263BE5 /* Profile */ = { 331C808A294A63A400263BE5 /* Profile */ = {
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
baseConfigurationReference = 2504B6EAF74460EDFF2C3034 /* Pods-RunnerTests.profile.xcconfig */;
buildSettings = { buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)"; BUNDLE_LOADER = "$(TEST_HOST)";
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
@ -545,6 +657,7 @@
DEVELOPMENT_TEAM = 37Z4ZA4QU2; DEVELOPMENT_TEAM = 37Z4ZA4QU2;
ENABLE_BITCODE = NO; ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist; INFOPLIST_FILE = Runner/Info.plist;
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.business";
LD_RUNPATH_SEARCH_PATHS = ( LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",
@ -568,6 +681,7 @@
DEVELOPMENT_TEAM = 37Z4ZA4QU2; DEVELOPMENT_TEAM = 37Z4ZA4QU2;
ENABLE_BITCODE = NO; ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist; INFOPLIST_FILE = Runner/Info.plist;
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.business";
LD_RUNPATH_SEARCH_PATHS = ( LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",

View File

@ -4,4 +4,7 @@
<FileRef <FileRef
location = "group:Runner.xcodeproj"> location = "group:Runner.xcodeproj">
</FileRef> </FileRef>
<FileRef
location = "group:Pods/Pods.xcodeproj">
</FileRef>
</Workspace> </Workspace>

View File

@ -60,7 +60,7 @@ class _LoginPageState extends State<LoginPage> {
debugPrint("🔵 Opening browser to: http://localhost:3000/login"); debugPrint("🔵 Opening browser to: http://localhost:3000/login");
final loginUrl = Uri.parse('http://192.168.1.9:3000/login'); final loginUrl = Uri.parse('http://100.72.100.33:3000/login');
final launched = await launchUrl( final launched = await launchUrl(
loginUrl, loginUrl,
mode: LaunchMode.externalApplication, mode: LaunchMode.externalApplication,

View File

@ -56,7 +56,7 @@ class _CarManagementPageState extends State<CarManagementPage> {
return Scaffold( return Scaffold(
body: BlocConsumer<CarsBloc, CarsState>( body: BlocConsumer<CarsBloc, CarsState>(
listener: (context, state) { listener: (context, state) {
if (state is CarsLoaded) { if (state is CarsLoaded && context.read<TourBloc>().state is TourLoaded) {
var tour = (context.read<TourBloc>().state as TourLoaded).tour.copyWith(); var tour = (context.read<TourBloc>().state as TourLoaded).tour.copyWith();
tour.driver.cars = state.cars; tour.driver.cars = state.cars;
context.read<TourBloc>().add(UpdateTour(tour: tour)); context.read<TourBloc>().add(UpdateTour(tour: tour));

View File

@ -4,6 +4,8 @@ import 'package:hl_lieferservice/dto/discount_add_response.dart';
import 'package:hl_lieferservice/dto/discount_update_response.dart'; import 'package:hl_lieferservice/dto/discount_update_response.dart';
import 'package:hl_lieferservice/feature/delivery/detail/bloc/delivery_event.dart'; import 'package:hl_lieferservice/feature/delivery/detail/bloc/delivery_event.dart';
import 'package:hl_lieferservice/feature/delivery/detail/bloc/delivery_state.dart'; import 'package:hl_lieferservice/feature/delivery/detail/bloc/delivery_state.dart';
import 'package:hl_lieferservice/feature/delivery/detail/bloc/note_bloc.dart';
import 'package:hl_lieferservice/feature/delivery/detail/bloc/note_event.dart';
import 'package:hl_lieferservice/feature/delivery/detail/repository/delivery_repository.dart'; import 'package:hl_lieferservice/feature/delivery/detail/repository/delivery_repository.dart';
import 'package:hl_lieferservice/feature/delivery/detail/repository/note_repository.dart'; import 'package:hl_lieferservice/feature/delivery/detail/repository/note_repository.dart';
import 'package:hl_lieferservice/widget/operations/bloc/operation_bloc.dart'; import 'package:hl_lieferservice/widget/operations/bloc/operation_bloc.dart';
@ -15,6 +17,7 @@ import '../../../../model/delivery.dart' as model;
class DeliveryBloc extends Bloc<DeliveryEvent, DeliveryState> { class DeliveryBloc extends Bloc<DeliveryEvent, DeliveryState> {
OperationBloc opBloc; OperationBloc opBloc;
NoteBloc noteBloc;
DeliveryRepository repository; DeliveryRepository repository;
NoteRepository noteRepository; NoteRepository noteRepository;
@ -22,6 +25,7 @@ class DeliveryBloc extends Bloc<DeliveryEvent, DeliveryState> {
required this.opBloc, required this.opBloc,
required this.repository, required this.repository,
required this.noteRepository, required this.noteRepository,
required this.noteBloc
}) : super(DeliveryInitial()) { }) : super(DeliveryInitial()) {
on<UnscanArticleEvent>(_unscan); on<UnscanArticleEvent>(_unscan);
on<ResetScanAmountEvent>(_resetAmount); on<ResetScanAmountEvent>(_resetAmount);
@ -34,10 +38,8 @@ class DeliveryBloc extends Bloc<DeliveryEvent, DeliveryState> {
on<FinishDeliveryEvent>(_finishDelivery); on<FinishDeliveryEvent>(_finishDelivery);
} }
void _finishDelivery( void _finishDelivery(FinishDeliveryEvent event,
FinishDeliveryEvent event, Emitter<DeliveryState> emit,) async {
Emitter<DeliveryState> emit,
) async {
final currentState = state; final currentState = state;
opBloc.add(LoadOperation()); opBloc.add(LoadOperation());
@ -70,10 +72,8 @@ class DeliveryBloc extends Bloc<DeliveryEvent, DeliveryState> {
} }
} }
void _updatePayment( void _updatePayment(UpdateSelectedPaymentMethodEvent event,
UpdateSelectedPaymentMethodEvent event, Emitter<DeliveryState> emit,) {
Emitter<DeliveryState> emit,
) {
final currentState = state; final currentState = state;
if (currentState is DeliveryLoaded) { if (currentState is DeliveryLoaded) {
@ -85,25 +85,23 @@ class DeliveryBloc extends Bloc<DeliveryEvent, DeliveryState> {
} }
} }
void _updateDeliveryOptions( void _updateDeliveryOptions(UpdateDeliveryOptionEvent event,
UpdateDeliveryOptionEvent event, Emitter<DeliveryState> emit,) {
Emitter<DeliveryState> emit,
) {
final currentState = state; final currentState = state;
if (currentState is DeliveryLoaded) { if (currentState is DeliveryLoaded) {
List<model.DeliveryOption> options = List<model.DeliveryOption> options =
currentState.delivery.options.map((option) { currentState.delivery.options.map((option) {
if (option.key == event.key) { if (option.key == event.key) {
if (option.numerical) { if (option.numerical) {
return option.copyWith(value: event.value); return option.copyWith(value: event.value);
} else { } else {
return option.copyWith(value: event.value == true ? "1" : "0"); return option.copyWith(value: event.value == true ? "1" : "0");
} }
} }
return option; return option;
}).toList(); }).toList();
emit( emit(
DeliveryLoaded( DeliveryLoaded(
@ -113,10 +111,8 @@ class DeliveryBloc extends Bloc<DeliveryEvent, DeliveryState> {
} }
} }
void _updateDiscount( void _updateDiscount(UpdateDiscountEvent event,
UpdateDiscountEvent event, Emitter<DeliveryState> emit,) async {
Emitter<DeliveryState> emit,
) async {
opBloc.add(LoadOperation()); opBloc.add(LoadOperation());
try { try {
@ -139,22 +135,22 @@ class DeliveryBloc extends Bloc<DeliveryEvent, DeliveryState> {
String discountArticleNumber = delivery.discount!.article.articleNumber; String discountArticleNumber = delivery.discount!.article.articleNumber;
delivery.discount = model.Discount( delivery.discount = model.Discount(
article: article:
response.values?.article != null response.values?.article != null
? Article.fromDTO(response.values!.article) ? Article.fromDTO(response.values!.article)
: delivery.discount!.article, : delivery.discount!.article,
note: note:
response.values?.note != null response.values?.note != null
? response.values!.note.noteDescription ? response.values!.note.noteDescription
: delivery.discount!.note, : delivery.discount!.note,
noteId: noteId:
response.values?.note != null response.values?.note != null
? response.values!.note.rowId ? response.values!.note.rowId
: delivery.discount!.noteId, : delivery.discount!.noteId,
); );
delivery.articles = [ delivery.articles = [
...delivery.articles.where( ...delivery.articles.where(
(article) => article.articleNumber != discountArticleNumber, (article) => article.articleNumber != discountArticleNumber,
), ),
delivery.discount!.article, delivery.discount!.article,
]; ];
@ -165,7 +161,8 @@ class DeliveryBloc extends Bloc<DeliveryEvent, DeliveryState> {
} }
} catch (e, st) { } catch (e, st) {
debugPrint( debugPrint(
"Fehler beim Hinzufügen eins Discounts zur Lieferung: ${event.deliveryId}:", "Fehler beim Hinzufügen eins Discounts zur Lieferung: ${event
.deliveryId}:",
); );
debugPrint("$e"); debugPrint("$e");
debugPrint("$st"); debugPrint("$st");
@ -176,10 +173,8 @@ class DeliveryBloc extends Bloc<DeliveryEvent, DeliveryState> {
} }
} }
void _removeDiscount( void _removeDiscount(RemoveDiscountEvent event,
RemoveDiscountEvent event, Emitter<DeliveryState> emit,) async {
Emitter<DeliveryState> emit,
) async {
opBloc.add(LoadOperation()); opBloc.add(LoadOperation());
try { try {
@ -196,9 +191,9 @@ class DeliveryBloc extends Bloc<DeliveryEvent, DeliveryState> {
delivery.articles delivery.articles
.where( .where(
(article) => (article) =>
article.internalId != article.internalId !=
delivery.discount?.article.internalId, delivery.discount?.article.internalId,
) )
.toList(); .toList();
delivery.discount = null; delivery.discount = null;
@ -245,6 +240,10 @@ class DeliveryBloc extends Bloc<DeliveryEvent, DeliveryState> {
noteId: response.values.note.rowId, noteId: response.values.note.rowId,
); );
noteBloc.add(AddNoteOffline(note: response.values.note.noteDescription,
deliveryId: delivery.id,
noteId: response.values.note.rowId));
delivery.articles = [...delivery.articles, delivery.discount!.article]; delivery.articles = [...delivery.articles, delivery.discount!.article];
emit(currentState.copyWith(delivery)); emit(currentState.copyWith(delivery));
@ -253,7 +252,8 @@ class DeliveryBloc extends Bloc<DeliveryEvent, DeliveryState> {
} }
} catch (e, st) { } catch (e, st) {
debugPrint( debugPrint(
"Fehler beim Hinzufügen eins Discounts zur Lieferung: ${event.deliveryId}:", "Fehler beim Hinzufügen eins Discounts zur Lieferung: ${event
.deliveryId}:",
); );
debugPrint("$e"); debugPrint("$e");
debugPrint("$st"); debugPrint("$st");
@ -284,7 +284,7 @@ class DeliveryBloc extends Bloc<DeliveryEvent, DeliveryState> {
if (currentState is DeliveryLoaded) { if (currentState is DeliveryLoaded) {
Article article = currentState.delivery.articles.firstWhere( Article article = currentState.delivery.articles.firstWhere(
(article) => article.internalId == int.parse(event.articleId), (article) => article.internalId == int.parse(event.articleId),
); );
article.removeNoteId = noteId; article.removeNoteId = noteId;
@ -293,7 +293,7 @@ class DeliveryBloc extends Bloc<DeliveryEvent, DeliveryState> {
List<Article> articles = [ List<Article> articles = [
...currentState.delivery.articles.where( ...currentState.delivery.articles.where(
(article) => article.internalId != int.parse(event.articleId), (article) => article.internalId != int.parse(event.articleId),
), ),
article, article,
]; ];
@ -313,10 +313,8 @@ class DeliveryBloc extends Bloc<DeliveryEvent, DeliveryState> {
} }
} }
void _resetAmount( void _resetAmount(ResetScanAmountEvent event,
ResetScanAmountEvent event, Emitter<DeliveryState> emit,) async {
Emitter<DeliveryState> emit,
) async {
opBloc.add(LoadOperation()); opBloc.add(LoadOperation());
try { try {
@ -325,7 +323,7 @@ class DeliveryBloc extends Bloc<DeliveryEvent, DeliveryState> {
if (currentState is DeliveryLoaded) { if (currentState is DeliveryLoaded) {
Article article = currentState.delivery.articles.firstWhere( Article article = currentState.delivery.articles.firstWhere(
(article) => article.internalId == int.parse(event.articleId), (article) => article.internalId == int.parse(event.articleId),
); );
article.removeNoteId = null; article.removeNoteId = null;
@ -334,7 +332,7 @@ class DeliveryBloc extends Bloc<DeliveryEvent, DeliveryState> {
List<Article> articles = [ List<Article> articles = [
...currentState.delivery.articles.where( ...currentState.delivery.articles.where(
(article) => article.internalId != int.parse(event.articleId), (article) => article.internalId != int.parse(event.articleId),
), ),
article, article,
]; ];

View File

@ -15,7 +15,7 @@ class NoteBloc extends Bloc<NoteEvent, NoteState> {
final OperationBloc opBloc; final OperationBloc opBloc;
NoteBloc({required this.repository, required this.opBloc}) NoteBloc({required this.repository, required this.opBloc})
: super(NoteInitial()) { : super(NoteInitial()) {
on<LoadNote>(_load); on<LoadNote>(_load);
on<AddNote>(_add); on<AddNote>(_add);
on<EditNote>(_edit); on<EditNote>(_edit);
@ -23,16 +23,44 @@ class NoteBloc extends Bloc<NoteEvent, NoteState> {
on<AddImageNote>(_upload); on<AddImageNote>(_upload);
on<RemoveImageNote>(_removeImage); on<RemoveImageNote>(_removeImage);
on<ResetNotes>(_reset); on<ResetNotes>(_reset);
on<AddNoteOffline>(_addOffline);
} }
Future<void> _reset(ResetNotes event, Emitter<NoteState> emit) async { Future<void> _reset(ResetNotes event, Emitter<NoteState> emit) async {
emit.call(NoteInitial()); emit.call(NoteInitial());
} }
Future<void> _removeImage( Future<void> _addOffline(AddNoteOffline event,
RemoveImageNote event, Emitter<NoteState> emit,) async {
Emitter<NoteState> emit, if (state is NoteInitial) {
) async { emit(
NoteLoadedBase(
notes: [Note(content: event.note, id: int.parse(event.noteId))],
),
);
}
if (state is NoteLoadedBase) {
emit(
NoteLoadedBase(
notes: [
...(state as NoteLoadedBase).notes,
Note(content: event.note, id: int.parse(event.noteId)),
],
),
);
}
if (state is NoteLoaded) {
final current = state as NoteLoaded;
emit(NoteLoaded(notes: [...current.notes, Note(content: event.note, id: int.parse(event.noteId))],
templates: [...current.templates],
images: [...current.images]));
}
}
Future<void> _removeImage(RemoveImageNote event,
Emitter<NoteState> emit,) async {
opBloc.add(LoadOperation()); opBloc.add(LoadOperation());
try { try {
@ -43,9 +71,9 @@ class NoteBloc extends Bloc<NoteEvent, NoteState> {
emit.call( emit.call(
currentState.copyWith( currentState.copyWith(
images: images:
currentState.images currentState.images
.where((image) => image.$1.objectId != event.objectId) .where((image) => image.$1.objectId != event.objectId)
.toList(), .toList(),
), ),
); );
} }
@ -89,7 +117,7 @@ class NoteBloc extends Bloc<NoteEvent, NoteState> {
try { try {
List<String> urls = List<String> urls =
event.delivery.images.map((image) => image.url).toList(); event.delivery.images.map((image) => image.url).toList();
List<Note> notes = await repository.loadNotes(event.delivery.id); List<Note> notes = await repository.loadNotes(event.delivery.id);
List<NoteTemplate> templates = await repository.loadTemplates(); List<NoteTemplate> templates = await repository.loadTemplates();
List<Uint8List> images = await repository.loadImages(urls); List<Uint8List> images = await repository.loadImages(urls);
@ -100,7 +128,7 @@ class NoteBloc extends Bloc<NoteEvent, NoteState> {
templates: templates, templates: templates,
images: List.generate( images: List.generate(
images.length, images.length,
(index) => (event.delivery.images[index], images[index]), (index) => (event.delivery.images[index], images[index]),
), ),
), ),
); );
@ -148,7 +176,7 @@ class NoteBloc extends Bloc<NoteEvent, NoteState> {
if (currentState is NoteLoaded) { if (currentState is NoteLoaded) {
List<Note> refreshedNotes = [ List<Note> refreshedNotes = [
...currentState.notes.where( ...currentState.notes.where(
(note) => note.id != int.parse(event.noteId), (note) => note.id != int.parse(event.noteId),
), ),
Note(content: event.content, id: int.parse(event.noteId)), Note(content: event.content, id: int.parse(event.noteId)),
]; ];
@ -173,9 +201,9 @@ class NoteBloc extends Bloc<NoteEvent, NoteState> {
if (currentState is NoteLoaded) { if (currentState is NoteLoaded) {
List<Note> refreshedNotes = List<Note> refreshedNotes =
currentState.notes currentState.notes
.where((note) => note.id != int.parse(event.noteId)) .where((note) => note.id != int.parse(event.noteId))
.toList(); .toList();
emit.call(currentState.copyWith(notes: refreshedNotes)); emit.call(currentState.copyWith(notes: refreshedNotes));
} }

View File

@ -18,6 +18,14 @@ class AddNote extends NoteEvent {
final String deliveryId; final String deliveryId;
} }
class AddNoteOffline extends NoteEvent {
AddNoteOffline({required this.note, required this.deliveryId, required this.noteId});
final String note;
final String noteId;
final String deliveryId;
}
class RemoveNote extends NoteEvent { class RemoveNote extends NoteEvent {
RemoveNote({required this.noteId}); RemoveNote({required this.noteId});

View File

@ -10,14 +10,21 @@ class NoteLoading extends NoteState {}
class NoteLoadingFailed extends NoteState {} class NoteLoadingFailed extends NoteState {}
class NoteLoaded extends NoteState { class NoteLoadedBase extends NoteState {
NoteLoaded({ NoteLoadedBase({
required this.notes, required this.notes,
required this.templates,
required this.images,
}); });
List<Note> notes; List<Note> notes;
}
class NoteLoaded extends NoteLoadedBase {
NoteLoaded({
required this.templates,
required this.images,
required super.notes,
});
List<NoteTemplate> templates; List<NoteTemplate> templates;
List<(ImageNote, Uint8List)> images; List<(ImageNote, Uint8List)> images;

View File

@ -48,11 +48,29 @@ class _SignatureViewState extends State<SignatureView> {
bool _customerAccepted = false; bool _customerAccepted = false;
bool _noteAccepted = false; bool _noteAccepted = false;
bool _notesEmpty = true; bool _notesEmpty = true;
bool _isCustomerSignatureEmpty = true;
bool _isDriverSignatureEmpty = true;
@override @override
void initState() { void initState() {
super.initState(); super.initState();
_customerController.addListener(() {
if (_isCustomerSignatureEmpty != _customerController.isEmpty) {
setState(() {
_isCustomerSignatureEmpty = _customerController.isEmpty;
});
}
});
_driverController.addListener(() {
if (_isDriverSignatureEmpty != _driverController.isEmpty) {
setState(() {
_isDriverSignatureEmpty = _driverController.isEmpty;
});
}
});
// only load notes if they are not already loaded // only load notes if they are not already loaded
final noteState = context.read<NoteBloc>().state; final noteState = context.read<NoteBloc>().state;
if (noteState is NoteInitial) { if (noteState is NoteInitial) {
@ -63,6 +81,7 @@ class _SignatureViewState extends State<SignatureView> {
@override @override
void dispose() { void dispose() {
_customerController.dispose(); _customerController.dispose();
_driverController.dispose();
super.dispose(); super.dispose();
} }
@ -92,12 +111,18 @@ class _SignatureViewState extends State<SignatureView> {
_notesEmpty = current.notes.isEmpty; _notesEmpty = current.notes.isEmpty;
}); });
} }
if (current is NoteLoadedBase) {
setState(() {
_notesEmpty = current.notes.isEmpty;
});
}
}, },
builder: (context, state) { builder: (context, state) {
final current = state; final current = state;
if (current is NoteLoaded) { if (current is NoteLoadedBase) {
if (current.notes.isEmpty) { if (current.notes.isEmpty) {
return const SizedBox( return const SizedBox(
width: double.infinity, width: double.infinity,
@ -107,12 +132,12 @@ class _SignatureViewState extends State<SignatureView> {
return ListView.separated( return ListView.separated(
shrinkWrap: true, shrinkWrap: true,
physics: NeverScrollableScrollPhysics(), physics: const NeverScrollableScrollPhysics(),
itemBuilder: (context, index) { itemBuilder: (context, index) {
return ListTile( return ListTile(
leading: const Icon(Icons.event_note_outlined), leading: const Icon(Icons.event_note_outlined),
title: Text(current.notes[index].content), title: Text(current.notes[index].content),
contentPadding: EdgeInsets.all(20), contentPadding: const EdgeInsets.all(20),
tileColor: Theme.of(context).colorScheme.onSecondary, tileColor: Theme.of(context).colorScheme.onSecondary,
); );
}, },
@ -121,7 +146,7 @@ class _SignatureViewState extends State<SignatureView> {
); );
} }
return SizedBox( return const SizedBox(
width: double.infinity, width: double.infinity,
child: Center(child: CircularProgressIndicator()), child: Center(child: CircularProgressIndicator()),
); );
@ -156,10 +181,17 @@ class _SignatureViewState extends State<SignatureView> {
}); });
}, },
), ),
const Flexible( Flexible(
child: Text( child: InkWell(
"Ich nehme die oben genannten Anmerkungen zur Lieferung zur Kenntnis.", onTap: _notesEmpty ? null : () {
overflow: TextOverflow.fade, setState(() {
_noteAccepted = !_noteAccepted;
});
},
child: Text(
"Ich nehme die oben genannten Anmerkungen zur Lieferung zur Kenntnis.",
overflow: TextOverflow.fade,
),
), ),
), ),
], ],
@ -177,10 +209,17 @@ class _SignatureViewState extends State<SignatureView> {
}); });
}, },
), ),
const Flexible( Flexible(
child: Text( child: InkWell(
"Ich bestätige, dass ich die Ware im ordnungsgemäßen Zustand erhalten habe und, dass die Aufstell- und Einbauarbeiten korrekt durchgeführt wurden.", child: Text(
overflow: TextOverflow.fade, "Ich bestätige, dass ich die Ware im ordnungsgemäßen Zustand erhalten habe und, dass die Aufstell- und Einbauarbeiten korrekt durchgeführt wurden.",
overflow: TextOverflow.fade,
),
onTap: () {
setState(() {
_customerAccepted = !_customerAccepted;
});
},
), ),
), ),
], ],
@ -195,6 +234,16 @@ class _SignatureViewState extends State<SignatureView> {
Widget build(BuildContext context) { Widget build(BuildContext context) {
String formattedDate = DateFormat("dd.MM.yyyy").format(DateTime.now()); String formattedDate = DateFormat("dd.MM.yyyy").format(DateTime.now());
bool isButtonEnabled;
if (!_isDriverSigning) {
isButtonEnabled =
_customerAccepted &&
(_noteAccepted || _notesEmpty) &&
!_isCustomerSignatureEmpty;
} else {
isButtonEnabled = !_isDriverSignatureEmpty;
}
return Scaffold( return Scaffold(
appBar: AppBar( appBar: AppBar(
title: title:
@ -247,9 +296,8 @@ class _SignatureViewState extends State<SignatureView> {
child: Center( child: Center(
child: FilledButton( child: FilledButton(
onPressed: onPressed:
!(_customerAccepted && (_noteAccepted || _notesEmpty)) isButtonEnabled
? null ? () async {
: () async {
if (!_isDriverSigning) { if (!_isDriverSigning) {
setState(() { setState(() {
_isDriverSigning = true; _isDriverSigning = true;
@ -260,7 +308,8 @@ class _SignatureViewState extends State<SignatureView> {
(await _driverController.toPngBytes())!, (await _driverController.toPngBytes())!,
); );
} }
}, }
: null,
child: child:
!_isDriverSigning !_isDriverSigning
? const Text("Weiter") ? const Text("Weiter")

View File

@ -4,6 +4,7 @@ import 'package:hl_lieferservice/feature/delivery/overview/bloc/tour_bloc.dart';
import 'package:hl_lieferservice/feature/delivery/overview/bloc/tour_event.dart'; import 'package:hl_lieferservice/feature/delivery/overview/bloc/tour_event.dart';
import 'package:hl_lieferservice/feature/delivery/overview/presentation/delivery_info.dart'; import 'package:hl_lieferservice/feature/delivery/overview/presentation/delivery_info.dart';
import 'package:hl_lieferservice/feature/delivery/overview/presentation/delivery_list.dart'; import 'package:hl_lieferservice/feature/delivery/overview/presentation/delivery_list.dart';
import 'package:hl_lieferservice/feature/delivery/overview/presentation/delivery_overview_custom_sort.dart';
import 'package:hl_lieferservice/model/tour.dart'; import 'package:hl_lieferservice/model/tour.dart';
import '../../../../model/delivery.dart'; import '../../../../model/delivery.dart';
@ -11,7 +12,11 @@ import '../../../authentication/bloc/auth_bloc.dart';
import '../../../authentication/bloc/auth_state.dart'; import '../../../authentication/bloc/auth_state.dart';
class DeliveryOverview extends StatefulWidget { class DeliveryOverview extends StatefulWidget {
const DeliveryOverview({super.key, required this.tour, required this.distances}); const DeliveryOverview({
super.key,
required this.tour,
required this.distances,
});
final Tour tour; final Tour tour;
final Map<String, double> distances; final Map<String, double> distances;
@ -44,9 +49,7 @@ class _DeliveryOverviewState extends State<DeliveryOverview> {
} }
Future<void> _loadTour() async { Future<void> _loadTour() async {
Authenticated state = context Authenticated state = context.read<AuthBloc>().state as Authenticated;
.read<AuthBloc>()
.state as Authenticated;
context.read<TourBloc>().add(LoadTour(teamId: state.user.number)); context.read<TourBloc>().add(LoadTour(teamId: state.user.number));
} }
@ -57,58 +60,47 @@ class _DeliveryOverviewState extends State<DeliveryOverview> {
child: ListView( child: ListView(
scrollDirection: Axis.horizontal, scrollDirection: Axis.horizontal,
children: children:
widget.tour.driver.cars.map((car) { widget.tour.driver.cars.map((car) {
Color? backgroundColor; Color? backgroundColor;
Color? iconColor = Theme Color? iconColor = Theme.of(context).primaryColor;
.of(context) Color? textColor;
.primaryColor;
Color? textColor;
if (_selectedCarId == car.id) { if (_selectedCarId == car.id) {
backgroundColor = Theme backgroundColor = Theme.of(context).primaryColor;
.of(context) textColor = Theme.of(context).colorScheme.onSecondary;
.primaryColor; iconColor = Theme.of(context).colorScheme.onSecondary;
textColor = Theme }
.of(context)
.colorScheme
.onSecondary;
iconColor = Theme
.of(context)
.colorScheme
.onSecondary;
}
return Padding( return Padding(
padding: const EdgeInsets.only(right: 8), padding: const EdgeInsets.only(right: 8),
child: GestureDetector( child: GestureDetector(
onTap: () { onTap: () {
setState(() { setState(() {
_selectedCarId = car.id; _selectedCarId = car.id;
}); });
}, },
child: Chip( child: Chip(
backgroundColor: backgroundColor, backgroundColor: backgroundColor,
label: Row( label: Row(
children: [ children: [
Icon(Icons.local_shipping, color: iconColor, size: 20), Icon(Icons.local_shipping, color: iconColor, size: 20),
Padding( Padding(
padding: const EdgeInsets.only(left: 5), padding: const EdgeInsets.only(left: 5),
child: Text( child: Text(
car.plate, car.plate,
style: TextStyle(color: textColor, fontSize: 12), style: TextStyle(color: textColor, fontSize: 12),
), ),
),
],
), ),
], ),
), ),
), );
), }).toList(),
);
}).toList(),
), ),
); );
} }
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return RefreshIndicator( return RefreshIndicator(
@ -118,7 +110,12 @@ class _DeliveryOverviewState extends State<DeliveryOverview> {
children: [ children: [
DeliveryInfo(tour: widget.tour), DeliveryInfo(tour: widget.tour),
Padding( Padding(
padding: const EdgeInsets.only(left: 10, right: 10), padding: const EdgeInsets.only(
left: 10,
right: 10,
top: 15,
bottom: 10,
),
child: Row( child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
@ -126,10 +123,7 @@ class _DeliveryOverviewState extends State<DeliveryOverview> {
children: [ children: [
Text( Text(
"Fahrten", "Fahrten",
style: Theme style: Theme.of(context).textTheme.headlineSmall,
.of(context)
.textTheme
.headlineSmall,
), ),
], ],
), ),
@ -147,25 +141,41 @@ class _DeliveryOverviewState extends State<DeliveryOverview> {
_deliveries = _deliveries.reversed.toList(); _deliveries = _deliveries.reversed.toList();
}); });
} }
if (value == "custom") {
showDialog(
context: context,
fullscreenDialog: true,
builder: (context) => CustomSortDialog(),
);
}
if (value == "distance") {
// TODO: muss noch implementiert werden
}
}); });
}, },
itemBuilder: (BuildContext context) => <PopupMenuEntry<String>>[ itemBuilder:
PopupMenuItem<String>( (BuildContext context) => <PopupMenuEntry<String>>[
value: 'name-asc', PopupMenuItem<String>(
child: Text('Name (A-Z)'), value: 'name-asc',
), child: Text('Name (A-Z)'),
PopupMenuItem<String>( ),
value: 'name-desc', PopupMenuItem<String>(
child: Text('Name (Z-A)'), value: 'name-desc',
), child: Text('Name (Z-A)'),
PopupMenuItem<String>( ),
value: 'distance', PopupMenuItem<String>(
child: Text('Entfernung'), value: 'distance',
), child: Text('Entfernung'),
], ),
PopupMenuItem<String>(
value: 'custom',
child: Text('Eigene Sortierung'),
),
],
child: Icon(Icons.filter_list), child: Icon(Icons.filter_list),
) ),
], ],
), ),
), ),
@ -177,13 +187,13 @@ class _DeliveryOverviewState extends State<DeliveryOverview> {
child: DeliveryList( child: DeliveryList(
distances: widget.distances, distances: widget.distances,
deliveries: deliveries:
_deliveries _deliveries
.where( .where(
(delivery) => (delivery) =>
delivery.carId == _selectedCarId && delivery.carId == _selectedCarId &&
delivery.allArticlesScanned(), delivery.allArticlesScanned(),
) )
.toList(), .toList(),
), ),
), ),
], ],

View File

@ -0,0 +1,113 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:hl_lieferservice/feature/delivery/overview/bloc/tour_bloc.dart';
import 'package:hl_lieferservice/feature/delivery/overview/bloc/tour_state.dart';
class CustomSortDialog extends StatefulWidget {
const CustomSortDialog({super.key});
@override
State<StatefulWidget> createState() => _CustomSortDialogState();
}
class _CustomSortDialogState extends State<CustomSortDialog> {
Widget _information() {
return Padding(
padding: EdgeInsets.only(top: 15),
child: Column(
children: [
Padding(
padding: EdgeInsets.all(15),
child: Row(
children: [
Padding(
padding: EdgeInsets.only(right: 15),
child: Icon(Icons.info_outline, color: Colors.blueAccent),
),
Expanded(
child: Text(
"Ziehen Sie die einzelnen Lieferungen mit dem Finger in die gewünschte Position.",
),
),
],
),
),
Divider(),
_sortableList(),
],
),
);
}
Widget _sortableList() {
return BlocBuilder<TourBloc, TourState>(
builder: (context, state) {
final currentState = state;
if (currentState is TourLoaded) {
return Expanded(
child: ReorderableListView(
onReorder: (oldIndex, newIndex) {},
children: currentState.tour.deliveries.indexed.fold([], (
acc,
current,
) {
final delivery = current.$2;
final index = current.$1;
acc.add(
ListTile(
leading: CircleAvatar(
backgroundColor: Theme.of(context).primaryColor,
child: Text(
"${index + 1}",
style: TextStyle(
color: Theme.of(context).colorScheme.onSecondary,
),
),
),
title: Text(delivery.customer.name),
subtitle: Text(delivery.customer.address.toString(), style: TextStyle(fontSize: 11),),
trailing: Icon(Icons.drag_handle),
key: Key("reorder-item-${delivery.id}"),
),
);
return acc;
}),
),
);
}
return Center(child: CircularProgressIndicator());
},
);
}
@override
Widget build(BuildContext context) {
return Dialog(
child: Column(
children: [
Padding(
padding: const EdgeInsets.only(left: 20, right: 10, top: 15),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
"Fahrten sortieren",
style: Theme.of(context).textTheme.headlineSmall,
),
IconButton(
onPressed: () => Navigator.of(context).pop(),
icon: const Icon(Icons.close),
),
],
),
),
Expanded(child: _information()),
],
),
);
}
}

View File

@ -20,7 +20,12 @@ class _DeliveryOverviewPageState extends State<DeliveryOverviewPage> {
if (state is TourLoaded) { if (state is TourLoaded) {
final currentState = state; final currentState = state;
return Center(child: DeliveryOverview(tour: currentState.tour, distances: currentState.distances)); return Center(
child: DeliveryOverview(
tour: currentState.tour,
distances: currentState.distances,
),
);
} }
return Container(); return Container();

View File

@ -71,6 +71,7 @@ class _DeliveryAppState extends State<DeliveryApp> {
BlocProvider( BlocProvider(
create: create:
(context) => DeliveryBloc( (context) => DeliveryBloc(
noteBloc: context.read<NoteBloc>(),
opBloc: context.read<OperationBloc>(), opBloc: context.read<OperationBloc>(),
noteRepository: NoteRepository( noteRepository: NoteRepository(
service: NoteService( service: NoteService(