second commit
This commit is contained in:
446
lib/View/Authentication/Usercreate/Usercreateview.dart
Normal file
446
lib/View/Authentication/Usercreate/Usercreateview.dart
Normal file
@@ -0,0 +1,446 @@
|
||||
import 'dart:io';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
import '../../../Controller/Authentication/Createtenantusercontroller.dart';
|
||||
import '../../../Globalwidgets/textwidget.dart';
|
||||
import '../../../Helper/Constants/AssetConstants.dart';
|
||||
import '../../../Helper/Constants/Colorconstants.dart';
|
||||
import '../../../Helper/Logger.dart';
|
||||
import '../../../Helper/custombutton.dart';
|
||||
import '../../../Helper/customederaction.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
import '../Logiview.dart';
|
||||
|
||||
class CreateUserView extends StatelessWidget {
|
||||
final String? phNumber;
|
||||
CreateUserView({super.key, this.phNumber});
|
||||
|
||||
final CreateUserController controller = Get.put(CreateUserController());
|
||||
final ScrollController listScrollController = ScrollController();
|
||||
final GlobalKey<ScaffoldState> scaffoldKey = GlobalKey<ScaffoldState>();
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return SafeArea(
|
||||
top: false,
|
||||
child: Scaffold(
|
||||
key: scaffoldKey,
|
||||
appBar: AppBar(
|
||||
automaticallyImplyLeading: true,
|
||||
leading: InkWell(
|
||||
onTap: () {
|
||||
Get.to(() => LoginView());
|
||||
},
|
||||
child: Icon(
|
||||
Icons.arrow_back,
|
||||
color: ColorConstants.blackColor,
|
||||
),
|
||||
),
|
||||
title: TextWidget(
|
||||
text: 'Create Account',
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.w700,
|
||||
),
|
||||
),
|
||||
backgroundColor: Colors.white,
|
||||
body: GetBuilder<CreateUserController>(
|
||||
initState: (_) {
|
||||
controller.contactNoController.text = phNumber ?? '';
|
||||
logger.i('Phone Number: ${controller.contactNoController.text}');
|
||||
controller.getAppLocations();
|
||||
controller.getCurrentLocation();
|
||||
controller.getAppCategory();
|
||||
|
||||
logger.i('Cat Name Is empty : ${controller.catName}');
|
||||
},
|
||||
builder: (controller) => Column(
|
||||
children: [
|
||||
// _buildHeader(),
|
||||
// const SizedBox(height: 10,),
|
||||
Expanded(
|
||||
child: ListView(
|
||||
controller: listScrollController,
|
||||
padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 16),
|
||||
children: [
|
||||
SizedBox(height: 10,),
|
||||
Center(
|
||||
child: Stack(
|
||||
children: [
|
||||
InkWell(
|
||||
onTap: () {
|
||||
controller.getProfileImage();
|
||||
},
|
||||
child: Container(
|
||||
width: 100,
|
||||
// Set the size to match the CircleAvatar's diameter
|
||||
height: 100,
|
||||
decoration: BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
border: Border.all(
|
||||
color: ColorConstants.primaryColor, // Border color
|
||||
width: 2.0, // Border width
|
||||
),
|
||||
),
|
||||
child: CircleAvatar(
|
||||
radius: 30,
|
||||
backgroundColor: ColorConstants.secondaryColor,
|
||||
child: ClipOval(
|
||||
child: controller.profileImage == null
|
||||
? Image.asset(
|
||||
AssetConstants.noProfile,
|
||||
width: 70,
|
||||
height: 70,
|
||||
color: ColorConstants.primaryColor,
|
||||
)
|
||||
: Image.file(
|
||||
width: 100,
|
||||
height: 100,
|
||||
File(controller.profileImage?.path ?? ''),
|
||||
fit: BoxFit.cover,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
const Positioned(
|
||||
bottom: 0,
|
||||
right: 0,
|
||||
child: CircleAvatar(
|
||||
radius: 15,
|
||||
backgroundColor: ColorConstants.primaryColor,
|
||||
child: Icon(
|
||||
Icons.camera_alt_outlined,
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 8,
|
||||
),
|
||||
Center(
|
||||
child: TextWidget(
|
||||
text: 'Upload Company Logo',
|
||||
)),
|
||||
const SizedBox(height: 30,),
|
||||
_buildTextField(
|
||||
controller: controller.firstnameController,
|
||||
label: 'Contact Name',
|
||||
icon: Icons.person,
|
||||
formatters: [UpperCaseTextFormatter()],
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
_buildTextField(
|
||||
controller: controller.companyNameController,
|
||||
label: 'Company Name',
|
||||
icon: Icons.business,
|
||||
formatters: [UpperCaseTextFormatter()],
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
_buildTextField(
|
||||
controller: controller.emailController,
|
||||
label: 'Email',
|
||||
icon: Icons.email_outlined,
|
||||
validator: _validateEmail,
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
_buildSelectionField(
|
||||
context: context,
|
||||
label: controller.selectedCategoryName.isEmpty ? 'Select Category' : controller.selectedCategoryName,
|
||||
icon: Icons.category,
|
||||
onTap: () async {
|
||||
var result = await SubCategoryService().fetchSubCategories();
|
||||
if (result != null && result.details != null) {
|
||||
final categories = result.details!
|
||||
.map((e) => e.catgeoryname ?? '')
|
||||
.toSet()
|
||||
.toList();
|
||||
|
||||
if (context.mounted) {
|
||||
showModalBottomSheet(
|
||||
context: context,
|
||||
shape: const RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.vertical(top: Radius.circular(16)),
|
||||
),
|
||||
builder: (context) {
|
||||
return ListView.builder(
|
||||
itemCount: categories.length,
|
||||
itemBuilder: (context, index) {
|
||||
final categoryName = categories[index];
|
||||
return ListTile(
|
||||
title: Text(categoryName),
|
||||
trailing: controller.selectedCategoryName == categoryName
|
||||
? Icon(Icons.check, color: ColorConstants.primaryColor)
|
||||
: null,
|
||||
onTap: () {
|
||||
// Update controller
|
||||
controller.selectedCategoryName = categoryName;
|
||||
controller.update(); // Trigger UI rebuild
|
||||
Navigator.pop(context);
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
},
|
||||
),
|
||||
|
||||
|
||||
const SizedBox(height: 20),
|
||||
_buildTextField(
|
||||
controller: controller.gstinNumberController,
|
||||
label: 'GSTIN',
|
||||
icon: Icons.verified_user,
|
||||
),
|
||||
|
||||
const SizedBox(height: 20),
|
||||
|
||||
_buildAddressSection(context, controller),
|
||||
const SizedBox(height: 20),
|
||||
if (controller.isEnterAddress) ...[
|
||||
_buildTextField(controller: controller.suburbController, label: 'Suburb', icon: Icons.location_on),
|
||||
const SizedBox(height: 15),
|
||||
_buildTextField(controller: controller.cityController, label: 'City', icon: Icons.location_on),
|
||||
const SizedBox(height: 15),
|
||||
_buildTextField(controller: controller.stateController, label: 'State', icon: Icons.location_on),
|
||||
const SizedBox(height: 15),
|
||||
],
|
||||
_buildTextField(controller: controller.postcodeController, label: 'Pincode', icon: Icons.location_on),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
bottomNavigationBar: _buildBottomBar(controller),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildTextField({
|
||||
required TextEditingController controller,
|
||||
required String label,
|
||||
required IconData icon,
|
||||
List<TextInputFormatter>? formatters,
|
||||
String? Function(String?)? validator,
|
||||
}) {
|
||||
return Container(
|
||||
height: Get.height * 0.07,
|
||||
decoration: BoxDecoration(color: ColorConstants.secondaryColor),
|
||||
child: TextFormField(
|
||||
controller: controller,
|
||||
textCapitalization: TextCapitalization.sentences,
|
||||
inputFormatters: formatters,
|
||||
validator: validator,
|
||||
onFieldSubmitted: (_) {
|
||||
FocusManager.instance.primaryFocus?.unfocus(); // Removes focus and hides keyboard
|
||||
},
|
||||
style: const TextStyle(fontFamily: 'Inter'),
|
||||
decoration: CustomDecoration.textFieldStyle(labelTextStr: label, prefixIcon: Icon(icon, color: ColorConstants.darkGreyColor)),
|
||||
onEditingComplete: () => FocusScope.of(Get.context!).requestFocus(FocusNode()),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildSelectionField({
|
||||
required BuildContext context,
|
||||
required String label,
|
||||
required IconData icon,
|
||||
required VoidCallback onTap,
|
||||
}) {
|
||||
return InkWell(
|
||||
onTap: onTap,
|
||||
child: Container(
|
||||
height: 60,
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(5),
|
||||
border: Border.all(color: Colors.grey[200]!, width: 2),
|
||||
),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(left: 10),
|
||||
child: Row(
|
||||
children: [
|
||||
Icon(icon, color: ColorConstants.darkGreyColor),
|
||||
const SizedBox(width: 10),
|
||||
Expanded(child: Text(label, style: TextStyle(fontSize: 17, color: Colors.grey[500]))),
|
||||
Icon(Icons.arrow_drop_down, color: Colors.grey[600], size: 20),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
Widget _buildAddressSection(BuildContext context, CreateUserController controller) {
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
Icon(Icons.location_on, color: ColorConstants.darkGreyColor, size: 23),
|
||||
const SizedBox(width: 5),
|
||||
const Text('Address', style: TextStyle(color: Colors.black54, fontSize: 16)),
|
||||
const Spacer(),
|
||||
InkWell(
|
||||
onTap: () {
|
||||
// Toggle the isEnterAddress state if needed for other UI logic
|
||||
controller.isEnterAddress = !controller.isEnterAddress;
|
||||
controller.update();
|
||||
},
|
||||
child: Icon(
|
||||
controller.isEnterAddress ? Icons.check : Icons.keyboard_arrow_down_sharp,
|
||||
color: Colors.grey[600],
|
||||
size: 23,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 5),
|
||||
TextFormField(
|
||||
controller: controller.addressController,
|
||||
maxLines: 3,
|
||||
cursorColor: ColorConstants.textFieldColor,
|
||||
style: TextStyle(color: ColorConstants.textFieldColor),
|
||||
decoration: CustomDecoration.textFieldStyle(),
|
||||
readOnly: true, // Make it read-only to prevent direct editing
|
||||
onTap: () async {
|
||||
// Navigate to the address search screen and wait for the result
|
||||
final selectedAddress = await Get.to(() => AddressSearchScreen(controller: controller));
|
||||
if (selectedAddress != null) {
|
||||
controller.addressController.text = selectedAddress['description'];
|
||||
controller.getPlaceDetails(selectedAddress['place_id'], selectedAddress['description']);
|
||||
controller.update();
|
||||
}
|
||||
},
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Widget _buildBottomBar(CreateUserController controller) {
|
||||
return Container(
|
||||
height: Get.height * 0.1,
|
||||
child: RoundedButton(
|
||||
height: Get.height * 0.06,
|
||||
width: Get.width * 0.9,
|
||||
onPressed: controller.doSomething,
|
||||
color: ColorConstants.primaryColor,
|
||||
title: 'Create',
|
||||
controller: controller.btnController,
|
||||
textStyle: const TextStyle(fontSize: 18, fontFamily: 'Inter', color: Colors.white, fontWeight: FontWeight.bold),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
String? _validateEmail(String? value) {
|
||||
const simplePattern = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$';
|
||||
final regex = RegExp(simplePattern);
|
||||
return value!.isNotEmpty && !regex.hasMatch(value) ? 'Enter a valid email address' : null;
|
||||
}
|
||||
}
|
||||
|
||||
class UpperCaseTextFormatter extends TextInputFormatter {
|
||||
@override
|
||||
TextEditingValue formatEditUpdate(TextEditingValue oldValue, TextEditingValue newValue) {
|
||||
return TextEditingValue(text: capitalize(newValue.text), selection: newValue.selection);
|
||||
}
|
||||
}
|
||||
|
||||
String capitalize(String value) {
|
||||
if (value.trim().isEmpty) return '';
|
||||
return '${value[0].toUpperCase()}${value.substring(1)}';
|
||||
}
|
||||
|
||||
|
||||
class AddressSearchScreen extends StatelessWidget {
|
||||
final CreateUserController controller;
|
||||
|
||||
const AddressSearchScreen({Key? key, required this.controller}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
// Initialize a new TextEditingController with the initial address
|
||||
final searchController = TextEditingController(text: controller.addressController.text);
|
||||
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: TextWidget(
|
||||
text: 'Search Address',
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 20,
|
||||
),
|
||||
leading: IconButton(
|
||||
icon: Icon(Icons.arrow_back, color: ColorConstants.blackColor),
|
||||
onPressed: () => Get.back(), // Return without selecting an address
|
||||
),
|
||||
),
|
||||
body: Padding(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: Column(
|
||||
children: [
|
||||
TextFormField(
|
||||
controller: searchController,
|
||||
autofocus: true,
|
||||
cursorColor: ColorConstants.textFieldColor,
|
||||
style: TextStyle(color: ColorConstants.textFieldColor),
|
||||
decoration: CustomDecoration.textFieldStyle().copyWith(
|
||||
hintText: 'Enter address',
|
||||
suffixIcon: IconButton(
|
||||
icon: Icon(Icons.cancel, color: ColorConstants.blackColor),
|
||||
onPressed: () {
|
||||
searchController.clear(); // Clear the search field
|
||||
controller.predictions.clear(); // Clear predictions
|
||||
controller.update(); // Notify UI to update
|
||||
},
|
||||
),
|
||||
),
|
||||
onChanged: (text) {
|
||||
if (text.isEmpty) {
|
||||
controller.predictions.clear();
|
||||
controller.update();
|
||||
}
|
||||
controller.onSearchTextChanged(text);
|
||||
},
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Expanded(
|
||||
child: Obx(
|
||||
() => controller.predictions.isEmpty
|
||||
? const Center(child: Text('No results found'))
|
||||
: ListView.builder(
|
||||
itemCount: controller.predictions.length,
|
||||
itemBuilder: (context, index) {
|
||||
final prediction = controller.predictions[index]['description'];
|
||||
return ListTile(
|
||||
title: Text(prediction),
|
||||
onTap: () {
|
||||
final selectedAddress = controller.predictions[index];
|
||||
controller.addressController.text = selectedAddress['description'];
|
||||
controller.getPlaceDetails(selectedAddress['place_id'], selectedAddress['description']);
|
||||
Get.back(result: selectedAddress);
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user