Compare commits
26 Commits
c771ce335c
...
vinayak
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7249870aa9 | ||
|
|
7dbeef2f80 | ||
|
|
1ca940e5cf | ||
|
|
b54739953a | ||
|
|
323d730e2d | ||
|
|
f3c98df517 | ||
|
|
0ef09633e0 | ||
| 72aae68e2d | |||
|
|
e2f9217d57 | ||
|
|
7d4c015134 | ||
|
|
061f196ece | ||
| 76e4fff06c | |||
|
|
6a68a06b78 | ||
| 9121cf1b1b | |||
|
|
a2ff4253ed | ||
| f43c2cc9f6 | |||
|
|
d73faf7506 | ||
|
|
560a10f4ea | ||
|
|
5c11344c17 | ||
| 9dd76e1dac | |||
| ede130224e | |||
| abca972ba5 | |||
| 92ce97b553 | |||
| 85c17595f2 | |||
| 548c4e2638 | |||
| 5c4ffb1686 |
@@ -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
|
||||
|
||||
@@ -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>
|
||||
|
||||
BIN
android/app/src/main/res/drawable-v21/background.png
Normal file
|
After Width: | Height: | Size: 69 B |
@@ -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>
|
||||
|
||||
BIN
android/app/src/main/res/drawable/background.png
Normal file
|
After Width: | Height: | Size: 69 B |
@@ -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>
|
||||
|
||||
BIN
android/app/src/main/res/mipmap-hdpi/launcher_icon.png
Normal file
|
After Width: | Height: | Size: 4.8 KiB |
BIN
android/app/src/main/res/mipmap-mdpi/launcher_icon.png
Normal file
|
After Width: | Height: | Size: 3.0 KiB |
BIN
android/app/src/main/res/mipmap-xhdpi/launcher_icon.png
Normal file
|
After Width: | Height: | Size: 6.2 KiB |
BIN
android/app/src/main/res/mipmap-xxhdpi/launcher_icon.png
Normal file
|
After Width: | Height: | Size: 7.7 KiB |
BIN
android/app/src/main/res/mipmap-xxxhdpi/launcher_icon.png
Normal file
|
After Width: | Height: | Size: 8.4 KiB |
20
android/app/src/main/res/values-night-v31/styles.xml
Normal 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>
|
||||
@@ -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
|
||||
|
||||
20
android/app/src/main/res/values-v31/styles.xml
Normal 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>
|
||||
@@ -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
|
||||
|
||||
BIN
assets/gif/itinenary_animation_for_citycards.mp4
Normal file
BIN
assets/images/booking_successful.png
Normal file
|
After Width: | Height: | Size: 22 KiB |
BIN
assets/images/empty_buy_ pass.png
Normal file
|
After Width: | Height: | Size: 115 KiB |
BIN
assets/images/postcard_bg.png
Normal file
|
After Width: | Height: | Size: 1.1 MiB |
BIN
assets/images/profile_default_img.png
Normal file
|
After Width: | Height: | Size: 2.0 KiB |
BIN
assets/images/qr_image.png
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
assets/images/splash1.png
Normal file
|
After Width: | Height: | Size: 8.6 MiB |
BIN
assets/images/splash2.png
Normal file
|
After Width: | Height: | Size: 1.9 MiB |
BIN
assets/images/splash3.jpg
Normal file
|
After Width: | Height: | Size: 366 KiB |
1
assets/intro/anim.json
Normal file
1
assets/intro/animation.json
Normal file
1
assets/intro/animm.json
Normal file
BIN
assets/logo/logo_resized.png
Normal file
|
After Width: | Height: | Size: 1.3 MiB |
BIN
assets/logo/logo_white_resized.png
Normal file
|
After Width: | Height: | Size: 93 KiB |
BIN
assets/logo/logoframe.png
Normal file
|
After Width: | Height: | Size: 30 KiB |
BIN
assets/logo/melbourne_logo.png
Normal file
|
After Width: | Height: | Size: 9.3 KiB |
BIN
assets/logo/melbourne_white.png
Normal file
|
After Width: | Height: | Size: 6.9 KiB |
BIN
assets/logo/splash.png
Normal file
|
After Width: | Height: | Size: 28 KiB |
19
flutter_launcher_icons.yaml
Normal 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"
|
||||
@@ -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
@@ -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
|
||||
@@ -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;
|
||||
|
||||
3
ios/Runner.xcworkspace/contents.xcworkspacedata
generated
@@ -4,4 +4,7 @@
|
||||
<FileRef
|
||||
location = "group:Runner.xcodeproj">
|
||||
</FileRef>
|
||||
<FileRef
|
||||
location = "group:Pods/Pods.xcodeproj">
|
||||
</FileRef>
|
||||
</Workspace>
|
||||
|
||||
@@ -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"}}
|
||||
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 117 KiB |
|
Before Width: | Height: | Size: 295 B After Width: | Height: | Size: 678 B |
|
Before Width: | Height: | Size: 406 B After Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 450 B After Width: | Height: | Size: 2.8 KiB |
|
Before Width: | Height: | Size: 282 B After Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 462 B After Width: | Height: | Size: 2.7 KiB |
|
Before Width: | Height: | Size: 704 B After Width: | Height: | Size: 4.3 KiB |
|
Before Width: | Height: | Size: 406 B After Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 586 B After Width: | Height: | Size: 4.0 KiB |
|
Before Width: | Height: | Size: 862 B After Width: | Height: | Size: 5.8 KiB |
|
After Width: | Height: | Size: 2.2 KiB |
|
After Width: | Height: | Size: 4.9 KiB |
|
After Width: | Height: | Size: 2.7 KiB |
|
After Width: | Height: | Size: 5.7 KiB |
|
Before Width: | Height: | Size: 862 B After Width: | Height: | Size: 5.8 KiB |
|
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 7.3 KiB |
|
After Width: | Height: | Size: 3.5 KiB |
|
After Width: | Height: | Size: 6.5 KiB |
|
Before Width: | Height: | Size: 762 B After Width: | Height: | Size: 3.7 KiB |
|
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 6.8 KiB |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 7.1 KiB |
21
ios/Runner/Assets.xcassets/LaunchBackground.imageset/Contents.json
vendored
Normal 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
|
||||
}
|
||||
}
|
||||
BIN
ios/Runner/Assets.xcassets/LaunchBackground.imageset/background.png
vendored
Normal file
|
After Width: | Height: | Size: 69 B |
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
Before Width: | Height: | Size: 68 B After Width: | Height: | Size: 69 B |
|
Before Width: | Height: | Size: 68 B After Width: | Height: | Size: 69 B |
|
Before Width: | Height: | Size: 68 B After Width: | Height: | Size: 69 B |
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -28,6 +28,7 @@ class AddDetailsView extends StatelessWidget {
|
||||
isWhiteLogo: false,
|
||||
isProfilePage: false,
|
||||
showCart: false,
|
||||
showDivider: true,
|
||||
),
|
||||
Row(
|
||||
children: [
|
||||
|
||||
@@ -1,482 +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';
|
||||
|
||||
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),
|
||||
|
||||
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)),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
15
lib/attraction_details/bloc/attraction_details_bloc.dart
Normal 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));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
import 'package:equatable/equatable.dart';
|
||||
|
||||
abstract class AttractionDetailsEvent {
|
||||
}
|
||||
|
||||
class SetFlowFromPass extends AttractionDetailsEvent{
|
||||
final bool fromByPass;
|
||||
SetFlowFromPass(this.fromByPass);
|
||||
}
|
||||
14
lib/attraction_details/bloc/attraction_details_state.dart
Normal 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];
|
||||
}
|
||||
555
lib/attraction_details/view/attraction_details_view.dart
Normal 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)),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -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')),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -14,6 +14,11 @@ class AttractionsBloc extends Bloc<AttractionsEvent, AttractionsState> {
|
||||
emit(AttractionsLoaded(attractions));
|
||||
});
|
||||
|
||||
on<LoadMyPassAttraction>((event, emit) {
|
||||
final attractions = repository.fetchMyPassAttraction();
|
||||
emit(AttractionsLoaded(attractions));
|
||||
});
|
||||
|
||||
on<SearchAttractions>((event, emit) {
|
||||
if (state is AttractionsLoaded) {
|
||||
final currentState = state as AttractionsLoaded;
|
||||
|
||||
@@ -4,6 +4,8 @@ abstract class AttractionsEvent {}
|
||||
|
||||
class LoadAttractions extends AttractionsEvent {}
|
||||
|
||||
class LoadMyPassAttraction extends AttractionsEvent {}
|
||||
|
||||
class SearchAttractions extends AttractionsEvent {
|
||||
final String query;
|
||||
SearchAttractions(this.query);
|
||||
|
||||
@@ -4,6 +4,8 @@ class Attraction {
|
||||
final String price;
|
||||
final String image;
|
||||
final List<String> tags;
|
||||
final bool isBookingRequired;
|
||||
final String description;
|
||||
|
||||
Attraction({
|
||||
required this.title,
|
||||
@@ -11,5 +13,7 @@ class Attraction {
|
||||
required this.price,
|
||||
required this.image,
|
||||
required this.tags,
|
||||
required this.isBookingRequired,
|
||||
required this.description
|
||||
});
|
||||
}
|
||||
|
||||
@@ -9,6 +9,9 @@ class AttractionsRepository {
|
||||
price: "\$25",
|
||||
image: "assets/dummy/dummy_1.jpg",
|
||||
tags: ["Unlimited Card", "Flexi Card"],
|
||||
isBookingRequired: false,
|
||||
description:
|
||||
"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... ",
|
||||
),
|
||||
Attraction(
|
||||
title: "Siem Reap",
|
||||
@@ -16,6 +19,9 @@ class AttractionsRepository {
|
||||
price: "\$25",
|
||||
image: "assets/dummy/dummy_2.jpg",
|
||||
tags: ["Unlimited Card"],
|
||||
isBookingRequired: false,
|
||||
description:
|
||||
"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... ",
|
||||
),
|
||||
Attraction(
|
||||
title: "Dart Palace",
|
||||
@@ -23,6 +29,9 @@ class AttractionsRepository {
|
||||
price: "\$25",
|
||||
image: "assets/dummy/dummy_3.jpg",
|
||||
tags: ["Unlimited Card", "Flexi Card"],
|
||||
isBookingRequired: false,
|
||||
description:
|
||||
"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... ",
|
||||
),
|
||||
Attraction(
|
||||
title: "Koh Rong Samloem",
|
||||
@@ -30,6 +39,9 @@ class AttractionsRepository {
|
||||
price: "\$25",
|
||||
image: "assets/dummy/dummy_4.jpg",
|
||||
tags: ["Flexi Card"],
|
||||
isBookingRequired: false,
|
||||
description:
|
||||
"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... ",
|
||||
),
|
||||
Attraction(
|
||||
title: "Dart Palace",
|
||||
@@ -37,6 +49,64 @@ class AttractionsRepository {
|
||||
price: "\$25",
|
||||
image: "assets/dummy/dummy_5.jpg",
|
||||
tags: ["Unlimited Card", "Flexi Card"],
|
||||
isBookingRequired: false,
|
||||
description:
|
||||
"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... ",
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
List<Attraction> fetchMyPassAttraction() {
|
||||
return [
|
||||
Attraction(
|
||||
title: "Koh Rong Samloem",
|
||||
location: "Krong Siem Reap",
|
||||
price: "\$25",
|
||||
image: "assets/dummy/dummy_1.jpg",
|
||||
tags: ["Unlimited Card", "Flexi Card"],
|
||||
isBookingRequired: true,
|
||||
description:
|
||||
"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... ",
|
||||
),
|
||||
Attraction(
|
||||
title: "Siem Reap",
|
||||
location: "Krong Siem Reap",
|
||||
price: "\$25",
|
||||
image: "assets/dummy/dummy_2.jpg",
|
||||
tags: ["Unlimited Card"],
|
||||
isBookingRequired: true,
|
||||
description:
|
||||
"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... ",
|
||||
),
|
||||
Attraction(
|
||||
title: "Dart Palace",
|
||||
location: "Krong Siem Reap",
|
||||
price: "\$25",
|
||||
image: "assets/dummy/dummy_3.jpg",
|
||||
tags: ["Unlimited Card", "Flexi Card"],
|
||||
isBookingRequired: true,
|
||||
description:
|
||||
"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... ",
|
||||
),
|
||||
Attraction(
|
||||
title: "Koh Rong Samloem",
|
||||
location: "Krong Siem Reap",
|
||||
price: "\$25",
|
||||
image: "assets/dummy/dummy_4.jpg",
|
||||
tags: ["Flexi Card"],
|
||||
isBookingRequired: true,
|
||||
description:
|
||||
"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... ",
|
||||
),
|
||||
Attraction(
|
||||
title: "Dart Palace",
|
||||
location: "Krong Siem Reap",
|
||||
price: "\$25",
|
||||
image: "assets/dummy/dummy_5.jpg",
|
||||
tags: ["Unlimited Card", "Flexi Card"],
|
||||
isBookingRequired: true,
|
||||
description:
|
||||
"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... ",
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
@@ -1,7 +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';
|
||||
@@ -9,12 +13,32 @@ import '../widget/attraction_card.dart';
|
||||
import '../widget/filter_chip.dart';
|
||||
|
||||
class AttractionsPage extends StatelessWidget {
|
||||
const AttractionsPage({super.key});
|
||||
final String source;
|
||||
const AttractionsPage({super.key, required this.source});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return BlocProvider(
|
||||
create: (_) => AttractionsBloc(AttractionsRepository())..add(LoadAttractions()),
|
||||
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());
|
||||
}
|
||||
|
||||
return bloc;
|
||||
},
|
||||
),
|
||||
BlocProvider(create: (_) => AttractionDetailsBloc(),
|
||||
|
||||
)
|
||||
],
|
||||
child: BlocBuilder<AttractionsBloc, AttractionsState>(
|
||||
builder: (context, state) {
|
||||
final bloc = context.read<AttractionsBloc>();
|
||||
@@ -28,27 +52,8 @@ class AttractionsPage extends StatelessWidget {
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
// App bar
|
||||
CommonAppBar(isWhiteLogo: false, isProfilePage: false),
|
||||
SizedBox(height: 22.h),
|
||||
|
||||
// Back row
|
||||
Row(
|
||||
children: [
|
||||
GestureDetector(
|
||||
onTap: () => Navigator.pop(context),
|
||||
child: Icon(Icons.arrow_back, size: 24.sp),
|
||||
),
|
||||
SizedBox(width: 8.w),
|
||||
Text(
|
||||
"Your Attraction",
|
||||
style: TextStyle(
|
||||
fontSize: 14.sp,
|
||||
fontWeight: FontWeight.w400,
|
||||
color: Colors.black87,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
CommonAppBar(isWhiteLogo: false, isProfilePage: false, showDivider: true),
|
||||
backWidget(context, "Your Attraction", Colors.black),
|
||||
const SizedBox(height: 20),
|
||||
|
||||
// 🔍 Search field
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:google_fonts/google_fonts.dart';
|
||||
import '../../core/route_constants.dart';
|
||||
import '../models/attraction_model.dart';
|
||||
|
||||
class AttractionCard extends StatelessWidget {
|
||||
@@ -8,91 +9,138 @@ class AttractionCard extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
margin: const EdgeInsets.symmetric(vertical: 8, horizontal: 8),
|
||||
padding: const EdgeInsets.all(12),
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(color: const Color(0xffFDCDCE)),
|
||||
borderRadius: BorderRadius.circular(15),
|
||||
color: Color(0xffFFF5F5),
|
||||
),
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
ClipRRect(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
child: Image.asset(
|
||||
attraction.image,
|
||||
height: 94,
|
||||
width: 94,
|
||||
fit: BoxFit.cover,
|
||||
return InkWell(
|
||||
onTap: (){
|
||||
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),
|
||||
padding: const EdgeInsets.all(12),
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(color: const Color(0xffFDCDCE)),
|
||||
borderRadius: BorderRadius.circular(15),
|
||||
color: Color(0xffFFF5F5),
|
||||
),
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
ClipRRect(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
child: Image.asset(
|
||||
attraction.image,
|
||||
height: 94,
|
||||
width: 94,
|
||||
fit: BoxFit.cover,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 10),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(attraction.title,
|
||||
style: TextStyle(
|
||||
fontSize: 16, fontWeight: FontWeight.w500)),
|
||||
const SizedBox(height: 6),
|
||||
Text(attraction.location,
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 12, fontWeight: FontWeight.w400, color: Color(0xff464646))),
|
||||
const SizedBox(height: 6),
|
||||
Text.rich(
|
||||
TextSpan(
|
||||
children: [
|
||||
TextSpan(
|
||||
text: "from ${attraction.price}",
|
||||
style: const TextStyle(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Colors.black,
|
||||
),
|
||||
),
|
||||
const TextSpan(
|
||||
text: "/person",
|
||||
style:
|
||||
TextStyle(fontSize: 10, color: Colors.black, fontWeight: FontWeight.w400,),
|
||||
),
|
||||
],
|
||||
const SizedBox(width: 10),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
attraction.title,
|
||||
style: TextStyle(fontSize: 16, fontWeight: FontWeight.w500),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 6),
|
||||
Wrap(
|
||||
spacing: 6,
|
||||
children: attraction.tags
|
||||
.map((tag) => Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 4),
|
||||
decoration: BoxDecoration(
|
||||
color: tag == "Flexi Card"
|
||||
? const Color(0xffF95FAF).withOpacity(0.1)
|
||||
: const Color(0xffF95F62).withOpacity(0.1),
|
||||
border: Border.all(
|
||||
color: tag == "Flexi Card"
|
||||
? const Color(0xffF95FAF)
|
||||
: const Color(0xffF95F62),
|
||||
),
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
const SizedBox(height: 6),
|
||||
Text(
|
||||
attraction.location,
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w400,
|
||||
color: Color(0xff464646),
|
||||
),
|
||||
child: Text(
|
||||
tag,
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 11,
|
||||
color: Color(0xff1A1A1A),
|
||||
fontWeight: FontWeight.w400,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 6),
|
||||
Text.rich(
|
||||
TextSpan(
|
||||
children: [
|
||||
TextSpan(
|
||||
text: "from ${attraction.price}",
|
||||
style: const TextStyle(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Colors.black,
|
||||
),
|
||||
),
|
||||
const TextSpan(
|
||||
text: "/person",
|
||||
style: TextStyle(
|
||||
fontSize: 10,
|
||||
color: Colors.black,
|
||||
fontWeight: FontWeight.w400,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
))
|
||||
.toList(),
|
||||
)
|
||||
,
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 6),
|
||||
attraction.isBookingRequired == false
|
||||
? Wrap(
|
||||
spacing: 6,
|
||||
children: attraction.tags
|
||||
.map(
|
||||
(tag) => Container(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 10,
|
||||
vertical: 4,
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
color: tag == "Flexi Card"
|
||||
? const Color(0xffF95FAF).withOpacity(0.1)
|
||||
: const Color(
|
||||
0xffF95F62,
|
||||
).withOpacity(0.1),
|
||||
border: Border.all(
|
||||
color: tag == "Flexi Card"
|
||||
? const Color(0xffF95FAF)
|
||||
: const Color(0xffF95F62),
|
||||
),
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
),
|
||||
child: Text(
|
||||
tag,
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 11,
|
||||
color: Color(0xff1A1A1A),
|
||||
fontWeight: FontWeight.w400,
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
)
|
||||
: Container(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 10,
|
||||
vertical: 4,
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
color: Color(0xffC1D2F8),
|
||||
border: Border.all(
|
||||
color: Color(0xff2563EB),
|
||||
),
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
),
|
||||
child: Text(
|
||||
"Booking Required",
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 11,
|
||||
color: Color(0xff1A1A1A),
|
||||
fontWeight: FontWeight.w400,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -126,7 +126,6 @@ class _PaymentCardState extends State<PaymentCard> {
|
||||
onTap: () {
|
||||
Navigator.of(
|
||||
context,
|
||||
rootNavigator: true,
|
||||
).pushNamed(RouteConstants.checkout);
|
||||
},
|
||||
label: "Proceed to Pay",
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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;
|
||||
|
||||
63
lib/checkout/bloc/email_verify_bloc.dart
Normal 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));
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
15
lib/checkout/repository/auth_local_repository.dart
Normal 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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
@@ -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),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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),
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -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),
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -87,6 +87,7 @@ class LanguageSelectionBottomsheet extends StatelessWidget {
|
||||
|
||||
showModalBottomSheet(
|
||||
context: context,
|
||||
backgroundColor: Colors.white,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.vertical(
|
||||
top: Radius.circular(12.r),
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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,8 +49,24 @@ 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:
|
||||
return MaterialPageRoute(builder: (_) => const AttractionsPage());
|
||||
final args = settings.arguments as String;
|
||||
return MaterialPageRoute(builder: (_) => AttractionsPage(source: args));
|
||||
case RouteConstants.profile:
|
||||
return MaterialPageRoute(
|
||||
builder: (_) {
|
||||
@@ -184,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: (_) =>
|
||||
|
||||
@@ -1,18 +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/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(
|
||||
@@ -22,14 +40,60 @@ 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: (_) => const AttractionsPage(),
|
||||
builder: (_) => AttractionsPage(source: args),
|
||||
);
|
||||
|
||||
// 🔹 Upload Photo Page (start of postcard creation flow)
|
||||
case RouteConstants.uploadPhotoPage:
|
||||
case RouteConstants.attractionDetails:
|
||||
return MaterialPageRoute(
|
||||
builder: (_) {
|
||||
return AttractionDetailsView();
|
||||
},
|
||||
);
|
||||
|
||||
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:
|
||||
return MaterialPageRoute(
|
||||
builder: (_) {
|
||||
return BlocProvider(
|
||||
create: (_) => OffersBloc(),
|
||||
child: SearchOffersWithListing(),
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
// 🔹 Upload Photo Page (start of postcard creation flow)
|
||||
case RouteConstants.postCardCreationPage:
|
||||
return MaterialPageRoute(
|
||||
builder: (_) => BlocProvider(
|
||||
create: (_) => PostcardCreationBloc(),
|
||||
@@ -37,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(),
|
||||
@@ -49,11 +115,79 @@ Widget buildOffstageNavigator(
|
||||
},
|
||||
);
|
||||
|
||||
case RouteConstants.qrPage:
|
||||
return MaterialPageRoute(
|
||||
builder: (context) {
|
||||
final previousBloc = BlocProvider.of<MyPassBloc>(context);
|
||||
return BlocProvider.value(
|
||||
value: previousBloc,
|
||||
child: const QrPassView(),
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
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'))),
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
@@ -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";
|
||||
@@ -46,4 +52,9 @@ class RouteConstants {
|
||||
static const String cartPage = '/cartPage';
|
||||
static const String yourItinerary = '/yourItinerary';
|
||||
|
||||
|
||||
static const String qrPage = '/qrPage';
|
||||
static const String makeBooking = '/makeBooking';
|
||||
static const String bookingSuccessful = '/bookingSuccessful';
|
||||
static const String postCardCreationPage = '/postCardCreationPage';
|
||||
}
|
||||
|
||||