fix update page
This commit is contained in:
@@ -632,6 +632,7 @@
|
|||||||
ENABLE_BITCODE = NO;
|
ENABLE_BITCODE = NO;
|
||||||
INFOPLIST_FILE = Runner/Info.plist;
|
INFOPLIST_FILE = Runner/Info.plist;
|
||||||
INFOPLIST_KEY_CFBundleDisplayName = "DBIZ Partner";
|
INFOPLIST_KEY_CFBundleDisplayName = "DBIZ Partner";
|
||||||
|
IPHONEOS_DEPLOYMENT_TARGET = 15;
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
@@ -934,6 +935,7 @@
|
|||||||
ENABLE_BITCODE = NO;
|
ENABLE_BITCODE = NO;
|
||||||
INFOPLIST_FILE = Runner/Info.plist;
|
INFOPLIST_FILE = Runner/Info.plist;
|
||||||
INFOPLIST_KEY_CFBundleDisplayName = "DBIZ Partner";
|
INFOPLIST_KEY_CFBundleDisplayName = "DBIZ Partner";
|
||||||
|
IPHONEOS_DEPLOYMENT_TARGET = 15;
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
@@ -959,6 +961,7 @@
|
|||||||
ENABLE_BITCODE = NO;
|
ENABLE_BITCODE = NO;
|
||||||
INFOPLIST_FILE = Runner/Info.plist;
|
INFOPLIST_FILE = Runner/Info.plist;
|
||||||
INFOPLIST_KEY_CFBundleDisplayName = "DBIZ Partner";
|
INFOPLIST_KEY_CFBundleDisplayName = "DBIZ Partner";
|
||||||
|
IPHONEOS_DEPLOYMENT_TARGET = 15;
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
|
|||||||
@@ -53,10 +53,14 @@ class _SubmissionCreatePageState extends ConsumerState<SubmissionCreatePage> {
|
|||||||
bool _isSubmitting = false;
|
bool _isSubmitting = false;
|
||||||
bool _isLoadingDetail = false;
|
bool _isLoadingDetail = false;
|
||||||
String? _deletingFileId; // Track which file is being deleted
|
String? _deletingFileId; // Track which file is being deleted
|
||||||
|
bool _isAllowModify = true; // From API detail response
|
||||||
|
|
||||||
/// Whether we're editing an existing submission
|
/// Whether we're editing an existing submission
|
||||||
bool get isEditing => widget.submission != null;
|
bool get isEditing => widget.submission != null;
|
||||||
|
|
||||||
|
/// Whether the form is read-only (editing but not allowed to modify)
|
||||||
|
bool get isReadOnly => isEditing && !_isAllowModify;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
@@ -101,6 +105,9 @@ class _SubmissionCreatePageState extends ConsumerState<SubmissionCreatePage> {
|
|||||||
|
|
||||||
// Set existing files from API
|
// Set existing files from API
|
||||||
_existingFiles = detail.filesList;
|
_existingFiles = detail.filesList;
|
||||||
|
|
||||||
|
// Set modify permission from API
|
||||||
|
_isAllowModify = detail.isAllowModify;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (mounted) {
|
if (mounted) {
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
@@ -146,7 +153,11 @@ class _SubmissionCreatePageState extends ConsumerState<SubmissionCreatePage> {
|
|||||||
onPressed: () => Navigator.of(context).pop(),
|
onPressed: () => Navigator.of(context).pop(),
|
||||||
),
|
),
|
||||||
title: Text(
|
title: Text(
|
||||||
isEditing ? 'Chỉnh sửa Dự án' : 'Đăng ký Công trình',
|
isReadOnly
|
||||||
|
? 'Chi tiết Dự án'
|
||||||
|
: isEditing
|
||||||
|
? 'Chỉnh sửa Dự án'
|
||||||
|
: 'Đăng ký Công trình',
|
||||||
style: TextStyle(color: colorScheme.onSurface),
|
style: TextStyle(color: colorScheme.onSurface),
|
||||||
),
|
),
|
||||||
actions: [
|
actions: [
|
||||||
@@ -197,10 +208,12 @@ class _SubmissionCreatePageState extends ConsumerState<SubmissionCreatePage> {
|
|||||||
|
|
||||||
// File Upload
|
// File Upload
|
||||||
_buildFileUploadCard(colorScheme),
|
_buildFileUploadCard(colorScheme),
|
||||||
const SizedBox(height: 24),
|
|
||||||
|
|
||||||
// Submit Button
|
// Submit Button - only show when not read-only
|
||||||
_buildSubmitButton(colorScheme),
|
if (!isReadOnly) ...[
|
||||||
|
const SizedBox(height: 24),
|
||||||
|
_buildSubmitButton(colorScheme),
|
||||||
|
],
|
||||||
const SizedBox(height: 40),
|
const SizedBox(height: 40),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@@ -376,49 +389,50 @@ class _SubmissionCreatePageState extends ConsumerState<SubmissionCreatePage> {
|
|||||||
),
|
),
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
|
|
||||||
// Upload Area
|
// Upload Area - only show when not read-only
|
||||||
InkWell(
|
if (!isReadOnly)
|
||||||
onTap: _pickFiles,
|
InkWell(
|
||||||
borderRadius: BorderRadius.circular(8),
|
onTap: _pickFiles,
|
||||||
child: Container(
|
borderRadius: BorderRadius.circular(8),
|
||||||
padding: const EdgeInsets.symmetric(vertical: 40, horizontal: 20),
|
child: Container(
|
||||||
width: double.infinity,
|
padding: const EdgeInsets.symmetric(vertical: 40, horizontal: 20),
|
||||||
decoration: BoxDecoration(
|
width: double.infinity,
|
||||||
border: Border.all(
|
decoration: BoxDecoration(
|
||||||
color: colorScheme.surfaceContainerHighest,
|
border: Border.all(
|
||||||
width: 2,
|
color: colorScheme.surfaceContainerHighest,
|
||||||
style: BorderStyle.solid,
|
width: 2,
|
||||||
|
style: BorderStyle.solid,
|
||||||
|
),
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
),
|
),
|
||||||
borderRadius: BorderRadius.circular(8),
|
child: Column(
|
||||||
),
|
children: [
|
||||||
child: Column(
|
FaIcon(
|
||||||
children: [
|
FontAwesomeIcons.cloudArrowUp,
|
||||||
FaIcon(
|
size: 48,
|
||||||
FontAwesomeIcons.cloudArrowUp,
|
|
||||||
size: 48,
|
|
||||||
color: colorScheme.onSurfaceVariant,
|
|
||||||
),
|
|
||||||
const SizedBox(height: 12),
|
|
||||||
Text(
|
|
||||||
'Kéo thả ảnh vào đây',
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 16,
|
|
||||||
fontWeight: FontWeight.w500,
|
|
||||||
color: colorScheme.onSurface,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(height: 4),
|
|
||||||
Text(
|
|
||||||
'hoặc nhấn để chọn file',
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 14,
|
|
||||||
color: colorScheme.onSurfaceVariant,
|
color: colorScheme.onSurfaceVariant,
|
||||||
),
|
),
|
||||||
),
|
const SizedBox(height: 12),
|
||||||
],
|
Text(
|
||||||
|
'Kéo thả ảnh vào đây',
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 16,
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
color: colorScheme.onSurface,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 4),
|
||||||
|
Text(
|
||||||
|
'hoặc nhấn để chọn file',
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 14,
|
||||||
|
color: colorScheme.onSurfaceVariant,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
|
||||||
|
|
||||||
// Existing files from API
|
// Existing files from API
|
||||||
if (_existingFiles.isNotEmpty) ...[
|
if (_existingFiles.isNotEmpty) ...[
|
||||||
@@ -488,7 +502,9 @@ class _SubmissionCreatePageState extends ConsumerState<SubmissionCreatePage> {
|
|||||||
int maxLines = 1,
|
int maxLines = 1,
|
||||||
TextInputType? keyboardType,
|
TextInputType? keyboardType,
|
||||||
String? helperText,
|
String? helperText,
|
||||||
|
bool? readOnly,
|
||||||
}) {
|
}) {
|
||||||
|
final isFieldReadOnly = readOnly ?? isReadOnly;
|
||||||
return Column(
|
return Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
@@ -517,11 +533,12 @@ class _SubmissionCreatePageState extends ConsumerState<SubmissionCreatePage> {
|
|||||||
controller: controller,
|
controller: controller,
|
||||||
maxLines: maxLines,
|
maxLines: maxLines,
|
||||||
keyboardType: keyboardType,
|
keyboardType: keyboardType,
|
||||||
|
readOnly: isFieldReadOnly,
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
hintText: hint,
|
hintText: hint,
|
||||||
hintStyle: TextStyle(color: colorScheme.onSurfaceVariant),
|
hintStyle: TextStyle(color: colorScheme.onSurfaceVariant),
|
||||||
filled: true,
|
filled: true,
|
||||||
fillColor: colorScheme.surface,
|
fillColor: isFieldReadOnly ? colorScheme.surfaceContainerHighest : colorScheme.surface,
|
||||||
border: OutlineInputBorder(
|
border: OutlineInputBorder(
|
||||||
borderRadius: BorderRadius.circular(8),
|
borderRadius: BorderRadius.circular(8),
|
||||||
borderSide: BorderSide(color: colorScheme.surfaceContainerHighest),
|
borderSide: BorderSide(color: colorScheme.surfaceContainerHighest),
|
||||||
@@ -594,10 +611,10 @@ class _SubmissionCreatePageState extends ConsumerState<SubmissionCreatePage> {
|
|||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
progressListAsync.when(
|
progressListAsync.when(
|
||||||
data: (progressList) => DropdownButtonFormField<ProjectProgress>(
|
data: (progressList) => DropdownButtonFormField<ProjectProgress>(
|
||||||
initialValue: _selectedProgress,
|
value: _selectedProgress,
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
filled: true,
|
filled: true,
|
||||||
fillColor: colorScheme.surface,
|
fillColor: isReadOnly ? colorScheme.surfaceContainerHighest : colorScheme.surface,
|
||||||
border: OutlineInputBorder(
|
border: OutlineInputBorder(
|
||||||
borderRadius: BorderRadius.circular(8),
|
borderRadius: BorderRadius.circular(8),
|
||||||
borderSide: BorderSide(color: colorScheme.surfaceContainerHighest),
|
borderSide: BorderSide(color: colorScheme.surfaceContainerHighest),
|
||||||
@@ -618,11 +635,13 @@ class _SubmissionCreatePageState extends ConsumerState<SubmissionCreatePage> {
|
|||||||
child: Text(progress.status),
|
child: Text(progress.status),
|
||||||
))
|
))
|
||||||
.toList(),
|
.toList(),
|
||||||
onChanged: (value) {
|
onChanged: isReadOnly
|
||||||
setState(() {
|
? null
|
||||||
_selectedProgress = value;
|
: (value) {
|
||||||
});
|
setState(() {
|
||||||
},
|
_selectedProgress = value;
|
||||||
|
});
|
||||||
|
},
|
||||||
validator: (value) {
|
validator: (value) {
|
||||||
if (value == null) {
|
if (value == null) {
|
||||||
return 'Vui lòng chọn tiến độ công trình';
|
return 'Vui lòng chọn tiến độ công trình';
|
||||||
@@ -692,11 +711,11 @@ class _SubmissionCreatePageState extends ConsumerState<SubmissionCreatePage> {
|
|||||||
),
|
),
|
||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
InkWell(
|
InkWell(
|
||||||
onTap: _pickExpectedDate,
|
onTap: isReadOnly ? null : _pickExpectedDate,
|
||||||
child: Container(
|
child: Container(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
|
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: colorScheme.surface,
|
color: isReadOnly ? colorScheme.surfaceContainerHighest : colorScheme.surface,
|
||||||
border: Border.all(color: colorScheme.surfaceContainerHighest),
|
border: Border.all(color: colorScheme.surfaceContainerHighest),
|
||||||
borderRadius: BorderRadius.circular(8),
|
borderRadius: BorderRadius.circular(8),
|
||||||
),
|
),
|
||||||
@@ -847,8 +866,8 @@ class _SubmissionCreatePageState extends ConsumerState<SubmissionCreatePage> {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
// Only show remove button when not uploading
|
// Only show remove button when not uploading and not read-only
|
||||||
if (!_isSubmitting)
|
if (!_isSubmitting && !isReadOnly)
|
||||||
IconButton(
|
IconButton(
|
||||||
icon: const FaIcon(
|
icon: const FaIcon(
|
||||||
FontAwesomeIcons.xmark,
|
FontAwesomeIcons.xmark,
|
||||||
@@ -961,8 +980,8 @@ class _SubmissionCreatePageState extends ConsumerState<SubmissionCreatePage> {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
// Delete button or checkmark
|
// Delete button or checkmark - only show delete when not read-only
|
||||||
if (!_isSubmitting && !isDeleting)
|
if (!_isSubmitting && !isDeleting && !isReadOnly)
|
||||||
IconButton(
|
IconButton(
|
||||||
icon: const FaIcon(
|
icon: const FaIcon(
|
||||||
FontAwesomeIcons.trash,
|
FontAwesomeIcons.trash,
|
||||||
@@ -1166,10 +1185,19 @@ class _SubmissionCreatePageState extends ConsumerState<SubmissionCreatePage> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _pickExpectedDate() async {
|
Future<void> _pickExpectedDate() async {
|
||||||
|
final now = DateTime.now();
|
||||||
|
final today = DateTime(now.year, now.month, now.day);
|
||||||
|
|
||||||
|
// For editing mode with past date, allow selecting from that date
|
||||||
|
// Otherwise, start from today
|
||||||
|
final firstDate = (_expectedStartDate != null && _expectedStartDate!.isBefore(today))
|
||||||
|
? _expectedStartDate!
|
||||||
|
: today;
|
||||||
|
|
||||||
final date = await showDatePicker(
|
final date = await showDatePicker(
|
||||||
context: context,
|
context: context,
|
||||||
initialDate: _expectedStartDate ?? DateTime.now(),
|
initialDate: _expectedStartDate ?? today,
|
||||||
firstDate: DateTime.now(),
|
firstDate: firstDate,
|
||||||
lastDate: DateTime.now().add(const Duration(days: 365 * 3)),
|
lastDate: DateTime.now().add(const Duration(days: 365 * 3)),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
|
|||||||
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
|
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
|
||||||
# In Windows, build-name is used as the major, minor, and patch parts
|
# In Windows, build-name is used as the major, minor, and patch parts
|
||||||
# of the product and file versions while build-number is used as the build suffix.
|
# of the product and file versions while build-number is used as the build suffix.
|
||||||
version: 1.0.1+23
|
version: 1.0.1+24
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
sdk: ^3.10.0
|
sdk: ^3.10.0
|
||||||
|
|||||||
Reference in New Issue
Block a user