Compare commits
2 Commits
10eae3577f
...
e91d24becc
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e91d24becc | ||
|
|
09726eb4e6 |
@@ -15,7 +15,7 @@ import '../repository/create_account_repository.dart';
|
||||
|
||||
class CreateAccountView extends StatelessWidget {
|
||||
final String email;
|
||||
CreateAccountView({super.key,required this.email});
|
||||
CreateAccountView({super.key, required this.email});
|
||||
|
||||
final TextEditingController firstNameController = TextEditingController();
|
||||
final TextEditingController lastNameController = TextEditingController();
|
||||
@@ -29,9 +29,9 @@ class CreateAccountView extends StatelessWidget {
|
||||
emailController.text.trim().isEmpty ||
|
||||
phoneController.text.trim().isEmpty ||
|
||||
addressController.text.trim().isEmpty) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(content: Text('Please fill all fields')),
|
||||
);
|
||||
ScaffoldMessenger.of(
|
||||
context,
|
||||
).showSnackBar(const SnackBar(content: Text('Please fill all fields')));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -51,15 +51,14 @@ class CreateAccountView extends StatelessWidget {
|
||||
Widget build(BuildContext context) {
|
||||
emailController.text = email;
|
||||
return BlocProvider(
|
||||
create: (context) => CreateAccountBloc(
|
||||
repository: CreateAccountRepository(),
|
||||
),
|
||||
create: (context) =>
|
||||
CreateAccountBloc(repository: CreateAccountRepository()),
|
||||
child: BlocListener<CreateAccountBloc, CreateAccountState>(
|
||||
listener: (context, state) async {
|
||||
listener: (ctx, state) async {
|
||||
if (state is CreateAccountSuccess) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(content: Text(state.message)),
|
||||
);
|
||||
ScaffoldMessenger.of(
|
||||
context,
|
||||
).showSnackBar(SnackBar(content: Text(state.message)));
|
||||
await LocalPreference.setLogin(true);
|
||||
final userId = await LocalPreference.getUserId();
|
||||
context.read<ProfileBloc>().add(FetchProfileEvent(userId: userId!));
|
||||
|
||||
20
lib/itinerary_creation/bloc/get_itinerary_bloc.dart
Normal file
20
lib/itinerary_creation/bloc/get_itinerary_bloc.dart
Normal file
@@ -0,0 +1,20 @@
|
||||
import 'package:bloc/bloc.dart';
|
||||
import 'package:citycards_customer/itinerary_creation/repository/itinerary_repository.dart';
|
||||
import 'package:equatable/equatable.dart';
|
||||
|
||||
part 'get_itinerary_event.dart';
|
||||
part 'get_itinerary_state.dart';
|
||||
|
||||
class GetItineraryBloc extends Bloc<GetItineraryEvent, GetItineraryState> {
|
||||
GetItineraryBloc() : super(GetItineraryInitial()) {
|
||||
on<GetIiterary>((event, emit) {
|
||||
try {
|
||||
emit(GetItineraryLoading());
|
||||
final data = ItineraryRepository().fetchItinerary();
|
||||
emit(GetItinerarySuccessfully());
|
||||
} catch (e) {
|
||||
emit(GetItineraryFailed(error: "Something went wrong"));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
26
lib/itinerary_creation/bloc/get_itinerary_cities_bloc.dart
Normal file
26
lib/itinerary_creation/bloc/get_itinerary_cities_bloc.dart
Normal file
@@ -0,0 +1,26 @@
|
||||
import 'dart:developer';
|
||||
|
||||
import 'package:bloc/bloc.dart';
|
||||
import 'package:citycards_customer/itinerary_creation/models/itinerary_city_model.dart';
|
||||
import 'package:citycards_customer/itinerary_creation/repository/itinerary_repository.dart';
|
||||
import 'package:equatable/equatable.dart';
|
||||
|
||||
part 'get_itinerary_cities_event.dart';
|
||||
part 'get_itinerary_cities_state.dart';
|
||||
|
||||
class GetItineraryCitiesBloc
|
||||
extends Bloc<GetItineraryCitiesEvent, GetItineraryCitiesState> {
|
||||
GetItineraryCitiesBloc() : super(GetItineraryCitiesInitial()) {
|
||||
on<GetItineraryCities>((event, emit) async {
|
||||
try {
|
||||
log("Getting cities");
|
||||
emit(GetItineraryCitiesLoading());
|
||||
final data = await ItineraryRepository().fetchItineraryCities();
|
||||
emit(GetItineraryCitiesSuccessfully(cities: data));
|
||||
} catch (e) {
|
||||
log("Fetch Itierary - ${e.toString()}");
|
||||
emit(GetItineraryCitiesFailed(error: "Something went wrong"));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
10
lib/itinerary_creation/bloc/get_itinerary_cities_event.dart
Normal file
10
lib/itinerary_creation/bloc/get_itinerary_cities_event.dart
Normal file
@@ -0,0 +1,10 @@
|
||||
part of 'get_itinerary_cities_bloc.dart';
|
||||
|
||||
abstract class GetItineraryCitiesEvent extends Equatable {
|
||||
const GetItineraryCitiesEvent();
|
||||
|
||||
@override
|
||||
List<Object> get props => [];
|
||||
}
|
||||
|
||||
class GetItineraryCities extends GetItineraryCitiesEvent {}
|
||||
22
lib/itinerary_creation/bloc/get_itinerary_cities_state.dart
Normal file
22
lib/itinerary_creation/bloc/get_itinerary_cities_state.dart
Normal file
@@ -0,0 +1,22 @@
|
||||
part of 'get_itinerary_cities_bloc.dart';
|
||||
|
||||
abstract class GetItineraryCitiesState extends Equatable {
|
||||
const GetItineraryCitiesState();
|
||||
|
||||
@override
|
||||
List<Object> get props => [];
|
||||
}
|
||||
|
||||
class GetItineraryCitiesInitial extends GetItineraryCitiesState {}
|
||||
|
||||
class GetItineraryCitiesLoading extends GetItineraryCitiesState {}
|
||||
|
||||
class GetItineraryCitiesSuccessfully extends GetItineraryCitiesState {
|
||||
final List<ItineraryCityModel> cities;
|
||||
const GetItineraryCitiesSuccessfully({required this.cities});
|
||||
}
|
||||
|
||||
class GetItineraryCitiesFailed extends GetItineraryCitiesState {
|
||||
final String error;
|
||||
const GetItineraryCitiesFailed({required this.error});
|
||||
}
|
||||
10
lib/itinerary_creation/bloc/get_itinerary_event.dart
Normal file
10
lib/itinerary_creation/bloc/get_itinerary_event.dart
Normal file
@@ -0,0 +1,10 @@
|
||||
part of 'get_itinerary_bloc.dart';
|
||||
|
||||
abstract class GetItineraryEvent extends Equatable {
|
||||
const GetItineraryEvent();
|
||||
|
||||
@override
|
||||
List<Object> get props => [];
|
||||
}
|
||||
|
||||
class GetIiterary extends GetItineraryEvent {}
|
||||
19
lib/itinerary_creation/bloc/get_itinerary_state.dart
Normal file
19
lib/itinerary_creation/bloc/get_itinerary_state.dart
Normal file
@@ -0,0 +1,19 @@
|
||||
part of 'get_itinerary_bloc.dart';
|
||||
|
||||
abstract class GetItineraryState extends Equatable {
|
||||
const GetItineraryState();
|
||||
|
||||
@override
|
||||
List<Object> get props => [];
|
||||
}
|
||||
|
||||
final class GetItineraryInitial extends GetItineraryState {}
|
||||
|
||||
class GetItineraryLoading extends GetItineraryState {}
|
||||
|
||||
class GetItinerarySuccessfully extends GetItineraryState {}
|
||||
|
||||
class GetItineraryFailed extends GetItineraryState {
|
||||
final String error;
|
||||
const GetItineraryFailed({required this.error});
|
||||
}
|
||||
@@ -1,6 +1,9 @@
|
||||
import 'package:citycards_customer/itinerary_creation/models/itinerary_city_model.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
|
||||
import '../models/current_location_model.dart';
|
||||
|
||||
abstract class ItineraryDetailEvent {}
|
||||
|
||||
class AddDateToItinerary extends ItineraryDetailEvent {
|
||||
@@ -10,11 +13,17 @@ class AddDateToItinerary extends ItineraryDetailEvent {
|
||||
}
|
||||
|
||||
class AddCityToItinerary extends ItineraryDetailEvent {
|
||||
final String city;
|
||||
final ItineraryCityModel city;
|
||||
|
||||
AddCityToItinerary(this.city);
|
||||
}
|
||||
|
||||
class AddAddressToItinerary extends ItineraryDetailEvent {
|
||||
final CurrentLocationModel address;
|
||||
|
||||
AddAddressToItinerary(this.address);
|
||||
}
|
||||
|
||||
class AddEnergyToItinerary extends ItineraryDetailEvent {
|
||||
final String energy;
|
||||
|
||||
@@ -65,7 +74,7 @@ class AddShoppingRating extends ItineraryDetailEvent {
|
||||
|
||||
class ItineraryDetailState {
|
||||
final String? selectedDate;
|
||||
final String? selectedCity;
|
||||
final ItineraryCityModel? selectedCity;
|
||||
final String? selectedEnergy;
|
||||
final String? withKid;
|
||||
final String? selectedDietary;
|
||||
@@ -74,6 +83,7 @@ class ItineraryDetailState {
|
||||
final String? culturalRating;
|
||||
final String? wildLifeRating;
|
||||
final String? shoppingRating;
|
||||
final CurrentLocationModel? baseAdd;
|
||||
|
||||
ItineraryDetailState({
|
||||
this.selectedDate,
|
||||
@@ -86,19 +96,21 @@ class ItineraryDetailState {
|
||||
this.culturalRating,
|
||||
this.wildLifeRating,
|
||||
this.shoppingRating,
|
||||
this.baseAdd,
|
||||
});
|
||||
|
||||
ItineraryDetailState copyWith({
|
||||
String? selectedDate,
|
||||
String? selectedCity,
|
||||
ItineraryCityModel? selectedCity,
|
||||
String? selectedEnergy,
|
||||
String? withKid,
|
||||
String? selectedDietary,
|
||||
String? selectedDietary,
|
||||
String? museumRating,
|
||||
String? scenicRating,
|
||||
String? culturalRating,
|
||||
String? wildLifeRating,
|
||||
String? shoppingRating,
|
||||
CurrentLocationModel? baseAdd,
|
||||
}) {
|
||||
return ItineraryDetailState(
|
||||
selectedDate: selectedDate ?? this.selectedDate,
|
||||
@@ -111,6 +123,7 @@ class ItineraryDetailState {
|
||||
culturalRating: culturalRating ?? this.culturalRating,
|
||||
wildLifeRating: wildLifeRating ?? this.wildLifeRating,
|
||||
shoppingRating: shoppingRating ?? this.shoppingRating,
|
||||
baseAdd: baseAdd ?? this.baseAdd,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -121,15 +134,6 @@ class AddItineraryDetailBloc
|
||||
: super(
|
||||
ItineraryDetailState(
|
||||
selectedDate: DateFormat('EEEE, MMMM d, yyyy').format(DateTime.now()),
|
||||
selectedCity: "Paris",
|
||||
selectedEnergy: "",
|
||||
withKid: "",
|
||||
selectedDietary: "",
|
||||
museumRating: "",
|
||||
scenicRating: "",
|
||||
culturalRating: "",
|
||||
wildLifeRating: "",
|
||||
shoppingRating: "",
|
||||
),
|
||||
) {
|
||||
on<AddDateToItinerary>((event, emit) {
|
||||
@@ -137,10 +141,13 @@ class AddItineraryDetailBloc
|
||||
});
|
||||
|
||||
on<AddCityToItinerary>((event, emit) {
|
||||
print("Selected city: ${event.city}");
|
||||
emit(state.copyWith(selectedCity: event.city));
|
||||
});
|
||||
|
||||
on<AddAddressToItinerary>((event, emit) {
|
||||
emit(state.copyWith(baseAdd: event.address));
|
||||
});
|
||||
|
||||
on<AddEnergyToItinerary>((event, emit) {
|
||||
emit(state.copyWith(selectedEnergy: event.energy));
|
||||
});
|
||||
@@ -150,13 +157,6 @@ class AddItineraryDetailBloc
|
||||
});
|
||||
|
||||
on<AddDietaryToItinerary>((event, emit) {
|
||||
// final currentSelection = List<String>.from(state.selectedDietary ?? []);
|
||||
//
|
||||
// if (currentSelection.contains(event.dietary)) {
|
||||
// currentSelection.remove(event.dietary);
|
||||
// } else {
|
||||
// currentSelection.add(event.dietary);
|
||||
// }
|
||||
emit(state.copyWith(selectedDietary: event.dietary));
|
||||
});
|
||||
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
class CurrentLocationModel {
|
||||
final String? baseAdd;
|
||||
final double? lat;
|
||||
final double? lan;
|
||||
CurrentLocationModel({this.baseAdd, this.lan, this.lat});
|
||||
}
|
||||
57
lib/itinerary_creation/models/itinerary_city_model.dart
Normal file
57
lib/itinerary_creation/models/itinerary_city_model.dart
Normal file
@@ -0,0 +1,57 @@
|
||||
class ItineraryCityModel {
|
||||
int? id;
|
||||
String? cityName;
|
||||
String? urlSlug;
|
||||
int? iconXid;
|
||||
Icon? icon;
|
||||
|
||||
ItineraryCityModel({
|
||||
this.id,
|
||||
this.cityName,
|
||||
this.urlSlug,
|
||||
this.iconXid,
|
||||
this.icon,
|
||||
});
|
||||
|
||||
ItineraryCityModel.fromJson(Map<String, dynamic> json) {
|
||||
id = json['id'];
|
||||
cityName = json['cityName'];
|
||||
urlSlug = json['urlSlug'];
|
||||
iconXid = json['iconXid'];
|
||||
icon = json['icon'] != null ? Icon.fromJson(json['icon']) : null;
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final Map<String, dynamic> data = <String, dynamic>{};
|
||||
data['id'] = id;
|
||||
data['cityName'] = cityName;
|
||||
data['urlSlug'] = urlSlug;
|
||||
data['iconXid'] = iconXid;
|
||||
if (icon != null) {
|
||||
data['icon'] = icon!.toJson();
|
||||
}
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
class Icon {
|
||||
int? id;
|
||||
String? iconName;
|
||||
String? iconSvg;
|
||||
|
||||
Icon({this.id, this.iconName, this.iconSvg});
|
||||
|
||||
Icon.fromJson(Map<String, dynamic> json) {
|
||||
id = json['id'];
|
||||
iconName = json['iconName'];
|
||||
iconSvg = json['iconSvg'];
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final Map<String, dynamic> data = <String, dynamic>{};
|
||||
data['id'] = id;
|
||||
data['iconName'] = iconName;
|
||||
data['iconSvg'] = iconSvg;
|
||||
return data;
|
||||
}
|
||||
}
|
||||
36
lib/itinerary_creation/repository/itinerary_repository.dart
Normal file
36
lib/itinerary_creation/repository/itinerary_repository.dart
Normal file
@@ -0,0 +1,36 @@
|
||||
import 'dart:developer';
|
||||
|
||||
import 'package:citycards_customer/itinerary_creation/models/itinerary_city_model.dart';
|
||||
import 'package:dio/dio.dart';
|
||||
|
||||
import '../../networkApiServices/api_urls.dart';
|
||||
import '../../networkApiServices/network_api_services.dart';
|
||||
|
||||
class ItineraryRepository {
|
||||
final NetworkApiService _apiService = NetworkApiService();
|
||||
|
||||
Future<dynamic> fetchItinerary() async {
|
||||
final response = await _apiService.getApi(url: ApiUrls.getItinerary);
|
||||
|
||||
return response.data;
|
||||
}
|
||||
|
||||
Future<List<ItineraryCityModel>> fetchItineraryCities() async {
|
||||
try {
|
||||
final response = await _apiService.getApi(
|
||||
url: ApiUrls.getItineraryCities,
|
||||
);
|
||||
final List<ItineraryCityModel> cities = (response.data as List)
|
||||
.map((e) => ItineraryCityModel.fromJson(e as Map<String, dynamic>))
|
||||
.toList();
|
||||
|
||||
return cities;
|
||||
} on DioException catch (e) {
|
||||
// log("Error logged - ${e.response}");
|
||||
throw e.response!.data["message"] ?? "Something went wrong";
|
||||
} catch (e, stack) {
|
||||
log("Error logged - ${stack.toString()}");
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,47 +1,30 @@
|
||||
import 'package:cached_network_image/cached_network_image.dart';
|
||||
import 'package:citycards_customer/common_packages/custom_filled_button.dart';
|
||||
import 'package:citycards_customer/common_packages/custom_search_field.dart';
|
||||
import 'package:citycards_customer/common_packages/custom_text.dart';
|
||||
import 'package:citycards_customer/common_packages/custom_textfield.dart';
|
||||
import 'package:citycards_customer/itinerary_creation/bloc/get_itinerary_cities_bloc.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/networkApiServices/api_urls.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
||||
|
||||
class MenuItem {
|
||||
final int id;
|
||||
final String label;
|
||||
final String flag;
|
||||
class CitySelectionView extends StatefulWidget {
|
||||
const CitySelectionView({super.key});
|
||||
|
||||
MenuItem(this.id, this.label, this.flag);
|
||||
@override
|
||||
State<CitySelectionView> createState() => _CitySelectionViewState();
|
||||
}
|
||||
|
||||
List<MenuItem> menuItems = [
|
||||
MenuItem(1, 'Paris', "🇫🇷"),
|
||||
MenuItem(2, 'Tokyo', "🇯🇵"),
|
||||
MenuItem(3, 'New York', "🇺🇸"),
|
||||
MenuItem(4, 'London', "🇬🇧"),
|
||||
MenuItem(5, 'Barcelona', "🇪🇸"),
|
||||
MenuItem(6, 'Dubai', "🇦🇪"),
|
||||
MenuItem(7, 'Rome', "🇮🇹"),
|
||||
MenuItem(8, 'Bangkok', "🇹🇭"),
|
||||
];
|
||||
|
||||
class CitySelectionView extends StatelessWidget {
|
||||
CitySelectionView({super.key});
|
||||
|
||||
final List<Map<String, String>> cityList = [
|
||||
{"flag": "🇫🇷", "city": "Paris"},
|
||||
{"flag": "🇯🇵", "city": "Tokyo"},
|
||||
{"flag": "🇺🇸", "city": "New York"},
|
||||
{"flag": "🇬🇧", "city": "London"},
|
||||
{"flag": "🇪🇸", "city": "Barcelona"},
|
||||
{"flag": "🇦🇪", "city": "Dubai"},
|
||||
{"flag": "🇮🇹", "city": "Rome"},
|
||||
{"flag": "🇹🇭", "city": "Bangkok"},
|
||||
];
|
||||
|
||||
class _CitySelectionViewState extends State<CitySelectionView> {
|
||||
final TextEditingController cityController = TextEditingController();
|
||||
final GetItineraryCitiesBloc getItineraryCitiesBloc =
|
||||
GetItineraryCitiesBloc();
|
||||
@override
|
||||
void initState() {
|
||||
getItineraryCitiesBloc.add(GetItineraryCities());
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@@ -60,89 +43,6 @@ class CitySelectionView extends StatelessWidget {
|
||||
),
|
||||
SizedBox(height: 32.h),
|
||||
|
||||
Container(
|
||||
height: 56.h,
|
||||
padding: EdgeInsets.only(left: 20.w),
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(color: Color(0xFFF95F62)),
|
||||
borderRadius: BorderRadius.circular(28),
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
Image.asset("assets/icons/location.png", scale: 4),
|
||||
Expanded(
|
||||
child: SizedBox(
|
||||
child:
|
||||
BlocBuilder<
|
||||
AddItineraryDetailBloc,
|
||||
ItineraryDetailState
|
||||
>(
|
||||
builder: (context, state) {
|
||||
final selectedMenuItem = menuItems.firstWhere(
|
||||
(menu) => menu.label == state.selectedCity,
|
||||
orElse: () =>
|
||||
menuItems.first, // fallback if not found
|
||||
);
|
||||
return DropdownMenu<MenuItem>(
|
||||
controller: cityController,
|
||||
initialSelection: selectedMenuItem,
|
||||
width: double.infinity,
|
||||
hintText: "Select City",
|
||||
requestFocusOnTap: true,
|
||||
enableFilter: true,
|
||||
showTrailingIcon: false,
|
||||
onSelected: (MenuItem? menu) {
|
||||
context.read<AddItineraryDetailBloc>().add(
|
||||
AddCityToItinerary(menu!.label),
|
||||
);
|
||||
},
|
||||
inputDecorationTheme: InputDecorationTheme(
|
||||
contentPadding: EdgeInsets.symmetric(
|
||||
vertical: 6.h,
|
||||
),
|
||||
enabledBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(28),
|
||||
borderSide: const BorderSide(
|
||||
color: Colors.transparent,
|
||||
),
|
||||
),
|
||||
|
||||
focusedBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(28),
|
||||
borderSide: const BorderSide(
|
||||
color: Colors.transparent,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
menuStyle: MenuStyle(
|
||||
backgroundColor: WidgetStateProperty.all(
|
||||
Colors.white,
|
||||
),
|
||||
maximumSize: WidgetStateProperty.all(
|
||||
Size.infinite,
|
||||
),
|
||||
),
|
||||
dropdownMenuEntries: menuItems
|
||||
.map<DropdownMenuEntry<MenuItem>>((
|
||||
MenuItem menu,
|
||||
) {
|
||||
return DropdownMenuEntry<MenuItem>(
|
||||
value: menu,
|
||||
label: menu.label,
|
||||
leadingIcon: CustomText(text: menu.flag),
|
||||
);
|
||||
})
|
||||
.toList(),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
SizedBox(height: 16.h),
|
||||
Align(
|
||||
alignment: Alignment.topLeft,
|
||||
@@ -154,57 +54,86 @@ class CitySelectionView extends StatelessWidget {
|
||||
),
|
||||
),
|
||||
SizedBox(height: 10.h),
|
||||
SizedBox(
|
||||
height: 175.h,
|
||||
child: BlocBuilder<AddItineraryDetailBloc, ItineraryDetailState>(
|
||||
builder: (context, state) {
|
||||
return GridView.builder(
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
|
||||
crossAxisCount: 4,
|
||||
mainAxisSpacing: 16.h,
|
||||
crossAxisSpacing: 16.w,
|
||||
),
|
||||
itemCount: cityList.length,
|
||||
itemBuilder: (context, index) {
|
||||
final item = cityList[index];
|
||||
final isSelected = item['city'] == state.selectedCity;
|
||||
return GestureDetector(
|
||||
onTap: () {
|
||||
context.read<AddItineraryDetailBloc>().add(
|
||||
AddCityToItinerary(item['city'] ?? ""),
|
||||
);
|
||||
},
|
||||
child: Container(
|
||||
height: 78.h,
|
||||
width: 76.w,
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
border: Border.all(
|
||||
color: isSelected
|
||||
? Color(0xFFF95F62)
|
||||
: Colors.transparent,
|
||||
),
|
||||
BlocBuilder<GetItineraryCitiesBloc, GetItineraryCitiesState>(
|
||||
bloc: getItineraryCitiesBloc,
|
||||
builder: (ctx, state1) {
|
||||
if (state1 is GetItineraryCitiesLoading) {
|
||||
return Center(child: CircularProgressIndicator());
|
||||
} else if (state1 is GetItineraryCitiesFailed) {
|
||||
return Center(child: Text(state1.error));
|
||||
} else if (state1 is GetItineraryCitiesSuccessfully &&
|
||||
state1.cities.isEmpty) {
|
||||
return Center(child: Text("Data not found"));
|
||||
} else if (state1 is GetItineraryCitiesSuccessfully) {
|
||||
return SizedBox(
|
||||
height: 175.h,
|
||||
child: BlocBuilder<AddItineraryDetailBloc, ItineraryDetailState>(
|
||||
builder: (context, state) {
|
||||
return GridView.builder(
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
|
||||
crossAxisCount: 4,
|
||||
mainAxisSpacing: 16.h,
|
||||
crossAxisSpacing: 16.w,
|
||||
),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
CustomText(text: item['flag'] ?? ""),
|
||||
SizedBox(height: 4.h),
|
||||
CustomText(
|
||||
text: item['city'] ?? "",
|
||||
size: 12.sp,
|
||||
color: Color(0xFF364153),
|
||||
itemCount: state1.cities.length,
|
||||
itemBuilder: (context, index) {
|
||||
final item = state1.cities[index];
|
||||
final isSelected = item == state.selectedCity;
|
||||
return GestureDetector(
|
||||
onTap: () {
|
||||
context.read<AddItineraryDetailBloc>().add(
|
||||
AddCityToItinerary(item),
|
||||
);
|
||||
},
|
||||
child: Container(
|
||||
height: 78.h,
|
||||
width: 76.w,
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
border: Border.all(
|
||||
color: isSelected
|
||||
? Color(0xFFF95F62)
|
||||
: Colors.transparent,
|
||||
),
|
||||
),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
CachedNetworkImage(
|
||||
imageUrl:
|
||||
"${ApiUrls.baseUrl}${item.icon!.iconSvg!}",
|
||||
width: 20,
|
||||
height: 20,
|
||||
fit: BoxFit.cover,
|
||||
placeholder: (context, url) => Container(
|
||||
width: 20,
|
||||
height: 20,
|
||||
color: Colors.grey.shade50,
|
||||
),
|
||||
errorWidget: (context, url, error) =>
|
||||
const Icon(Icons.flag, size: 20),
|
||||
),
|
||||
SizedBox(height: 4.h),
|
||||
CustomText(
|
||||
text: item.cityName ?? "",
|
||||
size: 12.sp,
|
||||
color: Color(0xFF364153),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
}
|
||||
|
||||
return Container();
|
||||
},
|
||||
),
|
||||
SizedBox(height: 40.h),
|
||||
CustomFilledButton(
|
||||
|
||||
@@ -1,11 +1,16 @@
|
||||
import 'package:citycards_customer/common_packages/custom_filled_button.dart';
|
||||
import 'package:citycards_customer/common_packages/custom_text.dart';
|
||||
import 'package:citycards_customer/itinerary_creation/bloc/itinerary_steps_selection_bloc.dart';
|
||||
import 'package:citycards_customer/itinerary_creation/models/current_location_model.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:flutter_map/flutter_map.dart';
|
||||
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
||||
import 'package:google_maps_flutter/google_maps_flutter.dart';
|
||||
import 'package:geocoding/geocoding.dart';
|
||||
import 'package:geolocator/geolocator.dart';
|
||||
import 'package:latlong2/latlong.dart';
|
||||
|
||||
import '../../bloc/itinerary_detail_bloc.dart';
|
||||
|
||||
class CurrentLocationSelection extends StatefulWidget {
|
||||
const CurrentLocationSelection({super.key});
|
||||
@@ -21,6 +26,7 @@ class _CurrentLocationSelectionState extends State<CurrentLocationSelection> {
|
||||
|
||||
Future<void> _getCurrentLocation() async {
|
||||
LocationPermission permission = await Geolocator.requestPermission();
|
||||
|
||||
if (permission == LocationPermission.denied ||
|
||||
permission == LocationPermission.deniedForever) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
@@ -33,11 +39,40 @@ class _CurrentLocationSelectionState extends State<CurrentLocationSelection> {
|
||||
desiredAccuracy: LocationAccuracy.high,
|
||||
);
|
||||
|
||||
final lat = position.latitude;
|
||||
final lng = position.longitude;
|
||||
|
||||
setState(() {
|
||||
_currentLatLng = LatLng(position.latitude, position.longitude);
|
||||
_controller.text =
|
||||
"Lat: ${position.latitude.toStringAsFixed(5)}, Lng: ${position.longitude.toStringAsFixed(5)}";
|
||||
_currentLatLng = LatLng(lat, lng);
|
||||
});
|
||||
|
||||
await _getAddressFromLatLng(lat, lng);
|
||||
}
|
||||
|
||||
Future<void> _getAddressFromLatLng(double lat, double lng) async {
|
||||
try {
|
||||
final placemarks = await placemarkFromCoordinates(lat, lng);
|
||||
|
||||
if (placemarks.isNotEmpty) {
|
||||
final place = placemarks.first;
|
||||
|
||||
final address = [
|
||||
place.name,
|
||||
place.street,
|
||||
place.subLocality,
|
||||
place.locality,
|
||||
place.administrativeArea,
|
||||
place.postalCode,
|
||||
place.country,
|
||||
].where((e) => e != null && e.isNotEmpty).join(', ');
|
||||
|
||||
setState(() {
|
||||
_controller.text = address;
|
||||
});
|
||||
}
|
||||
} catch (e) {
|
||||
debugPrint("Reverse geocoding error: $e");
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -98,32 +133,38 @@ class _CurrentLocationSelectionState extends State<CurrentLocationSelection> {
|
||||
child: SizedBox(
|
||||
height: 250.h,
|
||||
width: double.infinity,
|
||||
|
||||
child: Image.asset(
|
||||
"assets/images/attra_detail_map.png",
|
||||
fit: BoxFit.cover,
|
||||
height: 236.h,
|
||||
child: FlutterMap(
|
||||
options: MapOptions(
|
||||
initialCenter: _currentLatLng!,
|
||||
initialZoom: 15,
|
||||
),
|
||||
children: [
|
||||
TileLayer(
|
||||
urlTemplate:
|
||||
"https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png",
|
||||
subdomains: const ['a', 'b', 'c'],
|
||||
userAgentPackageName: 'com.citycards.customer',
|
||||
),
|
||||
MarkerLayer(
|
||||
markers: [
|
||||
Marker(
|
||||
point: _currentLatLng!,
|
||||
width: 40,
|
||||
height: 40,
|
||||
child: const Icon(
|
||||
Icons.location_pin,
|
||||
color: Colors.red,
|
||||
size: 40,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
// child: GoogleMap(
|
||||
// initialCameraPosition: CameraPosition(
|
||||
// target: _currentLatLng!,
|
||||
// zoom: 15,
|
||||
// ),
|
||||
// markers: {
|
||||
// Marker(
|
||||
// markerId: const MarkerId("currentLocation"),
|
||||
// position: _currentLatLng!,
|
||||
// ),
|
||||
// },
|
||||
// myLocationEnabled: true,
|
||||
// myLocationButtonEnabled: false,
|
||||
// ),
|
||||
),
|
||||
)
|
||||
: GestureDetector(
|
||||
onTap: () {
|
||||
_getCurrentLocation();
|
||||
},
|
||||
onTap: _getCurrentLocation,
|
||||
child: Container(
|
||||
height: 46.h,
|
||||
padding: EdgeInsets.symmetric(horizontal: 12.w),
|
||||
@@ -155,6 +196,15 @@ class _CurrentLocationSelectionState extends State<CurrentLocationSelection> {
|
||||
// --- Continue button ---
|
||||
CustomFilledButton(
|
||||
onTap: () {
|
||||
context.read<AddItineraryDetailBloc>().add(
|
||||
AddAddressToItinerary(
|
||||
CurrentLocationModel(
|
||||
baseAdd: _controller.text,
|
||||
lan: _currentLatLng?.latitude,
|
||||
lat: _currentLatLng?.latitude,
|
||||
),
|
||||
),
|
||||
);
|
||||
context.read<ItineraryStepNavigationBloc>().add(
|
||||
ItineraryStepNavigationNextEvent(),
|
||||
);
|
||||
|
||||
@@ -27,35 +27,35 @@ class DateSelectionView extends StatelessWidget {
|
||||
),
|
||||
SizedBox(height: 32.h),
|
||||
|
||||
Container(
|
||||
height: 90.h,
|
||||
padding: EdgeInsets.symmetric(horizontal: 20.w),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(28),
|
||||
border: Border.all(color: Color(0xFFF95F62), width: 1.1.w),
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
GestureDetector(
|
||||
onTap: () {
|
||||
_pickDate(context);
|
||||
},
|
||||
child: Image.asset("assets/icons/calender.png", scale: 4),
|
||||
),
|
||||
SizedBox(width: 16.w),
|
||||
BlocBuilder<AddItineraryDetailBloc, ItineraryDetailState>(
|
||||
builder: (context, state) {
|
||||
return CustomText(
|
||||
text: state.selectedDate ?? "",
|
||||
size: 14.sp,
|
||||
color: Color(0xFF101828),
|
||||
);
|
||||
},
|
||||
),
|
||||
const Spacer(),
|
||||
Icon(Icons.check_circle, color: Color(0xFFF95F62)),
|
||||
],
|
||||
GestureDetector(
|
||||
onTap: () {
|
||||
_pickDate(context);
|
||||
},
|
||||
child: Container(
|
||||
height: 90.h,
|
||||
padding: EdgeInsets.symmetric(horizontal: 20.w),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(28),
|
||||
border: Border.all(color: Color(0xFFF95F62), width: 1.1.w),
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
Image.asset("assets/icons/calender.png", scale: 4),
|
||||
SizedBox(width: 16.w),
|
||||
BlocBuilder<AddItineraryDetailBloc, ItineraryDetailState>(
|
||||
builder: (context, state) {
|
||||
return CustomText(
|
||||
text: state.selectedDate ?? "",
|
||||
size: 14.sp,
|
||||
color: Color(0xFF101828),
|
||||
);
|
||||
},
|
||||
),
|
||||
const Spacer(),
|
||||
Icon(Icons.check_circle, color: Color(0xFFF95F62)),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(height: 32.h),
|
||||
|
||||
@@ -69,7 +69,7 @@ class ItineraryCompletionView extends StatelessWidget {
|
||||
),
|
||||
_buildProfileRow(
|
||||
"City",
|
||||
state.selectedCity ?? "",
|
||||
state.selectedCity!.cityName ?? "",
|
||||
),
|
||||
_buildProfileRow(
|
||||
"Energy",
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
|
||||
import 'package:citycards_customer/itinerary_creation/bloc/get_itinerary_cities_bloc.dart';
|
||||
import 'package:citycards_customer/itinerary_creation/bloc/itinerary_steps_selection_bloc.dart';
|
||||
import 'package:citycards_customer/itinerary_creation/views/itinerary_creation_steps/current_location_selection.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
@@ -105,7 +105,10 @@ class _ItineraryCreationPageState extends State<ItineraryCreationPage> {
|
||||
children: [
|
||||
DateSelectionView(),
|
||||
CurrentLocationSelection(),
|
||||
CitySelectionView(),
|
||||
BlocProvider(
|
||||
create: (context) => GetItineraryCitiesBloc(),
|
||||
child: CitySelectionView(),
|
||||
),
|
||||
EnergySelectionView(),
|
||||
KidsSelectionView(),
|
||||
DietarySelectionView(),
|
||||
|
||||
@@ -43,63 +43,63 @@ class _MagicItineraryViewState extends State<MagicItineraryView> {
|
||||
child: isLoading
|
||||
? Center(child: CircularProgressIndicator())
|
||||
: Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 20.w, vertical: 10.h),
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
children: [
|
||||
CommonAppBar(
|
||||
isWhiteLogo: false,
|
||||
isProfilePage: false,
|
||||
showDivider: false,
|
||||
),
|
||||
SizedBox(height: 24.h),
|
||||
padding: EdgeInsets.symmetric(horizontal: 20.w, vertical: 10.h),
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
children: [
|
||||
CommonAppBar(
|
||||
isWhiteLogo: false,
|
||||
isProfilePage: false,
|
||||
showDivider: false,
|
||||
),
|
||||
SizedBox(height: 24.h),
|
||||
|
||||
// Show different UI based on login status
|
||||
if (isLoggedIn) ...[
|
||||
ItineraryFilledCard(),
|
||||
SizedBox(height: 32.h),
|
||||
CustomPaint(
|
||||
painter: DottedBorderPainter(),
|
||||
child: Container(
|
||||
width: double.infinity,
|
||||
padding: EdgeInsets.symmetric(vertical: 24.h),
|
||||
decoration: BoxDecoration(
|
||||
color: Color(0xFFF95F62).withOpacity(0.25),
|
||||
borderRadius: BorderRadius.circular(12.sp),
|
||||
),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
CustomText(
|
||||
text: "Plan your next adventure",
|
||||
color: Color(0xFF656565),
|
||||
size: 14.sp,
|
||||
),
|
||||
SizedBox(height: 16.h),
|
||||
CustomFilledButton(
|
||||
onTap: () {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) =>
|
||||
ItineraryCreationStartPage(),
|
||||
// Show different UI based on login status
|
||||
if (isLoggedIn) ...[
|
||||
ItineraryFilledCard(),
|
||||
SizedBox(height: 32.h),
|
||||
CustomPaint(
|
||||
painter: DottedBorderPainter(),
|
||||
child: Container(
|
||||
width: double.infinity,
|
||||
padding: EdgeInsets.symmetric(vertical: 24.h),
|
||||
decoration: BoxDecoration(
|
||||
color: Color(0xFFF95F62).withOpacity(0.25),
|
||||
borderRadius: BorderRadius.circular(12.sp),
|
||||
),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
CustomText(
|
||||
text: "Plan your next adventure",
|
||||
color: Color(0xFF656565),
|
||||
size: 14.sp,
|
||||
),
|
||||
);
|
||||
},
|
||||
label: "Create My Itinerary",
|
||||
showArrow: true,
|
||||
SizedBox(height: 16.h),
|
||||
CustomFilledButton(
|
||||
onTap: () {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) =>
|
||||
ItineraryCreationStartPage(),
|
||||
),
|
||||
);
|
||||
},
|
||||
label: "Create My Itinerary",
|
||||
showArrow: true,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
] else ...[
|
||||
EmptyItineraryView(),
|
||||
],
|
||||
],
|
||||
),
|
||||
] else ...[
|
||||
EmptyItineraryView(),
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -151,9 +151,7 @@ class EmptyItineraryView extends StatelessWidget {
|
||||
context: context,
|
||||
isScrollControlled: true,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.vertical(
|
||||
top: Radius.circular(12.r),
|
||||
),
|
||||
borderRadius: BorderRadius.vertical(top: Radius.circular(12.r)),
|
||||
),
|
||||
builder: (_) => const LoginEmailBottomsheet(),
|
||||
);
|
||||
@@ -247,8 +245,9 @@ class ItineraryFilledCard extends StatelessWidget {
|
||||
SizedBox(height: 12.h),
|
||||
InkWell(
|
||||
onTap: () {
|
||||
Navigator.of(context)
|
||||
.pushReplacementNamed(RouteConstants.yourItinerary);
|
||||
Navigator.of(
|
||||
context,
|
||||
).pushReplacementNamed(RouteConstants.yourItinerary);
|
||||
},
|
||||
child: Container(
|
||||
height: 43.h,
|
||||
|
||||
@@ -20,6 +20,9 @@ class ApiUrls {
|
||||
static const myPostCards = "$baseUrl/mobile/postcards/all";
|
||||
static const coupons = "$baseUrl/mobile/passes/dropdown/card";
|
||||
|
||||
static const getItinerary = "$baseUrl/mobile/itinerary/all-initineraries";
|
||||
static const getItineraryCities =
|
||||
"$baseUrl/mobile/itinerary/cities-with-icons";
|
||||
|
||||
//Post Apis
|
||||
static const createAccount = "$baseUrl/mobile/user/register";
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import 'dart:developer';
|
||||
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import '../localPreference/local_preference.dart';
|
||||
@@ -34,14 +36,17 @@ class NetworkApiService {
|
||||
const maxRetries = 2;
|
||||
final currentRetry = options.extra['retry'] as int? ?? 0;
|
||||
|
||||
final shouldRetry = currentRetry < maxRetries &&
|
||||
final shouldRetry =
|
||||
currentRetry < maxRetries &&
|
||||
(err.type == DioExceptionType.connectionTimeout ||
|
||||
err.type == DioExceptionType.sendTimeout ||
|
||||
err.type == DioExceptionType.receiveTimeout);
|
||||
|
||||
if (shouldRetry) {
|
||||
if (kDebugMode) {
|
||||
print('🔁 Retrying request (${currentRetry + 1}) => ${options.uri}');
|
||||
print(
|
||||
'🔁 Retrying request (${currentRetry + 1}) => ${options.uri}',
|
||||
);
|
||||
}
|
||||
|
||||
options.extra['retry'] = currentRetry + 1;
|
||||
@@ -65,6 +70,7 @@ class NetworkApiService {
|
||||
QueuedInterceptorsWrapper(
|
||||
onRequest: (options, handler) async {
|
||||
final token = await LocalPreference.getAccessToken();
|
||||
|
||||
if (token != null && token.isNotEmpty) {
|
||||
options.headers['Authorization'] = 'Bearer $token';
|
||||
}
|
||||
@@ -188,9 +194,7 @@ class NetworkApiService {
|
||||
final response = await _dio.post(
|
||||
ApiUrls.refreshToken,
|
||||
data: {"refreshToken": refreshToken},
|
||||
options: Options(
|
||||
headers: {'Authorization': null},
|
||||
),
|
||||
options: Options(headers: {'Authorization': null}),
|
||||
);
|
||||
await LocalPreference.setAccessToken(response.data['accessToken']);
|
||||
|
||||
|
||||
@@ -5,6 +5,8 @@ import '../../common_packages/app_bar.dart';
|
||||
import '../../common_packages/back_widget.dart';
|
||||
import '../models/my_postcard_model.dart';
|
||||
import '../../networkApiServices/api_urls.dart';
|
||||
import '../widgets/back_card_widget.dart';
|
||||
import '../widgets/front_card_widget.dart';
|
||||
|
||||
class MyPostcardPreviewView extends StatefulWidget {
|
||||
final MyPostCard postcard;
|
||||
@@ -154,9 +156,39 @@ class _MyPostcardPreviewViewState extends State<MyPostcardPreviewView> {
|
||||
),
|
||||
),
|
||||
|
||||
// Postcard Display
|
||||
// Expanded(
|
||||
// child: Padding(
|
||||
// padding: EdgeInsets.only(top: 40.h),
|
||||
// child: Align(
|
||||
// alignment: Alignment.topCenter,
|
||||
// child: AnimatedSwitcher(
|
||||
// duration: const Duration(milliseconds: 400),
|
||||
// transitionBuilder: (child, animation) {
|
||||
// return FadeTransition(
|
||||
// opacity: animation,
|
||||
// child: child,
|
||||
// );
|
||||
// },
|
||||
// child: showBack
|
||||
// ? BackCardWidget(
|
||||
// key: const ValueKey('back'),
|
||||
// message: widget.postcard.pcContent,
|
||||
// city: widget.postcard.cityName,
|
||||
// state: widget.postcard.stateName,
|
||||
// country: widget.postcard.countryName,
|
||||
// )
|
||||
// : FrontCardWidget(
|
||||
// key: const ValueKey('front'),
|
||||
// imageUrl:
|
||||
// '${ApiUrls.baseUrl}${widget.postcard.pcImagePath}',
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
Expanded(
|
||||
child: Center(
|
||||
child: Padding(
|
||||
padding: EdgeInsets.only(top: 40.h),
|
||||
child: AnimatedSwitcher(
|
||||
duration: const Duration(milliseconds: 400),
|
||||
transitionBuilder: (Widget child, Animation<double> animation) {
|
||||
@@ -180,16 +212,8 @@ class _MyPostcardPreviewViewState extends State<MyPostcardPreviewView> {
|
||||
Widget _buildFrontSide() {
|
||||
return Container(
|
||||
key: const ValueKey('front'),
|
||||
margin: EdgeInsets.symmetric(horizontal: 20.w),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(6),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.black.withOpacity(0.1),
|
||||
blurRadius: 10,
|
||||
offset: const Offset(0, 4),
|
||||
),
|
||||
],
|
||||
),
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
@@ -234,7 +258,6 @@ class _MyPostcardPreviewViewState extends State<MyPostcardPreviewView> {
|
||||
Widget _buildBackSide() {
|
||||
return Container(
|
||||
key: const ValueKey('back'),
|
||||
margin: EdgeInsets.symmetric(horizontal: 20.w),
|
||||
decoration: BoxDecoration(
|
||||
gradient: const LinearGradient(
|
||||
colors: [
|
||||
@@ -250,13 +273,6 @@ class _MyPostcardPreviewViewState extends State<MyPostcardPreviewView> {
|
||||
color: const Color(0xff000000).withOpacity(0.12),
|
||||
width: 1,
|
||||
),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.black.withOpacity(0.08),
|
||||
blurRadius: 10,
|
||||
offset: const Offset(0, 4),
|
||||
),
|
||||
],
|
||||
),
|
||||
child: AspectRatio(
|
||||
aspectRatio: 1.5,
|
||||
|
||||
86
pubspec.lock
86
pubspec.lock
@@ -34,13 +34,13 @@ packages:
|
||||
source: hosted
|
||||
version: "2.13.0"
|
||||
bloc:
|
||||
dependency: transitive
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: bloc
|
||||
sha256: e18b8e7825e9921d67a6d256dba0b6015ece8a577eb0a411845c46a352994d78
|
||||
sha256: a48653a82055a900b88cd35f92429f068c5a8057ae9b136d197b3d56c57efb81
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "9.0.1"
|
||||
version: "9.2.0"
|
||||
boolean_selector:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -49,6 +49,30 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.2"
|
||||
cached_network_image:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: cached_network_image
|
||||
sha256: "7c1183e361e5c8b0a0f21a28401eecdbde252441106a9816400dd4c2b2424916"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.4.1"
|
||||
cached_network_image_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: cached_network_image_platform_interface
|
||||
sha256: "35814b016e37fbdc91f7ae18c8caf49ba5c88501813f73ce8a07027a395e2829"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.1.1"
|
||||
cached_network_image_web:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: cached_network_image_web
|
||||
sha256: "980842f4e8e2535b8dbd3d5ca0b1f0ba66bf61d14cc3a17a9b4788a3685ba062"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.3.1"
|
||||
characters:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -262,6 +286,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "9.1.1"
|
||||
flutter_cache_manager:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: flutter_cache_manager
|
||||
sha256: "400b6592f16a4409a7f2bb929a9a7e38c72cceb8ffb99ee57bbf2cb2cecf8386"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.4.1"
|
||||
flutter_glass_morphism:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@@ -365,6 +397,38 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.1.1"
|
||||
geocoding:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: geocoding
|
||||
sha256: "606be036287842d779d7ec4e2f6c9435fc29bbbd3c6da6589710f981d8852895"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.0.0"
|
||||
geocoding_android:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: geocoding_android
|
||||
sha256: ba810da90d6633cbb82bbab630e5b4a3b7d23503263c00ae7f1ef0316dcae5b9
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.0.1"
|
||||
geocoding_ios:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: geocoding_ios
|
||||
sha256: "18ab1c8369e2b0dcb3a8ccc907319334f35ee8cf4cfef4d9c8e23b13c65cb825"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.1.0"
|
||||
geocoding_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: geocoding_platform_interface
|
||||
sha256: "8c2c8226e5c276594c2e18bfe88b19110ed770aeb7c1ab50ede570be8b92229b"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.2.0"
|
||||
geolocator:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@@ -709,6 +773,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.0"
|
||||
octo_image:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: octo_image
|
||||
sha256: "34faa6639a78c7e3cbe79be6f9f96535867e879748ade7d17c9b1ae7536293bd"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.0"
|
||||
opentype_dart:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -837,6 +909,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "6.1.5+1"
|
||||
rxdart:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: rxdart
|
||||
sha256: "5c3004a4a8dbb94bd4bf5412a4def4acdaa12e12f269737a5751369e12d1a962"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.28.0"
|
||||
sanitize_html:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
||||
@@ -57,6 +57,9 @@ dependencies:
|
||||
sqflite: ^2.4.2
|
||||
flutter_map: ^8.2.2
|
||||
flutter_stripe: ^12.2.0
|
||||
geocoding: ^4.0.0
|
||||
cached_network_image: ^3.4.1
|
||||
bloc: ^9.2.0
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
|
||||
Reference in New Issue
Block a user