22 Commits

Author SHA1 Message Date
Vinayakkadge04
7249870aa9 test 2025-11-19 13:46:43 +05:30
vishal-kaklotar-wdi
7dbeef2f80 integrated share plus package 2025-11-19 13:13:16 +05:30
vishal-kaklotar-wdi
1ca940e5cf worked on bu fix 2025-11-19 11:26:23 +05:30
Vinayakkadge04
b54739953a Fixed bug on pass_card_view 2025-11-14 16:21:18 +05:30
Vinayakkadge04
323d730e2d Used url_launcher 2025-11-14 11:29:16 +05:30
Vinayakkadge04
f3c98df517 worked on launch_url for redirect call & email 2025-11-11 14:18:39 +05:30
Vinayakkadge04
0ef09633e0 Updated Splash Screen... 2025-11-11 14:18:39 +05:30
72aae68e2d vinayak's pull merged 2025-11-11 14:18:35 +05:30
Vinayakkadge04
e2f9217d57 Updated Splash Screen... 2025-11-10 12:38:50 +05:30
Vinayakkadge04
7d4c015134 worked on onboarding screen 2025-11-07 17:44:51 +05:30
Vinayakkadge04
061f196ece Merge remote-tracking branch 'origin/dinesh' into vinayak
# Conflicts:
#	pubspec.yaml
2025-10-30 16:52:30 +05:30
76e4fff06c Added all the navigation and all first time user condition also made changes in common app bar and added logo and splash screen 2025-10-30 03:39:40 +05:30
Vinayakkadge04
6a68a06b78 Updated yaml file for splash screen for android 15 2025-10-29 20:22:27 +05:30
9121cf1b1b Merge remote-tracking branch 'origin/vinayak' into dinesh
# Conflicts:
#	pubspec.lock
#	pubspec.yaml
2025-10-29 20:02:11 +05:30
Vinayakkadge04
a2ff4253ed Updated bottomsheet bg color 2025-10-29 19:59:49 +05:30
f43c2cc9f6 routing magic itenary 2025-10-29 19:59:11 +05:30
Vinayakkadge04
d73faf7506 Updated language bottomSheet bg color 2025-10-29 19:47:59 +05:30
Vinayakkadge04
560a10f4ea Used Back widget 2025-10-29 18:55:45 +05:30
Vinayakkadge04
5c11344c17 Used Screen Util in ticket card view 2025-10-29 17:56:38 +05:30
9dd76e1dac Merge remote-tracking branch 'origin/vinayak' into dinesh
# Conflicts:
#	lib/main.dart
2025-10-29 17:12:05 +05:30
Vinayakkadge04
c771ce335c Changed serch_city_bottomsheet navigation 2025-10-29 17:11:07 +05:30
Vinayakkadge04
f93ba6dad2 Worked on Search city bottomsheet 2025-10-29 17:07:27 +05:30
147 changed files with 4195 additions and 2299 deletions

View File

@@ -21,7 +21,7 @@ android {
defaultConfig {
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId = "com.citycards_customer.citycards_customer"
applicationId = "com.citycard.customer"
// You can update the following values to match your application needs.
// For more information, see: https://flutter.dev/to/review-gradle-config.
minSdk = flutter.minSdkVersion

View File

@@ -1,33 +1,42 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.INTERNET" />
<application
android:label="citycards_customer"
android:name="${applicationName}"
android:icon="@mipmap/ic_launcher">
android:icon="@mipmap/launcher_icon"
android:label="CityCard Customer">
<activity
android:name=".MainActivity"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:exported="true"
android:hardwareAccelerated="true"
android:launchMode="singleTop"
android:taskAffinity=""
android:theme="@style/LaunchTheme"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true"
android:theme="@style/NormalTheme"
android:windowSoftInputMode="adjustResize">
<!-- Specifies an Android theme to apply to this Activity as soon as
the Android process has started. This theme is visible to the user
while the Flutter UI initializes. After that, this theme continues
to determine the Window background behind the Flutter UI. -->
<meta-data
android:name="io.flutter.embedding.android.NormalTheme"
android:resource="@style/NormalTheme"
/>
android:name="io.flutter.embedding.android.NormalTheme"
android:resource="@style/NormalTheme" />
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="http" />
<data android:scheme="https" />
<data android:scheme="mailto" />
</intent-filter>
</activity>
<!-- Don't delete the meta-data below.
@@ -43,8 +52,8 @@
In particular, this is used by the Flutter engine in io.flutter.plugin.text.ProcessTextPlugin. -->
<queries>
<intent>
<action android:name="android.intent.action.PROCESS_TEXT"/>
<data android:mimeType="text/plain"/>
<action android:name="android.intent.action.PROCESS_TEXT" />
<data android:mimeType="text/plain" />
</intent>
</queries>
</manifest>

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 B

View File

@@ -1,12 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Modify this file to customize your launch splash screen -->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="?android:colorBackground" />
<!-- You can insert your own image assets here -->
<!-- <item>
<bitmap
android:gravity="center"
android:src="@mipmap/launch_image" />
</item> -->
<item>
<bitmap android:gravity="fill" android:src="@drawable/background"/>
</item>
</layer-list>

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 B

View File

@@ -1,12 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Modify this file to customize your launch splash screen -->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@android:color/white" />
<!-- You can insert your own image assets here -->
<!-- <item>
<bitmap
android:gravity="center"
android:src="@mipmap/launch_image" />
</item> -->
<item>
<bitmap android:gravity="fill" android:src="@drawable/background"/>
</item>
</layer-list>

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.4 KiB

View File

@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is on -->
<style name="LaunchTheme" parent="@android:style/Theme.Black.NoTitleBar">
<item name="android:forceDarkAllowed">false</item>
<item name="android:windowFullscreen">false</item>
<item name="android:windowDrawsSystemBarBackgrounds">false</item>
<item name="android:windowLayoutInDisplayCutoutMode">shortEdges</item>
<item name="android:windowSplashScreenBackground">#F95F62</item>
</style>
<!-- Theme applied to the Android Window as soon as the process has started.
This theme determines the color of the Android Window while your
Flutter UI initializes, as well as behind your Flutter UI while its
running.
This Theme is only used starting with V2 of Flutter's Android embedding. -->
<style name="NormalTheme" parent="@android:style/Theme.Black.NoTitleBar">
<item name="android:windowBackground">?android:colorBackground</item>
</style>
</resources>

View File

@@ -5,6 +5,10 @@
<!-- Show a splash screen on the activity. Automatically removed when
the Flutter engine draws its first frame -->
<item name="android:windowBackground">@drawable/launch_background</item>
<item name="android:forceDarkAllowed">false</item>
<item name="android:windowFullscreen">false</item>
<item name="android:windowDrawsSystemBarBackgrounds">false</item>
<item name="android:windowLayoutInDisplayCutoutMode">shortEdges</item>
</style>
<!-- Theme applied to the Android Window as soon as the process has started.
This theme determines the color of the Android Window while your

View File

@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is off -->
<style name="LaunchTheme" parent="@android:style/Theme.Light.NoTitleBar">
<item name="android:forceDarkAllowed">false</item>
<item name="android:windowFullscreen">false</item>
<item name="android:windowDrawsSystemBarBackgrounds">false</item>
<item name="android:windowLayoutInDisplayCutoutMode">shortEdges</item>
<item name="android:windowSplashScreenBackground">#F95F62</item>
</style>
<!-- Theme applied to the Android Window as soon as the process has started.
This theme determines the color of the Android Window while your
Flutter UI initializes, as well as behind your Flutter UI while its
running.
This Theme is only used starting with V2 of Flutter's Android embedding. -->
<style name="NormalTheme" parent="@android:style/Theme.Light.NoTitleBar">
<item name="android:windowBackground">?android:colorBackground</item>
</style>
</resources>

View File

@@ -2,9 +2,12 @@
<resources>
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is off -->
<style name="LaunchTheme" parent="@android:style/Theme.Light.NoTitleBar">
<!-- Show a splash screen on the activity. Automatically removed when
the Flutter engine draws its first frame -->
<!-- Use a plain background instead of a splash drawable -->
<item name="android:windowBackground">@drawable/launch_background</item>
<item name="android:forceDarkAllowed">false</item>
<item name="android:windowFullscreen">false</item>
<item name="android:windowDrawsSystemBarBackgrounds">false</item>
<item name="android:windowLayoutInDisplayCutoutMode">shortEdges</item>
</style>
<!-- Theme applied to the Android Window as soon as the process has started.
This theme determines the color of the Android Window while your

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

BIN
assets/images/splash1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 MiB

BIN
assets/images/splash2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 MiB

BIN
assets/images/splash3.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 366 KiB

1
assets/intro/anim.json Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

1
assets/intro/animm.json Normal file

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 93 KiB

BIN
assets/logo/logoframe.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

BIN
assets/logo/splash.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

View File

@@ -0,0 +1,19 @@
# flutter pub run flutter_launcher_icons
flutter_launcher_icons:
image_path: "assets/logo/logo_city_cards.png"
android: "launcher_icon"
# image_path_android: "assets/icon/icon.png"
min_sdk_android: 21 # android min sdk min:16, default 21
# adaptive_icon_background: "assets/icon/background.png"
# adaptive_icon_foreground: "assets/icon/foreground.png"
# adaptive_icon_foreground_inset: 16
# adaptive_icon_monochrome: "assets/icon/monochrome.png"
ios: true
# image_path_ios: "assets/icon/icon.png"
remove_alpha_ios: true
# image_path_ios_dark_transparent: "assets/icon/icon_dark.png"
# image_path_ios_tinted_grayscale: "assets/icon/icon_tinted.png"
# desaturate_tinted_to_grayscale_ios: true
# background_color_ios: "#ffffff"

View File

@@ -1,5 +1,5 @@
# Uncomment this line to define a global platform for your project
# platform :ios, '13.0'
platform :ios, '16.0'
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
ENV['COCOAPODS_DISABLE_STATS'] = 'true'

94
ios/Podfile.lock Normal file
View File

@@ -0,0 +1,94 @@
PODS:
- Flutter (1.0.0)
- flutter_native_splash (2.4.3):
- Flutter
- geolocator_apple (1.2.0):
- Flutter
- FlutterMacOS
- Google-Maps-iOS-Utils (6.1.0):
- GoogleMaps (~> 9.0)
- google_maps_flutter_ios (0.0.1):
- Flutter
- Google-Maps-iOS-Utils (< 7.0, >= 5.0)
- GoogleMaps (< 10.0, >= 8.4)
- GoogleMaps (9.4.0):
- GoogleMaps/Maps (= 9.4.0)
- GoogleMaps/Maps (9.4.0)
- image_picker_ios (0.0.1):
- Flutter
- package_info_plus (0.4.5):
- Flutter
- path_provider_foundation (0.0.1):
- Flutter
- FlutterMacOS
- share_plus (0.0.1):
- Flutter
- shared_preferences_foundation (0.0.1):
- Flutter
- FlutterMacOS
- url_launcher_ios (0.0.1):
- Flutter
- video_player_avfoundation (0.0.1):
- Flutter
- FlutterMacOS
DEPENDENCIES:
- Flutter (from `Flutter`)
- flutter_native_splash (from `.symlinks/plugins/flutter_native_splash/ios`)
- geolocator_apple (from `.symlinks/plugins/geolocator_apple/darwin`)
- google_maps_flutter_ios (from `.symlinks/plugins/google_maps_flutter_ios/ios`)
- image_picker_ios (from `.symlinks/plugins/image_picker_ios/ios`)
- package_info_plus (from `.symlinks/plugins/package_info_plus/ios`)
- path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`)
- share_plus (from `.symlinks/plugins/share_plus/ios`)
- shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`)
- url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`)
- video_player_avfoundation (from `.symlinks/plugins/video_player_avfoundation/darwin`)
SPEC REPOS:
trunk:
- Google-Maps-iOS-Utils
- GoogleMaps
EXTERNAL SOURCES:
Flutter:
:path: Flutter
flutter_native_splash:
:path: ".symlinks/plugins/flutter_native_splash/ios"
geolocator_apple:
:path: ".symlinks/plugins/geolocator_apple/darwin"
google_maps_flutter_ios:
:path: ".symlinks/plugins/google_maps_flutter_ios/ios"
image_picker_ios:
:path: ".symlinks/plugins/image_picker_ios/ios"
package_info_plus:
:path: ".symlinks/plugins/package_info_plus/ios"
path_provider_foundation:
:path: ".symlinks/plugins/path_provider_foundation/darwin"
share_plus:
:path: ".symlinks/plugins/share_plus/ios"
shared_preferences_foundation:
:path: ".symlinks/plugins/shared_preferences_foundation/darwin"
url_launcher_ios:
:path: ".symlinks/plugins/url_launcher_ios/ios"
video_player_avfoundation:
:path: ".symlinks/plugins/video_player_avfoundation/darwin"
SPEC CHECKSUMS:
Flutter: cabc95a1d2626b1b06e7179b784ebcf0c0cde467
flutter_native_splash: c32d145d68aeda5502d5f543ee38c192065986cf
geolocator_apple: ab36aa0e8b7d7a2d7639b3b4e48308394e8cef5e
Google-Maps-iOS-Utils: 0a484b05ed21d88c9f9ebbacb007956edd508a96
google_maps_flutter_ios: 0291eb2aa252298a769b04d075e4a9d747ff7264
GoogleMaps: 0608099d4870cac8754bdba9b6953db543432438
image_picker_ios: 7fe1ff8e34c1790d6fff70a32484959f563a928a
package_info_plus: af8e2ca6888548050f16fa2f1938db7b5a5df499
path_provider_foundation: 080d55be775b7414fd5a5ef3ac137b97b097e564
share_plus: 50da8cb520a8f0f65671c6c6a99b3617ed10a58a
shared_preferences_foundation: 7036424c3d8ec98dfe75ff1667cb0cd531ec82bb
url_launcher_ios: 7a95fa5b60cc718a708b8f2966718e93db0cef1b
video_player_avfoundation: dd410b52df6d2466a42d28550e33e4146928280a
PODFILE CHECKSUM: 1857a7cdb7dfafe45f2b0e9a9af44644190f7506
COCOAPODS: 1.16.2

View File

@@ -7,10 +7,12 @@
objects = {
/* Begin PBXBuildFile section */
00C1AB7B0C8F1922F3F1AE65 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 54C8901E9D1856D980DFFE46 /* Pods_Runner.framework */; };
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 */; };
81D638B66EB4658C8192CA0D /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 445696AB37183A7C63CB7E98 /* Pods_RunnerTests.framework */; };
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 */; };
@@ -45,6 +47,10 @@
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>"; };
445696AB37183A7C63CB7E98 /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
4FD33ADDA221C4BBA29FA3D6 /* 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>"; };
54C8901E9D1856D980DFFE46 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
626B072D1717B50A277DA3C7 /* 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>"; };
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>"; };
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; };
@@ -55,6 +61,10 @@
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>"; };
B691822B373AD22ECA93B798 /* 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>"; };
C1FCB3EF88270ED76DFA3FBD /* 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>"; };
D56ABB8F306EF9F6809C0C1E /* 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>"; };
E2E6DC2B6718F55E3BF165E7 /* 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>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@@ -62,6 +72,15 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
00C1AB7B0C8F1922F3F1AE65 /* Pods_Runner.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
CF8A29BE993C0C902CB143AF /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
81D638B66EB4658C8192CA0D /* Pods_RunnerTests.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -76,6 +95,28 @@
path = RunnerTests;
sourceTree = "<group>";
};
5D45FB84C63476582408C414 /* Frameworks */ = {
isa = PBXGroup;
children = (
54C8901E9D1856D980DFFE46 /* Pods_Runner.framework */,
445696AB37183A7C63CB7E98 /* Pods_RunnerTests.framework */,
);
name = Frameworks;
sourceTree = "<group>";
};
6D4A73F1E55857ADBD000C6A /* Pods */ = {
isa = PBXGroup;
children = (
B691822B373AD22ECA93B798 /* Pods-Runner.debug.xcconfig */,
4FD33ADDA221C4BBA29FA3D6 /* Pods-Runner.release.xcconfig */,
D56ABB8F306EF9F6809C0C1E /* Pods-Runner.profile.xcconfig */,
E2E6DC2B6718F55E3BF165E7 /* Pods-RunnerTests.debug.xcconfig */,
626B072D1717B50A277DA3C7 /* Pods-RunnerTests.release.xcconfig */,
C1FCB3EF88270ED76DFA3FBD /* Pods-RunnerTests.profile.xcconfig */,
);
path = Pods;
sourceTree = "<group>";
};
9740EEB11CF90186004384FC /* Flutter */ = {
isa = PBXGroup;
children = (
@@ -94,6 +135,8 @@
97C146F01CF9000F007C117D /* Runner */,
97C146EF1CF9000F007C117D /* Products */,
331C8082294A63A400263BE5 /* RunnerTests */,
6D4A73F1E55857ADBD000C6A /* Pods */,
5D45FB84C63476582408C414 /* Frameworks */,
);
sourceTree = "<group>";
};
@@ -128,8 +171,10 @@
isa = PBXNativeTarget;
buildConfigurationList = 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */;
buildPhases = (
BC66FA7BADCD3982DC87655E /* [CP] Check Pods Manifest.lock */,
331C807D294A63A400263BE5 /* Sources */,
331C807F294A63A400263BE5 /* Resources */,
CF8A29BE993C0C902CB143AF /* Frameworks */,
);
buildRules = (
);
@@ -145,12 +190,15 @@
isa = PBXNativeTarget;
buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
buildPhases = (
3825EC0F330C0B58EA2A8981 /* [CP] Check Pods Manifest.lock */,
9740EEB61CF901F6004384FC /* Run Script */,
97C146EA1CF9000F007C117D /* Sources */,
97C146EB1CF9000F007C117D /* Frameworks */,
97C146EC1CF9000F007C117D /* Resources */,
9705A1C41CF9048500538489 /* Embed Frameworks */,
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
41FC0A605EBADE26C841287E /* [CP] Embed Pods Frameworks */,
D10E98BB568B7005161E1ABD /* [CP] Copy Pods Resources */,
);
buildRules = (
);
@@ -222,6 +270,28 @@
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
3825EC0F330C0B58EA2A8981 /* [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;
};
3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
isa = PBXShellScriptBuildPhase;
alwaysOutOfDate = 1;
@@ -238,6 +308,23 @@
shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin";
};
41FC0A605EBADE26C841287E /* [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;
};
9740EEB61CF901F6004384FC /* Run Script */ = {
isa = PBXShellScriptBuildPhase;
alwaysOutOfDate = 1;
@@ -253,6 +340,45 @@
shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
};
BC66FA7BADCD3982DC87655E /* [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;
};
D10E98BB568B7005161E1ABD /* [CP] Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-input-files.xcfilelist",
);
name = "[CP] Copy Pods Resources";
outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-output-files.xcfilelist",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n";
showEnvVarsInLog = 0;
};
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
@@ -361,24 +487,35 @@
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 = A89AY6VY4F;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = "CityCard Customer";
IPHONEOS_DEPLOYMENT_TARGET = 16.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = com.citycardscustomer.citycardsCustomer;
PRODUCT_BUNDLE_IDENTIFIER = com.citycard.customer;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
SUPPORTS_MACCATALYST = NO;
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO;
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = 1;
VERSIONING_SYSTEM = "apple-generic";
};
name = Profile;
};
331C8088294A63A400263BE5 /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = E2E6DC2B6718F55E3BF165E7 /* Pods-RunnerTests.debug.xcconfig */;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CODE_SIGN_STYLE = Automatic;
@@ -396,6 +533,7 @@
};
331C8089294A63A400263BE5 /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 626B072D1717B50A277DA3C7 /* Pods-RunnerTests.release.xcconfig */;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CODE_SIGN_STYLE = Automatic;
@@ -411,6 +549,7 @@
};
331C808A294A63A400263BE5 /* Profile */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = C1FCB3EF88270ED76DFA3FBD /* Pods-RunnerTests.profile.xcconfig */;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CODE_SIGN_STYLE = Automatic;
@@ -428,7 +567,7 @@
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = AppIcon;
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
@@ -475,7 +614,7 @@
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
ONLY_ACTIVE_ARCH = NO;
SDKROOT = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
};
@@ -485,7 +624,7 @@
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = AppIcon;
CLANG_ANALYZER_NONNULL = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
@@ -526,6 +665,7 @@
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
MTL_ENABLE_DEBUG_INFO = NO;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
SUPPORTED_PLATFORMS = iphoneos;
SWIFT_COMPILATION_MODE = wholemodule;
@@ -541,19 +681,29 @@
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 = A89AY6VY4F;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = "CityCard Customer";
IPHONEOS_DEPLOYMENT_TARGET = 16.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = com.citycardscustomer.citycardsCustomer;
PRODUCT_BUNDLE_IDENTIFIER = com.citycard.customer;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
SUPPORTS_MACCATALYST = NO;
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO;
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = 1;
VERSIONING_SYSTEM = "apple-generic";
};
name = Debug;
@@ -564,18 +714,28 @@
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 = A89AY6VY4F;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = "CityCard Customer";
IPHONEOS_DEPLOYMENT_TARGET = 16.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = com.citycardscustomer.citycardsCustomer;
PRODUCT_BUNDLE_IDENTIFIER = com.citycard.customer;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
SUPPORTS_MACCATALYST = NO;
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO;
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = 1;
VERSIONING_SYSTEM = "apple-generic";
};
name = Release;

View File

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

View File

@@ -1,122 +1 @@
{
"images" : [
{
"size" : "20x20",
"idiom" : "iphone",
"filename" : "Icon-App-20x20@2x.png",
"scale" : "2x"
},
{
"size" : "20x20",
"idiom" : "iphone",
"filename" : "Icon-App-20x20@3x.png",
"scale" : "3x"
},
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "Icon-App-29x29@1x.png",
"scale" : "1x"
},
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "Icon-App-29x29@2x.png",
"scale" : "2x"
},
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "Icon-App-29x29@3x.png",
"scale" : "3x"
},
{
"size" : "40x40",
"idiom" : "iphone",
"filename" : "Icon-App-40x40@2x.png",
"scale" : "2x"
},
{
"size" : "40x40",
"idiom" : "iphone",
"filename" : "Icon-App-40x40@3x.png",
"scale" : "3x"
},
{
"size" : "60x60",
"idiom" : "iphone",
"filename" : "Icon-App-60x60@2x.png",
"scale" : "2x"
},
{
"size" : "60x60",
"idiom" : "iphone",
"filename" : "Icon-App-60x60@3x.png",
"scale" : "3x"
},
{
"size" : "20x20",
"idiom" : "ipad",
"filename" : "Icon-App-20x20@1x.png",
"scale" : "1x"
},
{
"size" : "20x20",
"idiom" : "ipad",
"filename" : "Icon-App-20x20@2x.png",
"scale" : "2x"
},
{
"size" : "29x29",
"idiom" : "ipad",
"filename" : "Icon-App-29x29@1x.png",
"scale" : "1x"
},
{
"size" : "29x29",
"idiom" : "ipad",
"filename" : "Icon-App-29x29@2x.png",
"scale" : "2x"
},
{
"size" : "40x40",
"idiom" : "ipad",
"filename" : "Icon-App-40x40@1x.png",
"scale" : "1x"
},
{
"size" : "40x40",
"idiom" : "ipad",
"filename" : "Icon-App-40x40@2x.png",
"scale" : "2x"
},
{
"size" : "76x76",
"idiom" : "ipad",
"filename" : "Icon-App-76x76@1x.png",
"scale" : "1x"
},
{
"size" : "76x76",
"idiom" : "ipad",
"filename" : "Icon-App-76x76@2x.png",
"scale" : "2x"
},
{
"size" : "83.5x83.5",
"idiom" : "ipad",
"filename" : "Icon-App-83.5x83.5@2x.png",
"scale" : "2x"
},
{
"size" : "1024x1024",
"idiom" : "ios-marketing",
"filename" : "Icon-App-1024x1024@1x.png",
"scale" : "1x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
{"images":[{"size":"20x20","idiom":"iphone","filename":"Icon-App-20x20@2x.png","scale":"2x"},{"size":"20x20","idiom":"iphone","filename":"Icon-App-20x20@3x.png","scale":"3x"},{"size":"29x29","idiom":"iphone","filename":"Icon-App-29x29@1x.png","scale":"1x"},{"size":"29x29","idiom":"iphone","filename":"Icon-App-29x29@2x.png","scale":"2x"},{"size":"29x29","idiom":"iphone","filename":"Icon-App-29x29@3x.png","scale":"3x"},{"size":"40x40","idiom":"iphone","filename":"Icon-App-40x40@2x.png","scale":"2x"},{"size":"40x40","idiom":"iphone","filename":"Icon-App-40x40@3x.png","scale":"3x"},{"size":"57x57","idiom":"iphone","filename":"Icon-App-57x57@1x.png","scale":"1x"},{"size":"57x57","idiom":"iphone","filename":"Icon-App-57x57@2x.png","scale":"2x"},{"size":"60x60","idiom":"iphone","filename":"Icon-App-60x60@2x.png","scale":"2x"},{"size":"60x60","idiom":"iphone","filename":"Icon-App-60x60@3x.png","scale":"3x"},{"size":"20x20","idiom":"ipad","filename":"Icon-App-20x20@1x.png","scale":"1x"},{"size":"20x20","idiom":"ipad","filename":"Icon-App-20x20@2x.png","scale":"2x"},{"size":"29x29","idiom":"ipad","filename":"Icon-App-29x29@1x.png","scale":"1x"},{"size":"29x29","idiom":"ipad","filename":"Icon-App-29x29@2x.png","scale":"2x"},{"size":"40x40","idiom":"ipad","filename":"Icon-App-40x40@1x.png","scale":"1x"},{"size":"40x40","idiom":"ipad","filename":"Icon-App-40x40@2x.png","scale":"2x"},{"size":"50x50","idiom":"ipad","filename":"Icon-App-50x50@1x.png","scale":"1x"},{"size":"50x50","idiom":"ipad","filename":"Icon-App-50x50@2x.png","scale":"2x"},{"size":"72x72","idiom":"ipad","filename":"Icon-App-72x72@1x.png","scale":"1x"},{"size":"72x72","idiom":"ipad","filename":"Icon-App-72x72@2x.png","scale":"2x"},{"size":"76x76","idiom":"ipad","filename":"Icon-App-76x76@1x.png","scale":"1x"},{"size":"76x76","idiom":"ipad","filename":"Icon-App-76x76@2x.png","scale":"2x"},{"size":"83.5x83.5","idiom":"ipad","filename":"Icon-App-83.5x83.5@2x.png","scale":"2x"},{"size":"1024x1024","idiom":"ios-marketing","filename":"Icon-App-1024x1024@1x.png","scale":"1x"}],"info":{"version":1,"author":"xcode"}}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 117 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 295 B

After

Width:  |  Height:  |  Size: 678 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 406 B

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 450 B

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 282 B

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 462 B

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 704 B

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 406 B

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 586 B

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 862 B

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 862 B

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 762 B

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 7.1 KiB

View File

@@ -0,0 +1,21 @@
{
"images" : [
{
"filename" : "background.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 B

View File

@@ -1,23 +1,23 @@
{
"images" : [
{
"idiom" : "universal",
"filename" : "LaunchImage.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "LaunchImage@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"filename" : "LaunchImage@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 68 B

After

Width:  |  Height:  |  Size: 69 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 68 B

After

Width:  |  Height:  |  Size: 69 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 68 B

After

Width:  |  Height:  |  Size: 69 B

View File

@@ -16,13 +16,19 @@
<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>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleToFill" image="LaunchBackground" translatesAutoresizingMaskIntoConstraints="NO" id="tWc-Dq-wcI"/>
<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"/>
<constraint firstItem="YRO-k0-Ey4" firstAttribute="leading" secondItem="Ze5-6b-2t3" secondAttribute="leading" id="3T2-ad-Qdv"/>
<constraint firstItem="tWc-Dq-wcI" firstAttribute="bottom" secondItem="Ze5-6b-2t3" secondAttribute="bottom" id="RPx-PI-7Xg"/>
<constraint firstItem="tWc-Dq-wcI" firstAttribute="top" secondItem="Ze5-6b-2t3" secondAttribute="top" id="SdS-ul-q2q"/>
<constraint firstAttribute="trailing" secondItem="tWc-Dq-wcI" secondAttribute="trailing" id="Swv-Gf-Rwn"/>
<constraint firstAttribute="trailing" secondItem="YRO-k0-Ey4" secondAttribute="trailing" id="TQA-XW-tRk"/>
<constraint firstItem="YRO-k0-Ey4" firstAttribute="bottom" secondItem="Ze5-6b-2t3" secondAttribute="bottom" id="duK-uY-Gun"/>
<constraint firstItem="tWc-Dq-wcI" firstAttribute="leading" secondItem="Ze5-6b-2t3" secondAttribute="leading" id="kV7-tw-vXt"/>
<constraint firstItem="YRO-k0-Ey4" firstAttribute="top" secondItem="Ze5-6b-2t3" secondAttribute="top" id="xPn-NY-SIU"/>
</constraints>
</view>
</viewController>
@@ -33,5 +39,6 @@
</scenes>
<resources>
<image name="LaunchImage" width="168" height="185"/>
<image name="LaunchBackground" width="1" height="1"/>
</resources>
</document>

View File

@@ -1,49 +1,59 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleDisplayName</key>
<string>Citycards Customer</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>citycards_customer</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>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>
<key>CADisableMinimumFrameDurationOnPhone</key>
<true/>
<key>UIApplicationSupportsIndirectInputEvents</key>
<true/>
</dict>
<dict>
<key>CADisableMinimumFrameDurationOnPhone</key>
<true/>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleDisplayName</key>
<string>Citycards Customer</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>citycards_customer</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.0.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>NSCameraUsageDescription</key>
<string>We need access to your camera for taking photos for profile and to build a postcard.</string>
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>Citycard customer needs your location to find the closest place you can visit.</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string>Citycard customer needs your location to find the closest place you can visit.</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>We need access to your camera for taking photos for profile and to build a postcard.</string>
<key>UIApplicationSupportsIndirectInputEvents</key>
<true/>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIMainStoryboardFile</key>
<string>Main</string>
<key>UIStatusBarHidden</key>
<false/>
<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>

View File

@@ -28,6 +28,7 @@ class AddDetailsView extends StatelessWidget {
isWhiteLogo: false,
isProfilePage: false,
showCart: false,
showDivider: true,
),
Row(
children: [

View File

@@ -1,489 +0,0 @@
import 'package:citycards_customer/attraction_details/share_bottomsheet.dart';
import 'package:citycards_customer/common_packages/app_bar.dart';
import 'package:citycards_customer/common_packages/custom_text.dart';
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import '../core/route_constants.dart';
class AttractionDetailsView extends StatelessWidget {
const AttractionDetailsView({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
body: SafeArea(
child: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Stack(
children: [
Image.asset(
'assets/images/koh_rong_samloem_banner.png',
height: 377.h,
width: double.infinity,
fit: BoxFit.cover,
),
Positioned(
top: 0,
left: 0,
right: 0,
child: SafeArea(
child: Padding(
padding: EdgeInsets.symmetric(horizontal: 20.w, vertical: 10.h),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
CommonAppBar(isWhiteLogo: true, isProfilePage: false),
SizedBox(height: 10.h),
Divider(
color: Colors.white.withOpacity(0.6),
height: 1.h,
),
SizedBox(height: 8.h),
Row(
children: [
GestureDetector(
onTap: () => Navigator.pop(context),
child: Icon(
Icons.arrow_back,
size: 24.sp,
color: Colors.white,
),
),
SizedBox(width: 8.w),
Text(
"Koh Rong Samloem",
style: TextStyle(
fontSize: 14.sp,
fontWeight: FontWeight.w600,
color: Colors.white,
),
),
],
),
],
),
),
),
),
Positioned(
bottom: 31.h,
left: 12.w,
child: Text(
"Koh Rong\nSamloem",
style: TextStyle(
color: Colors.white,
fontSize: 44.sp,
fontWeight: FontWeight.w500,
height: 1.2,
),
),
),
Positioned(
bottom: 31.h,
right: 17.w,
child: GestureDetector(
onTap: () {
showModalBottomSheet(
context: context,
isScrollControlled: true,
backgroundColor: Colors.transparent,
builder: (context) => const ShareBottomSheet(),
);
},
child: Container(
height: 36.h,
width: 36.w,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(20.r),
),
child: Center(
child: Icon(
Icons.share_sharp,
color: Colors.black,
size: 18.sp,
),
),
),
),
),
],
),
// About Section
Padding(
padding: EdgeInsets.only(left: 16.w, right: 16.w, top: 30.h),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"About",
style: TextStyle(
fontSize: 18.sp,
fontWeight: FontWeight.w400,
),
),
SizedBox(height: 12.32.h),
Text(
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Convallis condimentum morbi non egestas enim amet sagittis. Proin sed aliquet rhoncus ut pellentesque ullamcorper sit eget ac.Sit nisi, cras amet varius eget egestas pellentesque. Cursus gravida euismod non...",
style: TextStyle(
color: Color(0xFF262626),
fontWeight: FontWeight.w400,
fontSize: 14.sp,
height: 1.5,
),
),
],
),
),
SizedBox(height: 41.h),
// Booking Section
Padding(
padding: EdgeInsets.symmetric(horizontal: 16.w),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"How to make a booking?",
style: TextStyle(
fontSize: 18.sp,
fontWeight: FontWeight.w400,
),
),
SizedBox(height: 16.h),
Container(
padding: EdgeInsets.symmetric(
horizontal: 12.w,
vertical: 12.h,
),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8.r),
border: Border.all(color: Color(0xFFF95F62)),
),
child: Row(
children: [
Icon(
Icons.call,
color: Color(0xFFF95F62),
size: 32.w,
),
SizedBox(width: 16.w),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
CustomText(
text: "Contact Number",
color: Colors.black.withOpacity(.6),
size: 12.sp,
weight: FontWeight.w500,
),
SizedBox(height: 6.h),
CustomText(
text: "+1012 3456 789",
color: Colors.black,
size: 14.sp,
weight: FontWeight.w600,
),
SizedBox(height: 6.h),
CustomText(
text: "Tap to call",
color: Colors.black.withOpacity(.4),
size: 12.sp,
weight: FontWeight.w400,
),
],
),
),
],
),
),
SizedBox(height: 16.h),
Container(
padding: EdgeInsets.symmetric(
horizontal: 12.w,
vertical: 12.h,
),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8.r),
border: Border.all(color: Color(0xFFF95F62)),
),
child: Row(
children: [
Icon(
Icons.email_sharp,
color: Color(0xFFF95F62),
size: 32.w,
),
SizedBox(width: 16.w),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
CustomText(
text: "Email",
color: Colors.black.withOpacity(.6),
size: 12.sp,
weight: FontWeight.w500,
),
SizedBox(height: 6.h),
CustomText(
text: "CityCards24@gmail.com",
color: Colors.black,
size: 14.sp,
weight: FontWeight.w600,
),
SizedBox(height: 6.h),
CustomText(
text: "Tap to email",
color: Colors.black.withOpacity(.4),
size: 12.sp,
weight: FontWeight.w400,
),
],
),
),
],
),
),
SizedBox(height: 16.h),
InkWell(
onTap: (){
Navigator.of(context).pushNamed(RouteConstants.makeBooking);
},
child: Container(
padding: EdgeInsets.symmetric(
horizontal: 24.w,
vertical: 18.h,
),
decoration: BoxDecoration(
color: Color(0xFFF95F62),
borderRadius: BorderRadius.circular(10.r),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
CustomText(
text: "Via CityCards",
size: 16.sp,
weight: FontWeight.w500,
color: Colors.white,
),
SizedBox(height: 8.h),
CustomText(
text: "Create a booking via app",
size: 11.sp,
weight: FontWeight.w400,
color: Colors.white,
),
],
),
),
Icon(
Icons.arrow_forward_ios_outlined,
color: Colors.white,
),
],
),
),
),
SizedBox(height: 30.h),
Divider(color: Colors.black.withOpacity(0.2)),
SizedBox(height: 30.h),
Text(
"What is included",
style: TextStyle(
fontSize: 24.sp,
fontWeight: FontWeight.w500,
),
),
SizedBox(height: 4.h),
Wrap(
runSpacing: 16.h,
spacing: 16.w,
children: [
includedBox(
"assets/icons/bus.png",
"Bus",
"Transportation",
),
includedBox(
"assets/icons/clock.png",
"2 day 1 night",
"Duration",
),
includedBox(
"assets/icons/bx_qr.png",
"TAC200812695",
"Product code",
),
],
),
SizedBox(height: 30.h),
Divider(color: Colors.black.withOpacity(0.2)),
SizedBox(height: 30.h),
Text(
"Exact Location",
style: TextStyle(
fontSize: 18.sp,
fontWeight: FontWeight.w400,
),
),
SizedBox(height: 8.h),
CustomText(
text: "View the location on map",
size: 12.sp,
color: Colors.black.withOpacity(.6),
),
SizedBox(height: 17.h),
ClipRRect(
borderRadius: BorderRadius.circular(13.54.r),
child: Image.asset(
height: 178.7.h,
width: double.infinity,
"assets/images/attra_detail_map.png",
fit: BoxFit.cover,
),
),
SizedBox(height: 17.h),
CustomText(
text:
"Angkor Mails Hotel \nNR6, Krong Siem Reap Cambodia",
size: 12.sp,
color: Colors.black.withOpacity(0.6),
),
SizedBox(height: 30.h),
Divider(color: Colors.black.withOpacity(0.2)),
SizedBox(height: 30.h),
Text(
"People frequently ask",
style: TextStyle(
fontSize: 18.sp,
fontWeight: FontWeight.w400,
),
),
SizedBox(height: 15.h),
faqBox(
"About this place",
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. A id diam nisl, non justo, in odio...",
),
SizedBox(height: 15.h),
faqBox(
"Term and condition",
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. A id diam nisl, non justo, in odio...",
),
SizedBox(height: 15.h),
faqBox(
"Cancellation Policy",
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. A id diam nisl, non justo, in odio...",
),
],
),
),
SizedBox(height: 24.h),
],
),
),
),
);
}
Widget includedBox(String icon, String title, String disc) {
return Container(
padding: EdgeInsets.symmetric(horizontal: 12.w, vertical: 10.h),
decoration: BoxDecoration(
color: Color(0xFFFFF5F5),
borderRadius: BorderRadius.circular(10.r),
border: Border.all(color: Color(0xFFFDCDCE)),
),
child: IntrinsicWidth(
child: Row(
children: [
Image.asset(icon, scale: 4),
SizedBox(width: 16.w),
Column(
children: [
CustomText(
text: title,
size: 16.sp,
weight: FontWeight.w500,
color: Color(0xFF212121),
),
SizedBox(height: 4.h),
CustomText(
text: disc,
size: 11.sp,
weight: FontWeight.w400,
color: Color(0xFF666666),
),
],
),
],
),
),
);
}
Widget faqBox(String title, String desc) {
return Container(
padding: EdgeInsets.symmetric(horizontal: 12.w, vertical: 12.h),
decoration: BoxDecoration(
color: Color(0xFFFFF5F5),
border: Border.all(color: Color(0xFFFDCDCE)),
borderRadius: BorderRadius.circular(10.r),
),
child: Column(
children: [
Row(
children: [
CustomText(
text: title,
size: 16.sp,
weight: FontWeight.w500,
color: Color(0xFF212121),
),
SizedBox(width: 20.w),
Icon(Icons.arrow_forward_ios_outlined, size: 18.sp),
],
),
SizedBox(height: 9.h),
CustomText(text: desc, size: 11.sp, color: Color(0xFF7D7D7D)),
],
),
);
}
}

View File

@@ -0,0 +1,15 @@
import 'package:citycards_customer/attraction_details/bloc/attraction_details_event.dart';
import 'package:citycards_customer/attraction_details/bloc/attraction_details_state.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
class AttractionDetailsBloc
extends Bloc<AttractionDetailsEvent, AttractionDetailsState> {
AttractionDetailsBloc() : super(AttractionDetailsState()) {
on<SetFlowFromPass>(_setFlowFromPass);
}
void _setFlowFromPass(SetFlowFromPass event, Emitter<AttractionDetailsState> emit) {
print("Setting the flow from pass ${event.fromByPass}");
emit(state.copyWith(fromByPass: event.fromByPass));
}
}

View File

@@ -0,0 +1,9 @@
import 'package:equatable/equatable.dart';
abstract class AttractionDetailsEvent {
}
class SetFlowFromPass extends AttractionDetailsEvent{
final bool fromByPass;
SetFlowFromPass(this.fromByPass);
}

View File

@@ -0,0 +1,14 @@
import 'package:equatable/equatable.dart';
class AttractionDetailsState extends Equatable {
bool fromByPass;
AttractionDetailsState({this.fromByPass = false});
AttractionDetailsState copyWith({required bool fromByPass}) {
return AttractionDetailsState(fromByPass: fromByPass ?? this.fromByPass);
}
@override
List<Object?> get props => [fromByPass];
}

View File

@@ -0,0 +1,555 @@
import 'package:citycards_customer/attraction_details/bloc/attraction_details_bloc.dart';
import 'package:citycards_customer/attraction_details/bloc/attraction_details_state.dart';
import 'package:citycards_customer/attraction_details/view_model/attraction_details_view_model.dart';
import 'package:citycards_customer/attraction_details/widgets/share_bottomsheet.dart';
import 'package:citycards_customer/common_packages/app_bar.dart';
import 'package:citycards_customer/common_packages/custom_text.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:share_plus/share_plus.dart';
import '../../core/route_constants.dart';
class AttractionDetailsView extends StatelessWidget {
AttractionDetailsView({super.key});
final AttractionDetailsViewModel viewModel = AttractionDetailsViewModel();
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
body: SafeArea(
child: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Stack(
children: [
Image.asset(
'assets/images/koh_rong_samloem_banner.png',
height: 377.h,
width: double.infinity,
fit: BoxFit.cover,
),
Positioned(
top: 0,
left: 0,
right: 0,
child: SafeArea(
child: Padding(
padding: EdgeInsets.symmetric(
horizontal: 20.w,
vertical: 10.h,
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
CommonAppBar(
isWhiteLogo: true,
isProfilePage: false,
showDivider: true,
),
SizedBox(height: 10.h),
Row(
children: [
GestureDetector(
onTap: () => Navigator.pop(context),
child: Icon(
Icons.arrow_back,
size: 24.sp,
color: Colors.white,
),
),
SizedBox(width: 8.w),
Text(
"Koh Rong Samloem",
style: TextStyle(
fontSize: 14.sp,
fontWeight: FontWeight.w600,
color: Colors.white,
),
),
],
),
],
),
),
),
),
Positioned(
bottom: 31.h,
left: 12.w,
child: Text(
"Koh Rong\nSamloem",
style: TextStyle(
color: Colors.white,
fontSize: 44.sp,
fontWeight: FontWeight.w500,
height: 1.2,
),
),
),
Positioned(
bottom: 31.h,
right: 17.w,
child: GestureDetector(
onTap: () {
Share.share(
'Check out my City Card app!',
subject: 'City Card App',
);
// showModalBottomSheet(
// context: context,
// isScrollControlled: true,
// backgroundColor: Colors.transparent,
// builder: (context) => const ShareBottomSheet(),
// );
},
child: Container(
height: 36.h,
width: 36.w,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(20.r),
),
child: Center(
child: Icon(
Icons.share_sharp,
color: Colors.black,
size: 18.sp,
),
),
),
),
),
],
),
// About Section
Padding(
padding: EdgeInsets.only(left: 16.w, right: 16.w, top: 30.h),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"About",
style: TextStyle(
fontSize: 18.sp,
fontWeight: FontWeight.w400,
),
),
SizedBox(height: 12.32.h),
Text(
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Convallis condimentum morbi non egestas enim amet sagittis. Proin sed aliquet rhoncus ut pellentesque ullamcorper sit eget ac.Sit nisi, cras amet varius eget egestas pellentesque. Cursus gravida euismod non...",
style: TextStyle(
color: Color(0xFF262626),
fontWeight: FontWeight.w400,
fontSize: 14.sp,
height: 1.5,
),
),
],
),
),
SizedBox(height: 41.h),
// Booking Section
Padding(
padding: EdgeInsets.symmetric(horizontal: 16.w),
child: BlocBuilder<AttractionDetailsBloc, AttractionDetailsState>(
builder: (context, state) {
print("fajfasfasjfjas======= ${state.fromByPass}");
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (state.fromByPass)
Column(
children: [
Text(
"How to make a booking?",
style: TextStyle(
fontSize: 18.sp,
fontWeight: FontWeight.w400,
),
),
SizedBox(height: 16.h),
InkWell(
onTap: () => viewModel.makePhoneCall(
'+10123456789',
context,
),
borderRadius: BorderRadius.circular(8.r),
child: Container(
padding: EdgeInsets.symmetric(
horizontal: 12.w,
vertical: 12.h,
),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8.r),
border: Border.all(
color: Color(0xFFF95F62),
),
),
child: Row(
children: [
Icon(
Icons.call,
color: Color(0xFFF95F62),
size: 32.w,
),
SizedBox(width: 16.w),
Expanded(
child: Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
CustomText(
text: "Contact Number",
color: Colors.black.withOpacity(
.6,
),
size: 12.sp,
weight: FontWeight.w500,
),
SizedBox(height: 6.h),
CustomText(
text: "+1012 3456 789",
color: Colors.black,
size: 14.sp,
weight: FontWeight.w600,
),
SizedBox(height: 6.h),
CustomText(
text: "Tap to call",
color: Colors.black.withOpacity(
.4,
),
size: 12.sp,
weight: FontWeight.w400,
),
],
),
),
],
),
),
),
SizedBox(height: 16.h),
InkWell(
onTap: () => viewModel.sendEmail(
'CityCards24@gmail.com',
context,
),
borderRadius: BorderRadius.circular(8.r),
child: Container(
padding: EdgeInsets.symmetric(
horizontal: 12.w,
vertical: 12.h,
),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8.r),
border: Border.all(
color: Color(0xFFF95F62),
),
),
child: Row(
children: [
Icon(
Icons.email_sharp,
color: Color(0xFFF95F62),
size: 32.w,
),
SizedBox(width: 16.w),
Expanded(
child: Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
CustomText(
text: "Email",
color: Colors.black.withOpacity(
.6,
),
size: 12.sp,
weight: FontWeight.w500,
),
SizedBox(height: 6.h),
CustomText(
text: "CityCards24@gmail.com",
color: Colors.black,
size: 14.sp,
weight: FontWeight.w600,
),
SizedBox(height: 6.h),
CustomText(
text: "Tap to email",
color: Colors.black.withOpacity(
.4,
),
size: 12.sp,
weight: FontWeight.w400,
),
],
),
),
],
),
),
),
SizedBox(height: 16.h),
InkWell(
onTap: () {
Navigator.of(
context,
).pushNamed(RouteConstants.makeBooking);
},
child: Container(
padding: EdgeInsets.symmetric(
horizontal: 24.w,
vertical: 18.h,
),
decoration: BoxDecoration(
color: Color(0xFFF95F62),
borderRadius: BorderRadius.circular(10.r),
),
child: Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
CustomText(
text: "Via CityCards",
size: 16.sp,
weight: FontWeight.w500,
color: Colors.white,
),
SizedBox(height: 8.h),
CustomText(
text:
"Create a booking via app",
size: 11.sp,
weight: FontWeight.w400,
color: Colors.white,
),
],
),
),
Icon(
Icons.arrow_forward_ios_outlined,
color: Colors.white,
),
],
),
),
),
],
),
SizedBox(height: 30.h),
Divider(color: Colors.black.withOpacity(0.2)),
SizedBox(height: 30.h),
Text(
"What is included",
style: TextStyle(
fontSize: 24.sp,
fontWeight: FontWeight.w500,
),
),
SizedBox(height: 4.h),
Wrap(
runSpacing: 16.h,
spacing: 16.w,
children: [
includedBox(
"assets/icons/bus.png",
"Bus",
"Transportation",
),
includedBox(
"assets/icons/clock.png",
"2 day 1 night",
"Duration",
),
includedBox(
"assets/icons/bx_qr.png",
"TAC200812695",
"Product code",
),
],
),
SizedBox(height: 30.h),
Divider(color: Colors.black.withOpacity(0.2)),
SizedBox(height: 30.h),
Text(
"Exact Location",
style: TextStyle(
fontSize: 18.sp,
fontWeight: FontWeight.w400,
),
),
SizedBox(height: 8.h),
CustomText(
text: "View the location on map",
size: 12.sp,
color: Colors.black.withOpacity(.6),
),
SizedBox(height: 17.h),
ClipRRect(
borderRadius: BorderRadius.circular(13.54.r),
child: Image.asset(
height: 178.7.h,
width: double.infinity,
"assets/images/attra_detail_map.png",
fit: BoxFit.cover,
),
),
SizedBox(height: 17.h),
CustomText(
text:
"Angkor Mails Hotel \nNR6, Krong Siem Reap Cambodia",
size: 12.sp,
color: Colors.black.withOpacity(0.6),
),
SizedBox(height: 30.h),
Divider(color: Colors.black.withOpacity(0.2)),
SizedBox(height: 30.h),
Text(
"People frequently ask",
style: TextStyle(
fontSize: 18.sp,
fontWeight: FontWeight.w400,
),
),
SizedBox(height: 15.h),
faqBox(
"About this place",
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. A id diam nisl, non justo, in odio...",
() {},
),
SizedBox(height: 15.h),
faqBox(
"Term and condition",
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. A id diam nisl, non justo, in odio...",
() {
Navigator.pushNamed(
context,
RouteConstants.termsAndCondition,
);
},
),
SizedBox(height: 15.h),
faqBox(
"Cancellation Policy",
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. A id diam nisl, non justo, in odio...",
() {},
),
],
);
},
),
),
SizedBox(height: 24.h),
],
),
),
),
);
}
Widget includedBox(String icon, String title, String disc) {
return Container(
padding: EdgeInsets.symmetric(horizontal: 12.w, vertical: 10.h),
decoration: BoxDecoration(
color: Color(0xFFFFF5F5),
borderRadius: BorderRadius.circular(10.r),
border: Border.all(color: Color(0xFFFDCDCE)),
),
child: IntrinsicWidth(
child: Row(
children: [
Image.asset(icon, scale: 4),
SizedBox(width: 16.w),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
CustomText(
text: title,
size: 16.sp,
weight: FontWeight.w500,
color: Color(0xFF212121),
),
SizedBox(height: 4.h),
CustomText(
text: disc,
size: 11.sp,
weight: FontWeight.w400,
color: Color(0xFF666666),
),
],
),
],
),
),
);
}
Widget faqBox(String title, String desc, Function() onTap) {
return GestureDetector(
onTap: onTap,
child: Container(
padding: EdgeInsets.symmetric(horizontal: 12.w, vertical: 12.h),
decoration: BoxDecoration(
color: Color(0xFFFFF5F5),
border: Border.all(color: Color(0xFFFDCDCE)),
borderRadius: BorderRadius.circular(10.r),
),
child: Column(
children: [
Row(
children: [
CustomText(
text: title,
size: 16.sp,
weight: FontWeight.w500,
color: Color(0xFF212121),
),
SizedBox(width: 20.w),
Icon(Icons.arrow_forward_ios_outlined, size: 18.sp),
],
),
SizedBox(height: 9.h),
CustomText(text: desc, size: 11.sp, color: Color(0xFF7D7D7D)),
],
),
),
);
}
}

View File

@@ -0,0 +1,33 @@
import 'package:url_launcher/url_launcher.dart';
import 'package:flutter/material.dart';
class AttractionDetailsViewModel {
// 📞 Call method
Future<void> makePhoneCall(String phoneNumber, BuildContext context) async {
final Uri url = Uri(scheme: 'tel', path: phoneNumber);
if (await canLaunchUrl(url)) {
await launchUrl(url);
} else {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Could not launch $phoneNumber')),
);
}
}
// 📧 Email method
Future<void> sendEmail(String emailAddress, BuildContext context) async {
final Uri url = Uri(
scheme: 'mailto',
path: emailAddress,
query: 'subject=Hello City Cards&body=Hi there,',
);
if (await canLaunchUrl(url)) {
await launchUrl(url);
} else {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Could not launch mail app')),
);
}
}
}

View File

@@ -1,8 +1,11 @@
import 'package:citycards_customer/attraction_details/bloc/attraction_details_bloc.dart';
import 'package:citycards_customer/common_packages/app_bar.dart';
import 'package:citycards_customer/common_packages/back_widget.dart';
import 'package:citycards_customer/core/route_constants.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import '../../attraction_details/bloc/attraction_details_event.dart';
import '../../common_packages/custom_search_field.dart';
import '../blocs/attractions_bloc.dart';
import '../repository/attractions_repository.dart';
@@ -15,19 +18,27 @@ class AttractionsPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return BlocProvider(
create: (_) {
final bloc = AttractionsBloc(AttractionsRepository());
return MultiBlocProvider(
providers: [
BlocProvider(
create: (_) {
final bloc = AttractionsBloc(AttractionsRepository());
// 🔥 Trigger event based on source
if (source == "home") {
bloc.add(LoadAttractions());
} else {
print("QR Passss -=------------------");
context.read<AttractionDetailsBloc>().add(SetFlowFromPass(true));
bloc.add(LoadMyPassAttraction());
}
// 🔥 Trigger event based on source
if (source == "home") {
bloc.add(LoadAttractions());
} else if (source == "qrPass") {
bloc.add(LoadMyPassAttraction());
}
return bloc;
},
),
BlocProvider(create: (_) => AttractionDetailsBloc(),
return bloc;
},
)
],
child: BlocBuilder<AttractionsBloc, AttractionsState>(
builder: (context, state) {
final bloc = context.read<AttractionsBloc>();
@@ -41,7 +52,7 @@ class AttractionsPage extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// App bar
CommonAppBar(isWhiteLogo: false, isProfilePage: false),
CommonAppBar(isWhiteLogo: false, isProfilePage: false, showDivider: true),
backWidget(context, "Your Attraction", Colors.black),
const SizedBox(height: 20),

View File

@@ -11,7 +11,12 @@ class AttractionCard extends StatelessWidget {
Widget build(BuildContext context) {
return InkWell(
onTap: (){
Navigator.of(context).pushNamed(RouteConstants.attractionDetails);
print("the value of from page this pushed ${ModalRoute.of(context)?.settings.arguments}");
Navigator.pushNamed(
context,
RouteConstants.attractionDetails,
arguments: ModalRoute.of(context)?.settings.arguments, // FORWARD
);
},
child: Container(
margin: const EdgeInsets.symmetric(vertical: 8, horizontal: 8),

View File

@@ -41,7 +41,7 @@ class BuyPassView extends StatelessWidget {
children: [
Padding(
padding: EdgeInsets.symmetric(horizontal: 20.0.w),
child: CommonAppBar(isWhiteLogo: false, isProfilePage: true),
child: CommonAppBar(isWhiteLogo: false, isProfilePage: true,showDivider: true,),
),
Padding(

View File

@@ -26,139 +26,137 @@ class PassCardView extends StatelessWidget {
border: Border.all(color:( themeColor ?? Color(0xFFF95FAF)).withOpacity(0.24)),
borderRadius: BorderRadius.circular(8.r),
),
child: Expanded(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
ClipRRect(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(8.r),
bottomLeft: Radius.circular(8.r)
),
child: Image.asset(
"assets/images/card_banner.png",
scale: 4,
width: 103.w,
height:140.h,
fit: BoxFit.cover,
),
),
SizedBox(width: 6.66.w),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
CustomText(
text: "Melbourne",
weight: FontWeight.w500,
size: 16.sp,
),
Row(
children: [
Text(
"From ",
style: TextStyle(
color: Colors.black.withOpacity(0.6),
fontSize: 11.sp,
fontWeight: FontWeight.w400,
),
),
Text(
"\$80",
style: TextStyle(
color:themeColor,
fontWeight: FontWeight.w500,
fontSize: 24.sp,
),
),
Text(
" /Adult",
style: TextStyle(
color: Colors.black.withOpacity(0.8),
fontSize: 11.sp,
fontWeight: FontWeight.w400,
),
),
],
),
Row(
children: [
Text(
"and ",
style: TextStyle(
color: Colors.black.withOpacity(0.6),
fontSize: 11.sp,
fontWeight: FontWeight.w400,
),
),
Text(
"\$10",
style: TextStyle(
color: themeColor,
fontWeight: FontWeight.w500,
fontSize: 24.sp,
),
),
Text(
" /child",
style: TextStyle(
color: Colors.black.withOpacity(0.8),
fontSize: 11.sp,
fontWeight: FontWeight.w400,
),
),
],
),
SizedBox(
width: 193.w,
child: CustomText(
text:
"Dive into an extensive selection of thrilling destinations!",
color: Color(0xFF000000).withOpacity(0.6),
size: 11.sp,
),
),
],
),
],
),
Container(
width: 35.w,
height: 140.h,
decoration: BoxDecoration(
color: themeColor,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
ClipRRect(
borderRadius: BorderRadius.only(
bottomRight: Radius.circular(8.r),
topRight: Radius.circular(8.r),
topLeft: Radius.circular(8.r),
bottomLeft: Radius.circular(8.r)
),
child: Image.asset(
"assets/images/card_banner.png",
scale: 4,
width: 103.w,
height:140.h,
fit: BoxFit.cover,
),
),
child: RotatedBox(
quarterTurns: -1,
child: Center(
child: RichText(
text: TextSpan(
children: [
TextSpan(
text: "Flexi ",
style: TextStyle(color: Colors.white, fontSize: 16.sp),
SizedBox(width: 6.66.w),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
CustomText(
text: "Melbourne",
weight: FontWeight.w500,
size: 16.sp,
),
Row(
children: [
Text(
"From ",
style: TextStyle(
color: Colors.black.withOpacity(0.6),
fontSize: 11.sp,
fontWeight: FontWeight.w400,
),
TextSpan(
text: "Card",
style: TextStyle(color: Colors.white, fontSize: 12.sp),
),
Text(
"\$80",
style: TextStyle(
color:themeColor,
fontWeight: FontWeight.w500,
fontSize: 24.sp,
),
],
),
Text(
" /Adult",
style: TextStyle(
color: Colors.black.withOpacity(0.8),
fontSize: 11.sp,
fontWeight: FontWeight.w400,
),
),
],
),
Row(
children: [
Text(
"and ",
style: TextStyle(
color: Colors.black.withOpacity(0.6),
fontSize: 11.sp,
fontWeight: FontWeight.w400,
),
),
Text(
"\$10",
style: TextStyle(
color: themeColor,
fontWeight: FontWeight.w500,
fontSize: 24.sp,
),
),
Text(
" /child",
style: TextStyle(
color: Colors.black.withOpacity(0.8),
fontSize: 11.sp,
fontWeight: FontWeight.w400,
),
),
],
),
SizedBox(
width: 193.w,
child: CustomText(
text:
"Dive into an extensive selection of thrilling destinations!",
color: Color(0xFF000000).withOpacity(0.6),
size: 11.sp,
),
),
],
),
],
),
Container(
width: 35.w,
height: 140.h,
decoration: BoxDecoration(
color: themeColor,
borderRadius: BorderRadius.only(
bottomRight: Radius.circular(8.r),
topRight: Radius.circular(8.r),
),
),
child: RotatedBox(
quarterTurns: -1,
child: Center(
child: RichText(
text: TextSpan(
children: [
TextSpan(
text: "Flexi ",
style: TextStyle(color: Colors.white, fontSize: 16.sp),
),
TextSpan(
text: "Card",
style: TextStyle(color: Colors.white, fontSize: 12.sp),
),
],
),
),
),
),
],
),
),
],
),
);
}

View File

@@ -126,7 +126,6 @@ class _PaymentCardState extends State<PaymentCard> {
onTap: () {
Navigator.of(
context,
rootNavigator: true,
).pushNamed(RouteConstants.checkout);
},
label: "Proceed to Pay",

View File

@@ -38,6 +38,7 @@ class _MyCartPageState extends State<MyCartPage> {
isWhiteLogo: false,
isProfilePage: false,
showCart: false,
showDivider: true,
),
backWidget(context, "Your Cart", Colors.black),
SizedBox(height: 24.h),

View File

@@ -14,26 +14,23 @@ class TicketCard extends StatelessWidget {
clipper: TicketClipper(),
child: Container(
width: 270.w,
height: 410.h,
height: 400.h,
padding: EdgeInsets.all(16.w),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12.r),
),
child: Column(
children: [
// Image Section
ClipRRect(
borderRadius: BorderRadius.circular(12.r),
child: Image.asset(
'assets/images/card_banner.png',
width: double.infinity,
width: 237.w,
height: 198.h,
fit: BoxFit.cover,
),
),
SizedBox(height: 24.h),
// Dashed divider
SizedBox(height: 20.h),
SizedBox(
width: 200.w,
child: DashedDivider(
@@ -41,7 +38,7 @@ class TicketCard extends StatelessWidget {
thickness: 2.h,
),
),
SizedBox(height: 6.h),
Text(
"Melbourne",
style: TextStyle(
@@ -49,7 +46,7 @@ class TicketCard extends StatelessWidget {
fontWeight: FontWeight.w500,
),
),
SizedBox(height: 12.h),
SizedBox(height: 6.h),
_infoRow("Postcards :", "5"),
_infoRow("Date :", "22/04/2025"),
_infoRow("Time :", "12:00PM - 2:00PM"),
@@ -84,36 +81,39 @@ class TicketCard extends StatelessWidget {
class TicketPainter extends CustomPainter {
@override
void paint(Canvas canvas, Size size) {
const notchRadius = 23.0;
const dividerY = 222.0;
final notchRadius = 23.r;
final dividerY = 240.h;
final ticketPath = Path()
..moveTo(12, 0)
..lineTo(size.width - 12, 0)
..arcToPoint(Offset(size.width, 12), radius: const Radius.circular(12))
..moveTo(12.w, 0)
..lineTo(size.width - 12.w, 0)
..arcToPoint(Offset(size.width, 12.h), radius: Radius.circular(12.r))
..lineTo(size.width, dividerY - notchRadius)
..arcToPoint(
Offset(size.width, dividerY + notchRadius),
radius: const Radius.circular(notchRadius),
radius: Radius.circular(notchRadius),
clockwise: false,
)
..lineTo(size.width, size.height - 12)
..arcToPoint(Offset(size.width - 12, size.height),
radius: const Radius.circular(12))
..lineTo(12, size.height)
..arcToPoint(Offset(0, size.height - 12),
radius: const Radius.circular(12))
..lineTo(size.width, size.height - 12.h)
..arcToPoint(
Offset(size.width - 12.w, size.height),
radius: Radius.circular(12.r),
)
..lineTo(12.w, size.height)
..arcToPoint(
Offset(0, size.height - 12.h),
radius: Radius.circular(12.r),
)
..lineTo(0, dividerY + notchRadius)
..arcToPoint(
Offset(0, dividerY - notchRadius),
radius: const Radius.circular(notchRadius),
radius: Radius.circular(notchRadius),
clockwise: false,
)
..lineTo(0, 12)
..arcToPoint(Offset(12, 0), radius: const Radius.circular(12))
..lineTo(0, 12.h)
..arcToPoint(Offset(12.w, 0), radius: Radius.circular(12.r))
..close();
// 🌑 Draw even soft black shadow around all sides
final shadowPaint = Paint()
..color = Colors.black.withOpacity(0.3)
..maskFilter = const MaskFilter.blur(BlurStyle.outer, 8);
@@ -134,33 +134,37 @@ class TicketPainter extends CustomPainter {
class TicketClipper extends CustomClipper<Path> {
@override
Path getClip(Size size) {
const notchRadius = 23.0;
const dividerY = 222.0;
final notchRadius = 23.r;
final dividerY = 240.h;
final path = Path()
..moveTo(12, 0)
..lineTo(size.width - 12, 0)
..arcToPoint(Offset(size.width, 12), radius: const Radius.circular(12))
..moveTo(12.w, 0)
..lineTo(size.width - 12.w, 0)
..arcToPoint(Offset(size.width, 12.h), radius: Radius.circular(12.r))
..lineTo(size.width, dividerY - notchRadius)
..arcToPoint(
Offset(size.width, dividerY + notchRadius),
radius: const Radius.circular(notchRadius),
radius: Radius.circular(notchRadius),
clockwise: false,
)
..lineTo(size.width, size.height - 12)
..arcToPoint(Offset(size.width - 12, size.height),
radius: const Radius.circular(12))
..lineTo(12, size.height)
..arcToPoint(Offset(0, size.height - 12),
radius: const Radius.circular(12))
..lineTo(size.width, size.height - 12.h)
..arcToPoint(
Offset(size.width - 12.w, size.height),
radius: Radius.circular(12.r),
)
..lineTo(12.w, size.height)
..arcToPoint(
Offset(0, size.height - 12.h),
radius: Radius.circular(12.r),
)
..lineTo(0, dividerY + notchRadius)
..arcToPoint(
Offset(0, dividerY - notchRadius),
radius: const Radius.circular(notchRadius),
radius: Radius.circular(notchRadius),
clockwise: false,
)
..lineTo(0, 12)
..arcToPoint(Offset(12, 0), radius: const Radius.circular(12))
..lineTo(0, 12.h)
..arcToPoint(Offset(12.w, 0), radius: Radius.circular(12.r))
..close();
return path;

View File

@@ -0,0 +1,63 @@
import 'package:flutter_bloc/flutter_bloc.dart';
/// EVENTS
abstract class EmailVerify {}
class SetEmailEvent extends EmailVerify {
final String email;
SetEmailEvent(this.email);
}
class CheckOtpFilled extends EmailVerify {
final bool isOtpFilled;
CheckOtpFilled(this.isOtpFilled);
}
class CheckIsLoggedIn extends EmailVerify{}
/// STATE
class EmailVerifyState {
final String email;
final bool isOtpFilled;
final bool loggedIn;
EmailVerifyState({
required this.email,
required this.isOtpFilled,
required this.loggedIn
});
EmailVerifyState copyWith({
String? email,
bool? isOtpFilled,
bool? loggedIn
}) {
return EmailVerifyState(
email: email ?? this.email,
isOtpFilled: isOtpFilled ?? this.isOtpFilled,
loggedIn: loggedIn ?? this.loggedIn
);
}
}
/// BLOC
class EmailVerifyBloc extends Bloc<EmailVerify, EmailVerifyState> {
EmailVerifyBloc()
: super(EmailVerifyState(email: "", isOtpFilled: false,
loggedIn: false
)) {
on<SetEmailEvent>((event, emit) {
emit(state.copyWith(email: event.email));
});
on<CheckOtpFilled>((event, emit) {
emit(state.copyWith(isOtpFilled: event.isOtpFilled));
});
on<CheckIsLoggedIn>((event,emit){
emit(state.copyWith(loggedIn: true));
});
}
}

View File

@@ -0,0 +1,15 @@
import 'package:shared_preferences/shared_preferences.dart';
class LocalAuth {
Future<void> setloggedIn(bool islogged)async{
final SharedPreferences prefs = await SharedPreferences.getInstance();
prefs.setBool('islogged', islogged);
}
Future<bool> getloggedIn()async{
final SharedPreferences prefs = await SharedPreferences.getInstance();
return prefs.getBool('islogged') ?? false;
}
}

View File

@@ -1,3 +1,5 @@
import 'package:citycards_customer/checkout/bloc/email_verify_bloc.dart';
import 'package:citycards_customer/checkout/repository/auth_local_repository.dart';
import 'package:citycards_customer/checkout/widget/all_coupons_bottomsheet.dart';
import 'package:citycards_customer/checkout/widget/login_email_bottomsheet.dart';
import 'package:citycards_customer/common_packages/app_bar.dart';
@@ -5,6 +7,7 @@ import 'package:citycards_customer/common_packages/custom_filled_button.dart';
import 'package:citycards_customer/common_packages/custom_text.dart';
import 'package:citycards_customer/common_packages/custom_dashed_line.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
class CheckoutView extends StatelessWidget {
@@ -12,354 +15,383 @@ class CheckoutView extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
resizeToAvoidBottomInset: true,
backgroundColor: Colors.white,
body: SafeArea(
child: Padding(
padding: EdgeInsets.symmetric(horizontal: 20.w),
child: Column(
children: [
CommonAppBar(
isWhiteLogo: false,
isProfilePage: false,
showCart: false,
),
Row(
children: [
GestureDetector(
onTap: () {
Navigator.pop(context);
},
child: Icon(Icons.arrow_back),
),
SizedBox(width: 8.w),
CustomText(text: "Checkout", size: 12.sp),
],
),
SizedBox(height: 22.h),
Container(
decoration: BoxDecoration(
color: Colors.white,
border: Border.all(color: Color(0xFFF95FAF).withOpacity(0.2)),
borderRadius: BorderRadius.circular(8.r),
return BlocProvider(
create: (context) => EmailVerifyBloc(),
child: Scaffold(
resizeToAvoidBottomInset: true,
backgroundColor: Colors.white,
body: SafeArea(
child: Padding(
padding: EdgeInsets.symmetric(horizontal: 20.w),
child: Column(
children: [
CommonAppBar(
isWhiteLogo: false,
isProfilePage: false,
showCart: false,
showDivider: true,
),
Row(
children: [
GestureDetector(
onTap: () {
Navigator.pop(context);
},
child: Icon(Icons.arrow_back),
),
SizedBox(width: 8.w),
CustomText(text: "Checkout", size: 12.sp),
],
),
child: Expanded(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
ClipRRect(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(8.r),
bottomLeft: Radius.circular(8.r),
),
child: Image.asset(
"assets/images/card_banner.png",
scale: 4,
width: 105.w,
height: 123.h,
fit: BoxFit.cover,
),
),
SizedBox(width: 6.66.w),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
CustomText(
text: "Melbourne",
weight: FontWeight.w500,
size: 16.sp,
),
SizedBox(height: 5.h),
CustomText(
text: "2 Days",
color: Color(0xFF8E8E8E),
size: 12.sp,
),
SizedBox(height: 5.h),
SizedBox(
width: MediaQuery.of(context).size.width * .5,
child: Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
SizedBox(height: 22.h),
Container(
decoration: BoxDecoration(
color: Colors.white,
border: Border.all(
color: Color(0xFFF95FAF).withOpacity(0.2),
),
borderRadius: BorderRadius.circular(8.r),
),
child: Expanded(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
ClipRRect(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(8.r),
bottomLeft: Radius.circular(8.r),
),
child: Image.asset(
"assets/images/card_banner.png",
scale: 4,
width: 105.w,
height: 123.h,
fit: BoxFit.cover,
),
),
SizedBox(width: 6.66.w),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
CustomText(
text: "Melbourne",
weight: FontWeight.w500,
size: 16.sp,
),
SizedBox(height: 5.h),
CustomText(
text: "2 Days",
color: Color(0xFF8E8E8E),
size: 12.sp,
),
SizedBox(height: 5.h),
SizedBox(
width: MediaQuery.of(context).size.width * .5,
child: Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
Image.asset(
'assets/icons/adult.png',
scale: 4,
),
SizedBox(width: 4.w),
CustomText(
text: "3 adults",
color: Color(0xFF8E8E8E),
size: 12.sp,
),
],
),
Row(
children: [
Image.asset(
'assets/icons/qty.png',
scale: 4,
),
SizedBox(width: 4.w),
Text.rich(
TextSpan(
children: [
TextSpan(
text: "Qty:",
style: TextStyle(
color: Color(0xFF8E8E8E),
fontSize: 12.sp,
),
),
TextSpan(
text: " 2",
style: TextStyle(
color: Color(0xFF000000),
fontSize: 12.sp,
fontWeight: FontWeight.w500,
),
),
],
),
),
],
),
],
),
),
SizedBox(height: 5.h),
Row(
children: [
Row(
children: [
Image.asset(
'assets/icons/adult.png',
scale: 4,
),
SizedBox(width: 4.w),
CustomText(
text: "3 adults",
color: Color(0xFF8E8E8E),
size: 12.sp,
),
],
Image.asset(
"assets/icons/kid.png",
scale: 4,
),
SizedBox(width: 4.w),
CustomText(
text: "3 Kids",
color: Color(0xFF8E8E8E),
size: 12.sp,
),
Row(
children: [
Image.asset(
'assets/icons/qty.png',
scale: 4,
),
SizedBox(width: 4.w),
Text.rich(
TextSpan(
children: [
TextSpan(
text: "Qty:",
style: TextStyle(
color: Color(0xFF8E8E8E),
fontSize: 12.sp,
),
),
TextSpan(
text: " 2",
style: TextStyle(
color: Color(0xFF000000),
fontSize: 12.sp,
fontWeight: FontWeight.w500,
),
),
],
),
),
],
SizedBox(width: 53.w),
CustomText(
text: "\$49.50",
size: 24.sp,
weight: FontWeight.w500,
color: Color(0xFFF95F62),
),
],
),
],
),
],
),
Container(
width: 35.w,
height: 123.h,
decoration: BoxDecoration(
color: Color(0xFFF95FAF),
borderRadius: BorderRadius.only(
bottomRight: Radius.circular(8.r),
topRight: Radius.circular(8.r),
),
),
child: RotatedBox(
quarterTurns: -1,
child: Center(
child: RichText(
text: TextSpan(
children: [
TextSpan(
text: "Flexi ",
style: TextStyle(
color: Colors.white,
fontSize: 16.sp,
),
),
TextSpan(
text: "Card",
style: TextStyle(
color: Colors.white,
fontSize: 12.sp,
),
),
],
),
),
),
),
),
],
),
),
),
SizedBox(height: 5.h),
Row(
children: [
Image.asset("assets/icons/kid.png", scale: 4),
SizedBox(width: 4.w),
CustomText(
text: "3 Kids",
color: Color(0xFF8E8E8E),
size: 12.sp,
),
SizedBox(width: 53.w),
CustomText(
text: "\$49.50",
size: 24.sp,
weight: FontWeight.w500,
color: Color(0xFFF95F62),
),
],
SizedBox(height: 15.h),
Container(
padding: EdgeInsets.symmetric(
horizontal: 12.w,
vertical: 12.h,
),
decoration: BoxDecoration(
color: Color(0xFFFFF5F5),
borderRadius: BorderRadius.circular(8.r),
border: Border.all(
color: Color(0xFFBB474A).withOpacity(0.4),
width: 0.8,
),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
CustomText(
text: "Get 10% off on your first trip",
color: Color(0xFF262626),
size: 14.sp,
),
SizedBox(height: 7.h),
Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
GestureDetector(
onTap: () {
showModalBottomSheet(
context: context,
isScrollControlled: true,
backgroundColor: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(
top: Radius.circular(12.r),
),
),
builder: (_) => AllCouponsBottomsheet(),
);
},
child: CustomText(
text: "View all coupons",
color: Color(0xFFF95F62),
size: 12,
),
),
SizedBox(width: 3.w),
Icon(Icons.arrow_right, color: Color(0xFFF95F62)),
],
),
],
),
const Spacer(),
Container(
width: 35.w,
height: 123.h,
decoration: BoxDecoration(
color: Color(0xFFF95FAF),
borderRadius: BorderRadius.only(
bottomRight: Radius.circular(8.r),
topRight: Radius.circular(8.r),
),
padding: EdgeInsets.symmetric(
horizontal: 20.w,
vertical: 10.h,
),
child: RotatedBox(
quarterTurns: -1,
child: Center(
child: RichText(
text: TextSpan(
children: [
TextSpan(
text: "Flexi ",
style: TextStyle(
color: Colors.white,
fontSize: 16.sp,
),
),
TextSpan(
text: "Card",
style: TextStyle(
color: Colors.white,
fontSize: 12.sp,
),
),
],
),
),
),
decoration: BoxDecoration(
border: Border.all(color: Color(0xFFF95F62)),
borderRadius: BorderRadius.circular(8.r),
),
child: CustomText(
text: "Apply",
color: Color(0xFFF95F62),
size: 14.sp,
),
),
],
),
),
),
SizedBox(height: 15.h),
Container(
padding: EdgeInsets.symmetric(horizontal: 12.w, vertical: 12.h),
decoration: BoxDecoration(
color: Color(0xFFFFF5F5),
borderRadius: BorderRadius.circular(8.r),
border: Border.all(
color: Color(0xFFBB474A).withOpacity(0.4),
width: 0.8,
),
SizedBox(height: 15.h),
DashedDivider(
color: Color(0xFFACACAC),
thickness: 1.h,
dashLength: 4,
dashSpace: 4,
),
child: Row(
SizedBox(height: 10.h),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
CustomText(
text: "Get 10% off on your first trip",
color: Color(0xFF262626),
size: 14.sp,
),
SizedBox(height: 7.h),
Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
GestureDetector(
onTap: () {
showModalBottomSheet(
context: context,
isScrollControlled: true,
backgroundColor: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(
top: Radius.circular(12.r),
),
),
builder: (_) => AllCouponsBottomsheet(),
);
},
child: CustomText(
text: "View all coupons",
color: Color(0xFFF95F62),
size: 12,
),
),
SizedBox(width: 3.w),
Icon(Icons.arrow_right, color: Color(0xFFF95F62)),
],
),
],
),
const Spacer(),
Container(
padding: EdgeInsets.symmetric(
horizontal: 20.w,
vertical: 10.h,
),
decoration: BoxDecoration(
border: Border.all(color: Color(0xFFF95F62)),
borderRadius: BorderRadius.circular(8.r),
),
child: CustomText(
text: "Apply",
color: Color(0xFFF95F62),
size: 14.sp,
),
CustomText(text: "Subtotal", size: 14.sp),
CustomText(
text: "\$49.50",
size: 14.sp,
weight: FontWeight.w500,
),
],
),
),
SizedBox(height: 15.h),
DashedDivider(
color: Color(0xFFACACAC),
thickness: 1.h,
dashLength: 4,
dashSpace: 4,
),
SizedBox(height: 10.h),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
CustomText(text: "Subtotal", size: 14.sp),
CustomText(
text: "\$49.50",
size: 14.sp,
weight: FontWeight.w500,
),
],
),
SizedBox(height: 14.h),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
CustomText(text: "Discount", size: 14.sp),
CustomText(
text: "-7.20%",
size: 14.sp,
weight: FontWeight.w500,
),
],
),
SizedBox(height: 10.h),
DashedDivider(
color: Color(0xFFACACAC),
thickness: 1.h,
dashLength: 4,
dashSpace: 4,
),
SizedBox(height: 10.h),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
CustomText(text: 'Total', size: 14.sp),
SizedBox(height: 4.h),
CustomText(
text: "Including \$2.24 in taxes",
size: 12.sp,
color: Colors.black.withOpacity(0.6),
),
],
SizedBox(height: 14.h),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
CustomText(text: "Discount", size: 14.sp),
CustomText(
text: "-7.20%",
size: 14.sp,
weight: FontWeight.w500,
),
),
CustomText(
text: "\$42.60",
size: 24.sp,
weight: FontWeight.w500,
),
],
),
const Spacer(),
CustomFilledButton(
onTap: () {
showModalBottomSheet(
context: context,
isScrollControlled: true,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(
top: Radius.circular(12.r),
],
),
SizedBox(height: 10.h),
DashedDivider(
color: Color(0xFFACACAC),
thickness: 1.h,
dashLength: 4,
dashSpace: 4,
),
SizedBox(height: 10.h),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
CustomText(text: 'Total', size: 14.sp),
SizedBox(height: 4.h),
CustomText(
text: "Including \$2.24 in taxes",
size: 12.sp,
color: Colors.black.withOpacity(0.6),
),
],
),
),
builder: (_) => const LoginEmailBottomsheet(),
);
},
width: double.infinity,
label: "Login to Checkout",
),
SizedBox(height: 25.h),
],
CustomText(
text: "\$42.60",
size: 24.sp,
weight: FontWeight.w500,
),
],
),
const Spacer(),
FutureBuilder(
future: LocalAuth().getloggedIn(),
builder: (context, snap) {
final isLoggedIn = snap.data ?? false;
return BlocBuilder<EmailVerifyBloc, EmailVerifyState>(
builder: (context, state){
return CustomFilledButton(
onTap: () async {
final rootContext = context;
showModalBottomSheet(
backgroundColor: Colors.white,
context: context,
isScrollControlled: true,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(
top: Radius.circular(12.r),
),
),
builder: (_) => BlocProvider(
create: (rootContext) => EmailVerifyBloc(),
child: LoginEmailBottomsheet(
rootContext: rootContext,
),
),
);
},
width: double.infinity,
label: isLoggedIn || state.loggedIn ? "Proceed to Checkouts" :"Login to Checkout",
);
},
);
},
),
SizedBox(height: 25.h),
],
),
),
),
),

View File

@@ -1,4 +1,4 @@
import 'package:citycards_customer/checkout/widget/purchase_details_bottomsheet.dart';
import 'package:citycards_customer/postcard/widgets/purchase_details_bottom_sheet.dart';
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:citycards_customer/common_packages/custom_text.dart';
@@ -6,11 +6,23 @@ import 'package:citycards_customer/common_packages/custom_text.dart';
class AllCouponsBottomsheet extends StatelessWidget {
AllCouponsBottomsheet({super.key});
final List<String> coupons = [
"assets/images/red_coupon.png",
"assets/images/green_coupon.png",
"assets/images/orange_coupon.png",
"assets/images/orange_coupon.png",
final List<Map<String, String>> coupons = [
{
"text": "Flat 3% cashback using Amazon Pay Balance",
"coupon_code": "AMZNPAY3",
},
{
"text": "Flat 3% cashback using Amazon Pay Balance",
"coupon_code": "AMZNPAY3",
},
{
"text": "Flat 3% cashback using Amazon Pay Balance",
"coupon_code": "AMZNPAY3",
},
{
"text": "Flat 3% cashback using Amazon Pay Balance",
"coupon_code": "AMZNPAY3",
},
];
@override
@@ -48,6 +60,7 @@ class AllCouponsBottomsheet extends StatelessWidget {
itemCount: coupons.length,
separatorBuilder: (_, __) => SizedBox(height: 12.h),
itemBuilder: (context, index) {
final coupon = coupons[index];
return Container(
alignment: Alignment.center,
padding: EdgeInsets.symmetric(horizontal: 8.w, vertical: 8.h),
@@ -58,42 +71,62 @@ class AllCouponsBottomsheet extends StatelessWidget {
color: const Color(0xFFF95F62).withOpacity(0.12),
),
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.center,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Image.asset(
width: 183.9.w,
height: 72.82.h,
coupons[index],
fit: BoxFit.cover,
),
GestureDetector(
onTap: (){
Navigator.pop(context);
showModalBottomSheet(context: context,
isScrollControlled: true,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(
top: Radius.circular(12.r),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
SizedBox(
width: 220.w,
child: CustomText(
text: coupon['text'] ?? "",
size: 12.sp,
weight: FontWeight.w400,
),
),
GestureDetector(
onTap: () {
Navigator.pop(context);
PurchaseDetailsBottomSheet.show(context);
},
child: Container(
width: 110.w,
height: 44.h,
decoration: BoxDecoration(
color: Color(0xFFF95F62),
borderRadius: BorderRadius.circular(12.r),
),
child: Center(
child: CustomText(
text: "Apply Coupon",
size: 12.sp,
color: Colors.white,
),
),
builder: (_) => const PurchaseDetailsBottomsheet());
},
child: Container(
width: 110.w,
height: 44.h,
decoration: BoxDecoration(
color: Color(0xFFF95F62),
borderRadius: BorderRadius.circular(12.r),
),
child: Center(
child: CustomText(
text: "Apply Coupon",
size: 12.sp,
color: Colors.white,
),
),
],
),
SizedBox(height: 8.h),
Container(
height: 32.h,
width: 83.w,
decoration: BoxDecoration(
color: Color(0xFFF95F62).withOpacity(0.12),
border: Border.all(color: Color(0xFFF95F62)),
borderRadius: BorderRadius.circular(6.r),
),
child: Center(
child: CustomText(
text: coupon['coupon_code'] ?? "",
size: 12.sp,
weight: FontWeight.w400,
color: Color(0xFFF95F62),
),
),
),
],

View File

@@ -1,16 +1,39 @@
import 'package:citycards_customer/checkout/bloc/email_verify_bloc.dart';
import 'package:citycards_customer/checkout/widget/verify_otp_bottomsheet.dart';
import 'package:citycards_customer/common_packages/custom_filled_button.dart';
import 'package:citycards_customer/common_packages/custom_text.dart';
import 'package:citycards_customer/core/route_constants.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
class LoginEmailBottomsheet extends StatelessWidget {
const LoginEmailBottomsheet({super.key});
class LoginEmailBottomsheet extends StatefulWidget {
final BuildContext rootContext;
LoginEmailBottomsheet({super.key, required this.rootContext});
@override
State<LoginEmailBottomsheet> createState() => _LoginEmailBottomsheetState();
}
class _LoginEmailBottomsheetState extends State<LoginEmailBottomsheet> {
TextEditingController emailController = TextEditingController();
String? emailError;
bool emailValidate() {
final emailRegex = RegExp(r'^[\w\.-]+@[\w\.-]+\.\w+$');
setState(() {
emailError = !emailRegex.hasMatch(emailController.text.trim())
? "Invalid email format"
: null;
});
return emailError == null;
}
@override
Widget build(BuildContext context) {
return AnimatedPadding(
duration: const Duration(milliseconds: 250),
curve: Curves.easeOut,
padding: EdgeInsets.only(
@@ -25,7 +48,11 @@ class LoginEmailBottomsheet extends StatelessWidget {
children: [
Image.asset("assets/logo/logo_city_cards_orange.png", scale: 4),
SizedBox(height: 8.h),
CustomText(text: "Get Started", size: 18.sp, weight: FontWeight.w500),
CustomText(
text: "Get Started",
size: 18.sp,
weight: FontWeight.w500,
),
SizedBox(height: 42.h),
CustomText(
text: "Enter your email to begin your CityCards journey",
@@ -35,19 +62,49 @@ class LoginEmailBottomsheet extends StatelessWidget {
SizedBox(height: 12.h),
TextField(
controller: emailController,
onChanged: (val) {
final bloc = context.read<EmailVerifyBloc>();
setState(() => emailValidate());
bloc.add(SetEmailEvent(val));
},
decoration: InputDecoration(
errorText: emailError,
filled: true,
contentPadding: EdgeInsets.symmetric(vertical: 6.h),
fillColor: const Color(0xFFFFF5F5),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(color: const Color(0xFFBB474A), width: 0.4.w),
borderSide: BorderSide(
color: const Color(0xFFBB474A),
width: 0.4.w,
),
borderRadius: BorderRadius.circular(8.sp),
),
errorBorder: OutlineInputBorder(
borderSide: BorderSide(
color: const Color(0xFFBB474A),
width: 0.4.w,
),
borderRadius: BorderRadius.circular(8.sp),
),
focusedErrorBorder: OutlineInputBorder(
borderSide: BorderSide(
color: const Color(0xFFBB474A),
width: 0.4.w,
),
borderRadius: BorderRadius.circular(8.sp),
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: const Color(0xFFBB474A), width: 0.4.w),
borderSide: BorderSide(
color: const Color(0xFFBB474A),
width: 0.4.w,
),
borderRadius: BorderRadius.circular(8.sp),
),
prefixIcon: const Icon(Icons.email_outlined, color: Color(0xFFF95F62)),
prefixIcon: const Icon(
Icons.email_outlined,
color: Color(0xFFF95F62),
),
hintText: "john.doe@gmail.com",
hintStyle: TextStyle(
color: const Color(0xFF000000).withOpacity(0.6),
@@ -59,43 +116,54 @@ class LoginEmailBottomsheet extends StatelessWidget {
SizedBox(height: 38.h),
CustomFilledButton(
onTap: () {
Navigator.pop(context);
showModalBottomSheet(
context: context,
isScrollControlled: true,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(
top: Radius.circular(12.r),
if (emailValidate()) {
Navigator.pop(context);
showModalBottomSheet(
context: context,
backgroundColor: Colors.white,
isScrollControlled: true,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(
top: Radius.circular(12.r),
),
),
),
builder: (_) => VerifyOtpBottomsheet(),
);
builder: (_) => BlocProvider(
create: (rootcontext) => EmailVerifyBloc(),
child: VerifyOtpBottomsheet(),
),
);
}
},
label: "Continue",
width: double.infinity,
),
SizedBox(height: 20.h),
Text.rich(
TextSpan(
children: [
TextSpan(
text: "Already have an account?",
style: TextStyle(
color: Colors.black.withOpacity(0.6),
fontSize: 12.sp,
fontWeight: FontWeight.w400,
InkWell(
onTap: () {
Navigator.of(context).pushNamed(RouteConstants.createAcct);
},
child: Text.rich(
TextSpan(
children: [
TextSpan(
text: "Already have an account?",
style: TextStyle(
color: Colors.black.withOpacity(0.6),
fontSize: 12.sp,
fontWeight: FontWeight.w400,
),
),
),
TextSpan(
text: " Sign in",
style: TextStyle(
color: const Color(0xFFF95F62),
fontSize: 12.sp,
fontWeight: FontWeight.w600,
TextSpan(
text: " Sign in",
style: TextStyle(
color: const Color(0xFFF95F62),
fontSize: 12.sp,
fontWeight: FontWeight.w600,
),
),
),
],
],
),
),
),
SizedBox(height: 15.h),

View File

@@ -1,215 +0,0 @@
import 'package:citycards_customer/checkout/bloc/purchase_details_bloc.dart';
import 'package:citycards_customer/common_packages/custom_filled_button.dart';
import 'package:citycards_customer/common_packages/custom_text.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
class PurchaseDetailsBottomsheet extends StatelessWidget {
const PurchaseDetailsBottomsheet({super.key});
@override
Widget build(BuildContext context) {
return BlocProvider(
create: (_) => PurchaseDetailsBloc(),
child: AnimatedPadding(
duration: const Duration(milliseconds: 250),
curve: Curves.easeOut,
padding: EdgeInsets.only(
top: 24.h,
left: 20.w,
right: 20.w,
bottom: MediaQuery.of(context).viewInsets.bottom,
),
child: BlocBuilder<PurchaseDetailsBloc, PurchaseDetailsState>(
builder: (context, state) {
final selected = state.buyPassState;
return Column(
mainAxisSize: MainAxisSize.min,
children: [
// --- Handle Bar ---
Container(
height: 4.h,
width: 40.w,
decoration: BoxDecoration(
color: const Color(0xFF2D3134),
borderRadius: BorderRadius.circular(4.r),
),
),
SizedBox(height: 12.h),
CustomText(
text: "Purchase Details",
size: 18.sp,
weight: FontWeight.w600,
),
SizedBox(height: 22.h),
// --- Option 1: Buy for Myself ---
GestureDetector(
onTap: () {
context.read<PurchaseDetailsBloc>().add(
SetPurchaseDetailsEvent("myself"),
);
},
child: Container(
padding: EdgeInsets.all(6),
decoration: BoxDecoration(
border: Border.all(
color: selected == "myself"
? const Color(0xFFF95F62)
: Colors.transparent,
),
borderRadius: BorderRadius.circular(10.r),
),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Icon(
selected == "myself"
? Icons.radio_button_checked
: Icons.radio_button_off,
color: selected == "myself"
? const Color(0xFFF95F62)
: Color(0xFF2B2929).withOpacity(.6),
size: 24.sp,
),
SizedBox(width: 8.w),
CustomText(
text: "Buy Pass for Myself",
color: selected == "myself"
? const Color(0xFFF95F62)
: Color(0xFF2B2929).withOpacity(.6),
size: 16.sp,
weight: FontWeight.w500,
),
],
),
if (selected == "myself") ...[
SizedBox(height: 6.h),
CustomText(
text: "Frank Adam",
size: 14.sp,
weight: FontWeight.w400,
color: Colors.black.withOpacity(0.6),
),
SizedBox(height: 4.h),
CustomText(
text: "132 My Street, Kingston, NY 12401",
size: 12.sp,
color: const Color(
0xFF000000,
).withOpacity(0.4),
),
],
],
),
),
if (selected == "myself")
Container(
padding: EdgeInsets.symmetric(
horizontal: 6.w,
vertical: 6.h,
),
decoration: BoxDecoration(
color: Color(0xFFF95F62).withOpacity(0.12),
border: Border.all(
color: const Color(0xFFF95F62),
width: 1,
),
borderRadius: BorderRadius.circular(12.r),
),
child: CustomText(
text: "Edit Details",
size: 16.sp,
weight: FontWeight.w500,
color: const Color(0xFFF95F62),
),
),
],
),
),
),
SizedBox(height: 16.h),
// --- Option 2: Gift the Pass ---
GestureDetector(
onTap: () {
context.read<PurchaseDetailsBloc>().add(
SetPurchaseDetailsEvent("gift"),
);
},
child: Container(
padding: EdgeInsets.all(12.w),
decoration: BoxDecoration(
border: Border.all(
color: selected == "gift"
? const Color(0xFFF95F62)
: Colors.transparent,
),
borderRadius: BorderRadius.circular(12.r),
),
child: Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Icon(
selected == "gift"
? Icons.radio_button_checked
: Icons.radio_button_off,
color: selected == "gift"
? const Color(0xFFF95F62)
: Color(0xFF2F2A2A).withOpacity(0.4),
size: 24.sp,
),
SizedBox(width: 8.w),
CustomText(
text: "Gift the pass",
color: selected == "gift"
? const Color(0xFFF95F62)
: Color(0xFF2F2A2A).withOpacity(0.4),
size: 16.sp,
weight: FontWeight.w500,
),
],
),
SizedBox(height: 6.h),
if (selected == "gift")
CustomText(
text: "Gift the pass for someone else",
size: 12.sp,
color: const Color(0xFF000000).withOpacity(0.6),
),
],
),
),
),
),
SizedBox(height: 24.h),
// --- Proceed Button ---
CustomFilledButton(
onTap: () {},
label: "Proceed",
width: double.infinity,
),
SizedBox(height: 20.h),
],
);
},
),
),
);
}
}

View File

@@ -1,9 +1,14 @@
import 'package:citycards_customer/checkout/bloc/email_verify_bloc.dart';
import 'package:citycards_customer/checkout/repository/auth_local_repository.dart';
import 'package:citycards_customer/common_packages/custom_filled_button.dart';
import 'package:citycards_customer/common_packages/custom_text.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_otp_text_field/flutter_otp_text_field.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import '../../core/route_constants.dart';
class VerifyOtpBottomsheet extends StatelessWidget {
VerifyOtpBottomsheet({super.key});
@@ -23,85 +28,116 @@ class VerifyOtpBottomsheet extends StatelessWidget {
mainAxisSize: MainAxisSize.min, // shrink to fit content
children: [
Image.asset("assets/logo/logo_city_cards_orange.png", scale: 4),
SizedBox(height: 8.h),
CustomText(
text: "Verify your phone",
size: 18.sp,
weight: FontWeight.w500,
),
SizedBox(height: 42.h),
Text.rich(
TextSpan(
children: [
BlocBuilder<EmailVerifyBloc, EmailVerifyState>(
builder: (context, state) {
return Text.rich(
TextSpan(
text: "Enter the verification code sent to your email id",
style: TextStyle(
fontSize: 14.sp,
color: Colors.black.withOpacity(0.6),
),
children: [
TextSpan(
text:
"Enter the verification code sent to your email id: ",
style: TextStyle(
fontSize: 14.sp,
color: Colors.black.withOpacity(0.6),
),
),
TextSpan(
text: " ${state.email}",
style: TextStyle(
fontSize: 14.sp,
fontWeight: FontWeight.w500,
color: Colors.black,
),
),
],
),
TextSpan(
text: " frank7824@mail.com",
style: TextStyle(
fontSize: 14.sp,
fontWeight: FontWeight.w500,
color: Colors.black,
),
),
],
),
);
},
),
SizedBox(height: 15.h),
OtpTextField(
numberOfFields: 6,
borderWidth: 0.4.w,
fieldWidth: 48.w,
fieldHeight: 60.h,
borderRadius: BorderRadius.circular(8.r),
filled: true,
fillColor: const Color(0xFFFFF5F5),
borderColor: const Color(0xFFBB474A),
cursorColor: const Color(0xFFF95F62),
showFieldAsBox: true,
textStyle: TextStyle(
fontSize: 18.sp,
fontWeight: FontWeight.w500,
),
onCodeChanged: (code) {},
onSubmit: (code) {
debugPrint("OTP entered: $code");
BlocBuilder<EmailVerifyBloc, EmailVerifyState>(
builder: (context, state) {
final bloc = (context).read<EmailVerifyBloc>();
return OtpTextField(
numberOfFields: 6,
borderWidth: 0.4.w,
fieldWidth: 48.w,
fieldHeight: 60.h,
borderRadius: BorderRadius.circular(8.r),
filled: true,
fillColor: const Color(0xFFFFF5F5),
borderColor: const Color(0xFFBB474A),
cursorColor: const Color(0xFFF95F62),
showFieldAsBox: true,
textStyle: TextStyle(
fontSize: 18.sp,
fontWeight: FontWeight.w500,
),
onCodeChanged: (code) {},
onSubmit: (code) {
bloc.add(CheckOtpFilled(true));
debugPrint("OTP entered: $code");
},
);
},
),
SizedBox(height: 42.h),
CustomFilledButton(
onTap: () {},
label: "Continue",
width: double.infinity,
BlocBuilder<EmailVerifyBloc, EmailVerifyState>(
builder: (context, state) {
return CustomFilledButton(
onTap: () async {
if (state.isOtpFilled) {
Navigator.pop(context);
await LocalAuth().setloggedIn(true);
context.read<EmailVerifyBloc>().add(CheckIsLoggedIn());
}
},
label: "Continue",
width: double.infinity,
);
},
),
SizedBox(height: 20.h),
Text.rich(
TextSpan(
children: [
TextSpan(
text: "Already have an account?",
style: TextStyle(
color: Colors.black.withOpacity(0.6),
fontSize: 12.sp,
fontWeight: FontWeight.w400,
InkWell(
onTap: () {
Navigator.of(context).pushNamed(RouteConstants.createAcct);
},
child: Text.rich(
TextSpan(
children: [
TextSpan(
text: "Already have an account?",
style: TextStyle(
color: Colors.black.withOpacity(0.6),
fontSize: 12.sp,
fontWeight: FontWeight.w400,
),
),
),
TextSpan(
text: " Sign in",
style: TextStyle(
color: const Color(0xFFF95F62),
fontSize: 12.sp,
fontWeight: FontWeight.w600,
TextSpan(
text: " Sign in",
style: TextStyle(
color: const Color(0xFFF95F62),
fontSize: 12.sp,
fontWeight: FontWeight.w600,
),
),
),
],
],
),
),
),
SizedBox(height: 15.h),

View File

@@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import '../core/route_constants.dart';
import '../home/widgets/search_city_bottomsheet.dart';
class CommonAppBar extends StatelessWidget {
const CommonAppBar({
@@ -9,11 +10,13 @@ class CommonAppBar extends StatelessWidget {
required this.isWhiteLogo,
required this.isProfilePage,
this.showCart = true,
required this.showDivider
});
final bool isWhiteLogo;
final bool isProfilePage;
final bool? showCart;
final bool showDivider;
@override
Widget build(BuildContext context) {
@@ -22,11 +25,25 @@ class CommonAppBar extends StatelessWidget {
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Image.asset(
isWhiteLogo
? "assets/logo/logo_city_cards_white.png"
: "assets/logo/logo_city_cards.png",
scale: 4,
Row(
children: [
Image.asset(
isWhiteLogo
? "assets/logo/melbourne_white.png"
: "assets/logo/melbourne_logo.png",
scale: 4,
),
IconButton(onPressed: (){
showModalBottomSheet(
context: context,
isScrollControlled: true,
backgroundColor: Colors.transparent,
builder: (_) => const CitySelectionBottomSheet(),
);
}, icon: Icon(Icons.arrow_drop_down, color: isWhiteLogo ? Colors.white : Color(0xffF95F62), size: 30,))
],
),
Row(
children: [
@@ -61,16 +78,14 @@ class CommonAppBar extends StatelessWidget {
},
child: CircleAvatar(
backgroundColor: Color(0xffFFDFDF),
backgroundImage: AssetImage(
"assets/images/profile_img.png",
),
child: Image.asset( "assets/images/profile_default_img.png",),
),
),
],
),
],
),
if (!isWhiteLogo)
if (showDivider)
Column(
children: [
SizedBox(height: 12.h),

View File

@@ -87,6 +87,7 @@ class LanguageSelectionBottomsheet extends StatelessWidget {
showModalBottomSheet(
context: context,
backgroundColor: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(
top: Radius.circular(12.r),

View File

@@ -1,4 +1,5 @@
import 'package:citycards_customer/common_packages/app_bar.dart';
import 'package:citycards_customer/common_packages/back_widget.dart';
import 'package:flutter/material.dart';
import 'package:citycards_customer/common_packages/custom_text.dart';
import 'package:citycards_customer/common_packages/custom_textfield.dart';
@@ -24,30 +25,9 @@ class ContactUsPage extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Header bar
CommonAppBar(isWhiteLogo: false, isProfilePage: true),
SizedBox(height: 12.h),
Divider(height: 1.h, color: Color(0xFFD9D9D9)),
SizedBox(height: 22.h),
CommonAppBar(isWhiteLogo: false, isProfilePage: true, showDivider: true,),
// Back + Title
Row(
children: [
GestureDetector(
onTap: () {
Navigator.pop(context);
},
child: Icon(Icons.arrow_back, size: 24.sp),
),
SizedBox(width: 8.w),
Text(
"Contact Us",
style: TextStyle(
fontSize: 12.sp,
fontWeight: FontWeight.w500,
),
),
],
),
backWidget(context,"Contact Us", Colors.black),
SizedBox(height: 22.h),
CustomText(

View File

@@ -1,6 +1,6 @@
import 'package:citycards_customer/Profile/profile_page_view.dart';
import 'package:citycards_customer/add_details/add_details_view.dart';
import 'package:citycards_customer/attraction_details/attraction_details_view.dart';
import 'package:citycards_customer/attraction_details/view/attraction_details_view.dart';
import 'package:citycards_customer/buy_a_pass/view/buy_pass_view.dart';
import 'package:citycards_customer/checkout/view/checkout_view.dart';
import 'package:citycards_customer/common_bloc/language_selection_bloc.dart';
@@ -10,6 +10,7 @@ import 'package:citycards_customer/edit_profile/edit_profile_view.dart';
import 'package:citycards_customer/esim_offer/esim_offer_view.dart';
import 'package:citycards_customer/faq/faq_view.dart';
import 'package:citycards_customer/hotel_offer/hotel_offer_view.dart';
import 'package:citycards_customer/intro_screens/views/intro_screen_view.dart';
import 'package:citycards_customer/itinerary_creation/bloc/itinerary_detail_bloc.dart';
import 'package:citycards_customer/itinerary_creation/bloc/itinerary_steps_selection_bloc.dart';
import 'package:citycards_customer/itinerary_creation/views/itinerary_creation_start_view.dart';
@@ -17,10 +18,13 @@ import 'package:citycards_customer/itinerary_creation/views/itinerary_creation_v
import 'package:citycards_customer/itinerary_creation/views/magic_itinerary_empty_view.dart';
import 'package:citycards_customer/itinerary_creation/views/magic_itinerary_filled_view.dart';
import 'package:citycards_customer/offer_pass_detail/offer_pass_detail_view.dart';
import 'package:citycards_customer/postcard/views/postcard_creation_page_view.dart';
import 'package:citycards_customer/privacy/privacy_view.dart';
import 'package:citycards_customer/search_offers/bloc/search_offers_listing_bloc.dart';
import 'package:citycards_customer/search_offers/view/search_offers_with_listing.dart';
import 'package:citycards_customer/splash_screen/views/splash_screen.dart';
import 'package:citycards_customer/terms_and_condition/terms_and_condition_view.dart';
import 'package:citycards_customer/trail.dart';
import 'package:citycards_customer/your_itinerary/view/your_itinerary_view.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
@@ -28,10 +32,12 @@ import '../attractions/views/attractions_page_view.dart';
import '../cart/views/my_cart_view_page.dart';
import '../common_bloc/bottom_navigation_bloc.dart';
import '../home/views/home_page_view.dart';
import '../home/views/registered_user_home_page.dart';
import 'route_constants.dart';
class AppRouter {
Route onGenerateRoute(RouteSettings settings) {
print('Navigating to route: ${settings.name}');
switch (settings.name) {
case '/':
case RouteConstants.home:
@@ -43,6 +49,21 @@ class AppRouter {
);
},
);
case RouteConstants.splash:
print('✅ Splash route matched');
return MaterialPageRoute(
builder: (_) {
return SplashScreen();
},
);
case RouteConstants.intro:
return MaterialPageRoute(
builder: (_) {
return IntroScreensView();
},
);
case RouteConstants.attractionsPage:
final args = settings.arguments as String;
return MaterialPageRoute(builder: (_) => AttractionsPage(source: args));
@@ -185,19 +206,38 @@ class AppRouter {
);
case RouteConstants.magicItineraryEmptyScreen:
return MaterialPageRoute(builder: (_){
return MagicItineraryEmptyView();
});
return MaterialPageRoute(
builder: (_) {
return MagicItineraryEmptyView();
},
);
case RouteConstants.magicItineraryFilledScreen:
return MaterialPageRoute(builder: (_){
return MagicItineraryFilledView();
});
return MaterialPageRoute(
builder: (_) {
return MagicItineraryFilledView();
},
);
case RouteConstants.offerPassDetail:
return MaterialPageRoute(
builder: (_) {
return OfferPassDetailView();
},
);
case RouteConstants.registeredUserHome:
return MaterialPageRoute(
builder: (_) {
return RegisteredUserHomePage();
},
);
case RouteConstants.postCardCreationPage:
return MaterialPageRoute(builder: (_){
return OfferPassDetailView();
return PostcardCreationPage();
});
default:
return MaterialPageRoute(
builder: (_) =>

View File

@@ -1,24 +1,36 @@
import 'package:citycards_customer/core/route_constants.dart';
import 'package:citycards_customer/home/views/registered_user_home_page.dart';
import 'package:citycards_customer/my_pass/blocs/my_pass_bloc.dart';
import 'package:citycards_customer/postcard/views/add_filter_step_page_view.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import '../attraction_details/attraction_details_view.dart';
import '../attraction_details/view/attraction_details_view.dart';
import '../attractions/views/attractions_page_view.dart';
import '../buy_a_pass/view/buy_pass_view.dart';
import '../checkout/view/checkout_view.dart';
import '../create_account/create_account_view.dart';
import '../intro_screens/views/intro_screen_view.dart';
import '../itinerary_creation/bloc/itinerary_detail_bloc.dart';
import '../itinerary_creation/bloc/itinerary_steps_selection_bloc.dart';
import '../itinerary_creation/views/itinerary_creation_view.dart';
import '../itinerary_creation/views/magic_itinerary_filled_view.dart';
import '../my_pass/views/booking_page_view.dart';
import '../my_pass/views/booking_successful_page_view.dart';
import '../my_pass/views/qr_pass_page_view.dart';
import '../offer_pass_detail/offer_pass_detail_view.dart';
import '../postcard/blocs/postcard_creation_bloc.dart';
import '../postcard/views/postcard_creation_page_view.dart';
import '../search_offers/bloc/search_offers_listing_bloc.dart';
import '../search_offers/view/search_offers_with_listing.dart';
import '../your_itinerary/view/your_itinerary_view.dart';
Widget buildOffstageNavigator(
int index,
int currentIndex,
Widget child,
Key key,
) {
int index,
int currentIndex,
Widget child,
Key key,
) {
return Offstage(
offstage: currentIndex != index,
child: Navigator(
@@ -28,21 +40,46 @@ Widget buildOffstageNavigator(
case '/':
return MaterialPageRoute(builder: (_) => child);
// 🔹 Attractions Page
case RouteConstants.intro:
return MaterialPageRoute(builder: (_){
return IntroScreensView();
});
// 🔹 Attractions PageF
case RouteConstants.attractionsPage:
final args = settings.arguments as String;
return MaterialPageRoute(
builder: (_) => AttractionsPage(source: args,),
builder: (_) => AttractionsPage(source: args),
);
case RouteConstants.attractionDetails:
return MaterialPageRoute(builder: (_) {
return AttractionDetailsView();
});
return MaterialPageRoute(
builder: (_) {
return AttractionDetailsView();
},
);
case RouteConstants.makeBooking:
return MaterialPageRoute(builder: (_) {
return MakeBookingView(title: 'asffdsf', description: 'afdsfadsfasdfads',);
case RouteConstants.makeBooking:
return MaterialPageRoute(
builder: (_) {
return MakeBookingView(
title: 'Koh Rong Samloem',
description:
'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Convallis condimentum morbi non egestas enim amet sagittis.ß',
);
},
);
case RouteConstants.bookingSuccessful:
return MaterialPageRoute(
builder: (_) {
return BookingSuccessfulPageView();
},
);
case RouteConstants.offerPassDetail:
return MaterialPageRoute(builder: (_){
return OfferPassDetailView();
});
case RouteConstants.searchOffer:
@@ -55,8 +92,8 @@ Widget buildOffstageNavigator(
},
);
// 🔹 Upload Photo Page (start of postcard creation flow)
case RouteConstants.uploadPhotoPage:
// 🔹 Upload Photo Page (start of postcard creation flow)
case RouteConstants.postCardCreationPage:
return MaterialPageRoute(
builder: (_) => BlocProvider(
create: (_) => PostcardCreationBloc(),
@@ -64,11 +101,13 @@ Widget buildOffstageNavigator(
),
);
// 🔹 Add Filter Page (uses same bloc instance)
// 🔹 Add Filter Page (uses same bloc instance)
case RouteConstants.addFilterPage:
return MaterialPageRoute(
builder: (context) {
final previousBloc = BlocProvider.of<PostcardCreationBloc>(context);
final previousBloc = BlocProvider.of<PostcardCreationBloc>(
context,
);
return BlocProvider.value(
value: previousBloc,
child: const AddFilterStepPageView(),
@@ -76,7 +115,6 @@ Widget buildOffstageNavigator(
},
);
case RouteConstants.qrPage:
return MaterialPageRoute(
builder: (context) {
@@ -88,11 +126,68 @@ Widget buildOffstageNavigator(
},
);
case RouteConstants.itineraryCreation:
return MaterialPageRoute(
builder: (_) {
return MultiBlocProvider(
providers: [
BlocProvider<ItineraryStepNavigationBloc>(
create: (_) => ItineraryStepNavigationBloc(),
),
BlocProvider<AddItineraryDetailBloc>(
create: (_) => AddItineraryDetailBloc(),
),
],
child: const ItineraryCreationPage(),
);
},
);
case RouteConstants.yourItinerary:
return MaterialPageRoute(
builder: (_) {
return YourItineraryView();
},
);
case RouteConstants.magicItineraryFilledScreen:
return MaterialPageRoute(builder: (_){
return MagicItineraryFilledView();
});
case RouteConstants.checkout:
return MaterialPageRoute(
builder: (_) {
return CheckoutView();
},
);
case RouteConstants.buyPass:
return MaterialPageRoute(
builder: (_) {
return BuyPassView();
},
);
case RouteConstants.createAcct:
return MaterialPageRoute(
builder: (_) {
return CreateAccountView();
},
);
case RouteConstants.registeredUserHome:
return MaterialPageRoute(
builder: (_) {
return RegisteredUserHomePage();
},
);
default:
return MaterialPageRoute(
builder: (_) => const Scaffold(
body: Center(child: Text('Page not found')),
),
builder: (_) =>
const Scaffold(body: Center(child: Text('Page not found'))),
);
}
},

View File

@@ -1,7 +1,13 @@
class RouteConstants {
static const String intro = '/intro';
static const String splash = '/splash';
/****************************** HOME SECTION ************************************/
static const String home = '/home';
static const String registeredUserHome = '/registeredUserHome';
static const String attractionsPage = "/attractions";
static const String postCardPage = "/postcards";
static const String uploadPhotoPage = "/uploadPhoto";
@@ -49,4 +55,6 @@ class RouteConstants {
static const String qrPage = '/qrPage';
static const String makeBooking = '/makeBooking';
static const String bookingSuccessful = '/bookingSuccessful';
static const String postCardCreationPage = '/postCardCreationPage';
}

View File

@@ -29,6 +29,7 @@ class CreateAccountView extends StatelessWidget {
isWhiteLogo: false,
isProfilePage: false,
showCart: false,
showDivider: true,
),
Row(
children: [

View File

@@ -1,4 +1,5 @@
import 'package:citycards_customer/common_packages/app_bar.dart';
import 'package:citycards_customer/common_packages/back_widget.dart';
import 'package:citycards_customer/common_packages/custom_textfield.dart';
import 'package:flutter/material.dart';
import 'package:citycards_customer/common_packages/custom_text.dart';
@@ -24,30 +25,10 @@ class EditProfilePage extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.center,
children: [
// Header
CommonAppBar(isWhiteLogo: false, isProfilePage: true),
SizedBox(height: 12.h),
Divider(height: 1.h, color: Color(0xFFD9D9D9)),
SizedBox(height: 22.h),
CommonAppBar(isWhiteLogo: false, isProfilePage: true,showDivider: true,),
// Back + title
Row(
children: [
GestureDetector(
onTap: () {
Navigator.pop(context);
},
child: Icon(Icons.arrow_back, size: 24.sp),
),
SizedBox(width: 8.w),
Text(
"Edit Profile",
style: TextStyle(
fontSize: 12.sp,
fontWeight: FontWeight.w500,
),
),
],
),
backWidget(context,"Edit Profile", Colors.black),
SizedBox(height: 33.h),
// Profile Image

View File

@@ -18,7 +18,7 @@ class EsimOfferPage extends StatelessWidget {
Container(
color: Colors.white,
padding: EdgeInsets.symmetric(horizontal: 20, vertical: 10),
child: CommonAppBar(isWhiteLogo: false, isProfilePage: false),
child: CommonAppBar(isWhiteLogo: false, isProfilePage: false,showDivider: true,),
),
/************************* Top Banner ***********************/

View File

@@ -1,4 +1,5 @@
import 'package:citycards_customer/common_packages/app_bar.dart';
import 'package:citycards_customer/common_packages/back_widget.dart';
import 'package:citycards_customer/common_packages/custom_expansion_tile.dart';
import 'package:citycards_customer/common_packages/custom_text.dart';
import 'package:flutter/material.dart';
@@ -18,34 +19,8 @@ class FaqPage extends StatelessWidget {
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
CommonAppBar(isWhiteLogo: false, isProfilePage: true),
SizedBox(
height: 12.h,
),
Divider(
height: 1.h,
color: Color(0xFFD9D9D9),
),
SizedBox(height: 22.h),
// Back + Title
Row(
children: [
GestureDetector(
onTap: (){
Navigator.pop(context);
},
child: Icon(Icons.arrow_back, size: 24.sp)),
SizedBox(width: 8.w),
Text(
"FAQ",
style: TextStyle(
fontSize: 12.sp,
fontWeight: FontWeight.w500,
),
),
],
),
CommonAppBar(isWhiteLogo: false, isProfilePage: true, showDivider: true,),
backWidget(context,"FAQ", Colors.black),
SizedBox(height: 34.h),
FAQSection(title: "🧭 General FAQs", faqs: generalFAQs),

View File

@@ -0,0 +1,42 @@
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:shared_preferences/shared_preferences.dart';
/// --- Events ---
abstract class AppStartEvent {}
class CheckFirstTimeUser extends AppStartEvent {}
class MarkUserAsRegistered extends AppStartEvent {}
/// --- States ---
abstract class AppStartState {}
class AppStartLoading extends AppStartState {}
class AppStartFirstTime extends AppStartState {}
class AppStartRegistered extends AppStartState {}
/// --- Bloc ---
class AppStartBloc extends Bloc<AppStartEvent, AppStartState> {
AppStartBloc() : super(AppStartLoading()) {
on<CheckFirstTimeUser>(_onCheckFirstTimeUser);
on<MarkUserAsRegistered>(_onMarkUserAsRegistered);
}
Future<void> _onCheckFirstTimeUser(
CheckFirstTimeUser event, Emitter<AppStartState> emit) async {
emit(AppStartLoading());
final prefs = await SharedPreferences.getInstance();
final isFirstTime = prefs.getBool('isFirstTimeUser') ?? true;
if (isFirstTime) {
emit(AppStartFirstTime());
} else {
emit(AppStartRegistered());
}
}
Future<void> _onMarkUserAsRegistered(
MarkUserAsRegistered event, Emitter<AppStartState> emit) async {
final prefs = await SharedPreferences.getInstance();
await prefs.setBool('isFirstTimeUser', false);
emit(AppStartRegistered());
}
}

View File

@@ -0,0 +1,54 @@
import 'package:flutter_bloc/flutter_bloc.dart';
abstract class LoadCityEvent {}
class LoadAllCity extends LoadCityEvent {}
class SearchCity extends LoadCityEvent {
final String query;
SearchCity(this.query);
}
// ----- State -----
class CityState {
final List<Map<String, String>> offers;
const CityState(this.offers);
}
// ----- Bloc -----
class SearchCityBloc extends Bloc<LoadCityEvent, CityState> {
SearchCityBloc() : super(const CityState([])) {
on<LoadAllCity>(_onLoadCity);
on<SearchCity>(_onSearchCity);
}
final List<Map<String, String>> _allOffers = [
{"image": "assets/images/aa1.png", "title": "Sydney"},
{"image": "assets/images/aa2.png", "title": "New York"},
{"image": "assets/images/aa3.png", "title": "Abu Dhabi"},
{"image": "assets/images/aa4.png", "title": "Dubai"},
{
"image": "assets/images/card_banner.png",
"title": "Tokyo",
},
{"image": "assets/images/city_germany.jpg", "title": "Ontario"},
{"image": "assets/images/aa2.png", "title": "Mumbai"},
{"image": "assets/images/aa3.png", "title": "Louisiana"},
];
void _onLoadCity(event, emit) {
emit(CityState(_allOffers));
}
void _onSearchCity(event, emit) {
final filtered = _allOffers
.where(
(offer) =>
offer["title"]!.toLowerCase().contains(event.query.toLowerCase()),
)
.toList();
emit(CityState(filtered));
}
}

View File

@@ -5,7 +5,8 @@ import '../../common_packages/app_bar.dart';
import '../widgets/explore_cities_card.dart';
class FirstTimeUserHomePage extends StatefulWidget {
const FirstTimeUserHomePage({super.key});
final VoidCallback onContinue;
const FirstTimeUserHomePage({super.key, required this.onContinue});
@override
State<FirstTimeUserHomePage> createState() => _FirstTimeUserHomePageState();
@@ -92,7 +93,7 @@ class _FirstTimeUserHomePageState extends State<FirstTimeUserHomePage> {
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
CommonAppBar(isWhiteLogo: true, isProfilePage: false),
CommonAppBar(isWhiteLogo: true, isProfilePage: false, showDivider: false),
SizedBox(height: 140.h),
Text(
"CityCards.\nSee More,\nSpend Less.",
@@ -120,7 +121,7 @@ class _FirstTimeUserHomePageState extends State<FirstTimeUserHomePage> {
borderRadius: BorderRadius.circular(25.r),
),
),
onPressed: () {},
onPressed: widget.onContinue,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [

Some files were not shown because too many files have changed in this diff Show More