Merge remote-tracking branch 'origin/refactor_dark_mood_repository'
This commit is contained in:
@@ -1,8 +1,14 @@
|
|||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
import 'package:provider/single_child_widget.dart';
|
import 'package:provider/single_child_widget.dart';
|
||||||
import 'package:tm_app/core/theme/theme_provider.dart';
|
import 'package:tm_app/core/theme/theme_provider.dart';
|
||||||
|
<<<<<<< HEAD
|
||||||
import 'package:tm_app/data/repositories/home_repository.dart';
|
import 'package:tm_app/data/repositories/home_repository.dart';
|
||||||
import 'package:tm_app/data/services/home_service.dart';
|
import 'package:tm_app/data/services/home_service.dart';
|
||||||
|
=======
|
||||||
|
import 'package:tm_app/data/repositories/tender_detail_repository.dart';
|
||||||
|
import 'package:tm_app/data/services/tender_detail_service.dart';
|
||||||
|
import 'package:tm_app/view_models/tender_detail_view_model.dart';
|
||||||
|
>>>>>>> origin/refactor_dark_mood_repository
|
||||||
|
|
||||||
import '../../data/repositories/auth_repository.dart';
|
import '../../data/repositories/auth_repository.dart';
|
||||||
import '../../data/services/auth_service.dart';
|
import '../../data/services/auth_service.dart';
|
||||||
@@ -25,13 +31,16 @@ List<SingleChildWidget> get apiClients {
|
|||||||
return [
|
return [
|
||||||
Provider(create: (context) => AuthService(networkManager: context.read())),
|
Provider(create: (context) => AuthService(networkManager: context.read())),
|
||||||
Provider(create: (context) => HomeService(networkManager: context.read())),
|
Provider(create: (context) => HomeService(networkManager: context.read())),
|
||||||
|
Provider(create: (context) => TenderDetailService(networkManager: context.read())),
|
||||||
];
|
];
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
List<SingleChildWidget> get repositories {
|
List<SingleChildWidget> get repositories {
|
||||||
return [
|
return [
|
||||||
Provider(create: (context) => AuthRepository(authService: context.read())),
|
Provider(create: (context) => AuthRepository(authService: context.read())),
|
||||||
Provider(create: (context) => HomeRepository(homeService: context.read())),
|
Provider(create: (context) => HomeRepository(homeService: context.read())),
|
||||||
|
Provider(create: (context) => TenderDetailRepository(tenderDetailService: context.read())),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -42,7 +51,11 @@ List<SingleChildWidget> get viewModels {
|
|||||||
),
|
),
|
||||||
ChangeNotifierProvider(
|
ChangeNotifierProvider(
|
||||||
create: (context) => HomeViewModel(homeRepository: context.read()),
|
create: (context) => HomeViewModel(homeRepository: context.read()),
|
||||||
|
|
||||||
),
|
),
|
||||||
|
ChangeNotifierProvider(
|
||||||
|
create: (context) => TenderDetailViewModel(tenderDetailRepository: context.read()),
|
||||||
|
),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:go_router/go_router.dart';
|
import 'package:go_router/go_router.dart';
|
||||||
import 'package:tm_app/views/detail/detail_screen.dart';
|
import 'package:tm_app/views/detail/pages/detail_screen.dart';
|
||||||
import 'package:tm_app/views/home/pages/home_screen.dart';
|
import 'package:tm_app/views/home/pages/home_screen.dart';
|
||||||
import 'package:tm_app/views/login/login_screen.dart';
|
import 'package:tm_app/views/login/pages/login_screen.dart';
|
||||||
|
|
||||||
import '../../views/profile/profile_screen.dart';
|
import '../../views/profile/profile_screen.dart';
|
||||||
import '../../views/tenders/tenders_screen.dart';
|
import '../../views/tenders/tenders_screen.dart';
|
||||||
|
|||||||
@@ -121,6 +121,7 @@ class AppColors {
|
|||||||
// Red variations (status colors)
|
// Red variations (status colors)
|
||||||
static const Color red0 = Color(0xFFF8D6D6);
|
static const Color red0 = Color(0xFFF8D6D6);
|
||||||
static const Color red10 = Color(0xFFC02525);
|
static const Color red10 = Color(0xFFC02525);
|
||||||
|
static const Color red = Color(0xFFFF3B30);
|
||||||
|
|
||||||
// Other colors
|
// Other colors
|
||||||
static const Color paleOrange = Color(0xFFfff7ee);
|
static const Color paleOrange = Color(0xFFfff7ee);
|
||||||
|
|||||||
@@ -0,0 +1,18 @@
|
|||||||
|
import 'package:tm_app/core/utils/result.dart';
|
||||||
|
import 'package:tm_app/data/services/model/tender_detail_request/tender_detail_request.dart';
|
||||||
|
import 'package:tm_app/data/services/model/tender_detail_response/tender_detail_response_model.dart';
|
||||||
|
import 'package:tm_app/data/services/tender_detail_service.dart';
|
||||||
|
|
||||||
|
class TenderDetailRepository {
|
||||||
|
TenderDetailRepository({required TenderDetailService tenderDetailService})
|
||||||
|
: _tenderDetailService = tenderDetailService;
|
||||||
|
|
||||||
|
final TenderDetailService _tenderDetailService;
|
||||||
|
|
||||||
|
Future<Result<TenderDetailResponseModel>> getTenderDetail({
|
||||||
|
required TenderDetailRequest request,
|
||||||
|
}) async {
|
||||||
|
return await _tenderDetailService.getTenderDetail(request: request);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
const tenderDetailMockData = '''
|
||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"date": "2025-05-21",
|
||||||
|
"status": "Open",
|
||||||
|
"title": "Operation, support and further development of open e-platform Operation, support and further development of open e-platform",
|
||||||
|
"id": "JNDFKMDV-100JF",
|
||||||
|
"approvalDate": "2025-05-21",
|
||||||
|
"submissionDate": "2025-05-21",
|
||||||
|
"client": "Procurement Notice Procurement NoticeProcurement Notice",
|
||||||
|
"deliveryLocation": "Norrbotten County",
|
||||||
|
"referenceNumber": "KLF 2025/120",
|
||||||
|
"country": "UK",
|
||||||
|
"flagAsset": "assets/icons/SE.png",
|
||||||
|
"locationTitle": "Lorem ipsum is amet",
|
||||||
|
"locationDescription": "Luleå Municipality is procuring on behalf of Norrbotten’s e-board (all municipalities in Norrbotten). The procurement includes operation, support, and further development of the existing open e-platform. No additional information, amendments, or answers to questions will be provided after June 16.",
|
||||||
|
"documentName": "PDF, Document",
|
||||||
|
"documentUrl": "https://www.tenders.com",
|
||||||
|
"profileMatch": 0.75,
|
||||||
|
"incompleteResume": true,
|
||||||
|
"incompleteResumeReason": "No experience in e-platform development"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
''';
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
// ignore_for_file: invalid_annotation_target
|
||||||
|
|
||||||
|
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||||
|
|
||||||
|
part 'tender_detail_request.freezed.dart';
|
||||||
|
part 'tender_detail_request.g.dart';
|
||||||
|
|
||||||
|
@freezed
|
||||||
|
class TenderDetailRequest with _$TenderDetailRequest {
|
||||||
|
const factory TenderDetailRequest({
|
||||||
|
@JsonKey(name: 'id') required String id,
|
||||||
|
}) = _TenderDetailRequest;
|
||||||
|
|
||||||
|
factory TenderDetailRequest.fromJson(Map<String, dynamic> json) =>
|
||||||
|
_$TenderDetailRequestFromJson(json);
|
||||||
|
}
|
||||||
@@ -0,0 +1,177 @@
|
|||||||
|
// coverage:ignore-file
|
||||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
// ignore_for_file: type=lint
|
||||||
|
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
|
||||||
|
|
||||||
|
part of 'tender_detail_request.dart';
|
||||||
|
|
||||||
|
// **************************************************************************
|
||||||
|
// FreezedGenerator
|
||||||
|
// **************************************************************************
|
||||||
|
|
||||||
|
T _$identity<T>(T value) => value;
|
||||||
|
|
||||||
|
final _privateConstructorUsedError = UnsupportedError(
|
||||||
|
'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models',
|
||||||
|
);
|
||||||
|
|
||||||
|
TenderDetailRequest _$TenderDetailRequestFromJson(Map<String, dynamic> json) {
|
||||||
|
return _TenderDetailRequest.fromJson(json);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
mixin _$TenderDetailRequest {
|
||||||
|
@JsonKey(name: "id")
|
||||||
|
String get id => throw _privateConstructorUsedError;
|
||||||
|
|
||||||
|
/// Serializes this TenderDetailRequest to a JSON map.
|
||||||
|
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
||||||
|
|
||||||
|
/// Create a copy of TenderDetailRequest
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
|
$TenderDetailRequestCopyWith<TenderDetailRequest> get copyWith =>
|
||||||
|
throw _privateConstructorUsedError;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
abstract class $TenderDetailRequestCopyWith<$Res> {
|
||||||
|
factory $TenderDetailRequestCopyWith(
|
||||||
|
TenderDetailRequest value,
|
||||||
|
$Res Function(TenderDetailRequest) then,
|
||||||
|
) = _$TenderDetailRequestCopyWithImpl<$Res, TenderDetailRequest>;
|
||||||
|
@useResult
|
||||||
|
$Res call({@JsonKey(name: "id") String id});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
class _$TenderDetailRequestCopyWithImpl<$Res, $Val extends TenderDetailRequest>
|
||||||
|
implements $TenderDetailRequestCopyWith<$Res> {
|
||||||
|
_$TenderDetailRequestCopyWithImpl(this._value, this._then);
|
||||||
|
|
||||||
|
// ignore: unused_field
|
||||||
|
final $Val _value;
|
||||||
|
// ignore: unused_field
|
||||||
|
final $Res Function($Val) _then;
|
||||||
|
|
||||||
|
/// Create a copy of TenderDetailRequest
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@pragma('vm:prefer-inline')
|
||||||
|
@override
|
||||||
|
$Res call({Object? id = null}) {
|
||||||
|
return _then(
|
||||||
|
_value.copyWith(
|
||||||
|
id:
|
||||||
|
null == id
|
||||||
|
? _value.id
|
||||||
|
: id // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String,
|
||||||
|
)
|
||||||
|
as $Val,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
abstract class _$$TenderDetailRequestImplCopyWith<$Res>
|
||||||
|
implements $TenderDetailRequestCopyWith<$Res> {
|
||||||
|
factory _$$TenderDetailRequestImplCopyWith(
|
||||||
|
_$TenderDetailRequestImpl value,
|
||||||
|
$Res Function(_$TenderDetailRequestImpl) then,
|
||||||
|
) = __$$TenderDetailRequestImplCopyWithImpl<$Res>;
|
||||||
|
@override
|
||||||
|
@useResult
|
||||||
|
$Res call({@JsonKey(name: "id") String id});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
class __$$TenderDetailRequestImplCopyWithImpl<$Res>
|
||||||
|
extends _$TenderDetailRequestCopyWithImpl<$Res, _$TenderDetailRequestImpl>
|
||||||
|
implements _$$TenderDetailRequestImplCopyWith<$Res> {
|
||||||
|
__$$TenderDetailRequestImplCopyWithImpl(
|
||||||
|
_$TenderDetailRequestImpl _value,
|
||||||
|
$Res Function(_$TenderDetailRequestImpl) _then,
|
||||||
|
) : super(_value, _then);
|
||||||
|
|
||||||
|
/// Create a copy of TenderDetailRequest
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@pragma('vm:prefer-inline')
|
||||||
|
@override
|
||||||
|
$Res call({Object? id = null}) {
|
||||||
|
return _then(
|
||||||
|
_$TenderDetailRequestImpl(
|
||||||
|
id:
|
||||||
|
null == id
|
||||||
|
? _value.id
|
||||||
|
: id // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
@JsonSerializable()
|
||||||
|
class _$TenderDetailRequestImpl implements _TenderDetailRequest {
|
||||||
|
const _$TenderDetailRequestImpl({@JsonKey(name: "id") required this.id});
|
||||||
|
|
||||||
|
factory _$TenderDetailRequestImpl.fromJson(Map<String, dynamic> json) =>
|
||||||
|
_$$TenderDetailRequestImplFromJson(json);
|
||||||
|
|
||||||
|
@override
|
||||||
|
@JsonKey(name: "id")
|
||||||
|
final String id;
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return 'TenderDetailRequest(id: $id)';
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) {
|
||||||
|
return identical(this, other) ||
|
||||||
|
(other.runtimeType == runtimeType &&
|
||||||
|
other is _$TenderDetailRequestImpl &&
|
||||||
|
(identical(other.id, id) || other.id == id));
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
|
@override
|
||||||
|
int get hashCode => Object.hash(runtimeType, id);
|
||||||
|
|
||||||
|
/// Create a copy of TenderDetailRequest
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
|
@override
|
||||||
|
@pragma('vm:prefer-inline')
|
||||||
|
_$$TenderDetailRequestImplCopyWith<_$TenderDetailRequestImpl> get copyWith =>
|
||||||
|
__$$TenderDetailRequestImplCopyWithImpl<_$TenderDetailRequestImpl>(
|
||||||
|
this,
|
||||||
|
_$identity,
|
||||||
|
);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
return _$$TenderDetailRequestImplToJson(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class _TenderDetailRequest implements TenderDetailRequest {
|
||||||
|
const factory _TenderDetailRequest({
|
||||||
|
@JsonKey(name: "id") required final String id,
|
||||||
|
}) = _$TenderDetailRequestImpl;
|
||||||
|
|
||||||
|
factory _TenderDetailRequest.fromJson(Map<String, dynamic> json) =
|
||||||
|
_$TenderDetailRequestImpl.fromJson;
|
||||||
|
|
||||||
|
@override
|
||||||
|
@JsonKey(name: "id")
|
||||||
|
String get id;
|
||||||
|
|
||||||
|
/// Create a copy of TenderDetailRequest
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@override
|
||||||
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
|
_$$TenderDetailRequestImplCopyWith<_$TenderDetailRequestImpl> get copyWith =>
|
||||||
|
throw _privateConstructorUsedError;
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
|
||||||
|
part of 'tender_detail_request.dart';
|
||||||
|
|
||||||
|
// **************************************************************************
|
||||||
|
// JsonSerializableGenerator
|
||||||
|
// **************************************************************************
|
||||||
|
|
||||||
|
_$TenderDetailRequestImpl _$$TenderDetailRequestImplFromJson(
|
||||||
|
Map<String, dynamic> json,
|
||||||
|
) => _$TenderDetailRequestImpl(id: json['id'] as String);
|
||||||
|
|
||||||
|
Map<String, dynamic> _$$TenderDetailRequestImplToJson(
|
||||||
|
_$TenderDetailRequestImpl instance,
|
||||||
|
) => <String, dynamic>{'id': instance.id};
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
// ignore_for_file: invalid_annotation_target
|
||||||
|
|
||||||
|
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||||
|
|
||||||
|
part 'tender_detail_response_model.freezed.dart';
|
||||||
|
part 'tender_detail_response_model.g.dart';
|
||||||
|
|
||||||
|
@freezed
|
||||||
|
class TenderDetailResponseModel with _$TenderDetailResponseModel {
|
||||||
|
@JsonSerializable(explicitToJson: true)
|
||||||
|
const factory TenderDetailResponseModel({
|
||||||
|
required String? date,
|
||||||
|
required String? status,
|
||||||
|
required String? title,
|
||||||
|
required String? id,
|
||||||
|
required String? approvalDate,
|
||||||
|
required String? submissionDate,
|
||||||
|
required String? client,
|
||||||
|
required String? deliveryLocation,
|
||||||
|
required String? referenceNumber,
|
||||||
|
required String? country,
|
||||||
|
required String? flagAsset,
|
||||||
|
required String? locationTitle,
|
||||||
|
required String? locationDescription,
|
||||||
|
required String? documentName,
|
||||||
|
required String? documentUrl,
|
||||||
|
required double? profileMatch,
|
||||||
|
required bool? incompleteResume,
|
||||||
|
required String? incompleteResumeReason,
|
||||||
|
}) = _TenderDetailResponseModel;
|
||||||
|
|
||||||
|
factory TenderDetailResponseModel.fromJson(Map<String, dynamic> json) =>
|
||||||
|
_$TenderDetailResponseModelFromJson(json);
|
||||||
|
}
|
||||||
+599
@@ -0,0 +1,599 @@
|
|||||||
|
// coverage:ignore-file
|
||||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
// ignore_for_file: type=lint
|
||||||
|
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
|
||||||
|
|
||||||
|
part of 'tender_detail_response_model.dart';
|
||||||
|
|
||||||
|
// **************************************************************************
|
||||||
|
// FreezedGenerator
|
||||||
|
// **************************************************************************
|
||||||
|
|
||||||
|
T _$identity<T>(T value) => value;
|
||||||
|
|
||||||
|
final _privateConstructorUsedError = UnsupportedError(
|
||||||
|
'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models',
|
||||||
|
);
|
||||||
|
|
||||||
|
TenderDetailResponseModel _$TenderDetailResponseModelFromJson(
|
||||||
|
Map<String, dynamic> json,
|
||||||
|
) {
|
||||||
|
return _TenderDetailResponseModel.fromJson(json);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
mixin _$TenderDetailResponseModel {
|
||||||
|
String? get date => throw _privateConstructorUsedError;
|
||||||
|
String? get status => throw _privateConstructorUsedError;
|
||||||
|
String? get title => throw _privateConstructorUsedError;
|
||||||
|
String? get id => throw _privateConstructorUsedError;
|
||||||
|
String? get approvalDate => throw _privateConstructorUsedError;
|
||||||
|
String? get submissionDate => throw _privateConstructorUsedError;
|
||||||
|
String? get client => throw _privateConstructorUsedError;
|
||||||
|
String? get deliveryLocation => throw _privateConstructorUsedError;
|
||||||
|
String? get referenceNumber => throw _privateConstructorUsedError;
|
||||||
|
String? get country => throw _privateConstructorUsedError;
|
||||||
|
String? get flagAsset => throw _privateConstructorUsedError;
|
||||||
|
String? get locationTitle => throw _privateConstructorUsedError;
|
||||||
|
String? get locationDescription => throw _privateConstructorUsedError;
|
||||||
|
String? get documentName => throw _privateConstructorUsedError;
|
||||||
|
String? get documentUrl => throw _privateConstructorUsedError;
|
||||||
|
double? get profileMatch => throw _privateConstructorUsedError;
|
||||||
|
bool? get incompleteResume => throw _privateConstructorUsedError;
|
||||||
|
String? get incompleteResumeReason => throw _privateConstructorUsedError;
|
||||||
|
|
||||||
|
/// Serializes this TenderDetailResponseModel to a JSON map.
|
||||||
|
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
||||||
|
|
||||||
|
/// Create a copy of TenderDetailResponseModel
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
|
$TenderDetailResponseModelCopyWith<TenderDetailResponseModel> get copyWith =>
|
||||||
|
throw _privateConstructorUsedError;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
abstract class $TenderDetailResponseModelCopyWith<$Res> {
|
||||||
|
factory $TenderDetailResponseModelCopyWith(
|
||||||
|
TenderDetailResponseModel value,
|
||||||
|
$Res Function(TenderDetailResponseModel) then,
|
||||||
|
) = _$TenderDetailResponseModelCopyWithImpl<$Res, TenderDetailResponseModel>;
|
||||||
|
@useResult
|
||||||
|
$Res call({
|
||||||
|
String? date,
|
||||||
|
String? status,
|
||||||
|
String? title,
|
||||||
|
String? id,
|
||||||
|
String? approvalDate,
|
||||||
|
String? submissionDate,
|
||||||
|
String? client,
|
||||||
|
String? deliveryLocation,
|
||||||
|
String? referenceNumber,
|
||||||
|
String? country,
|
||||||
|
String? flagAsset,
|
||||||
|
String? locationTitle,
|
||||||
|
String? locationDescription,
|
||||||
|
String? documentName,
|
||||||
|
String? documentUrl,
|
||||||
|
double? profileMatch,
|
||||||
|
bool? incompleteResume,
|
||||||
|
String? incompleteResumeReason,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
class _$TenderDetailResponseModelCopyWithImpl<
|
||||||
|
$Res,
|
||||||
|
$Val extends TenderDetailResponseModel
|
||||||
|
>
|
||||||
|
implements $TenderDetailResponseModelCopyWith<$Res> {
|
||||||
|
_$TenderDetailResponseModelCopyWithImpl(this._value, this._then);
|
||||||
|
|
||||||
|
// ignore: unused_field
|
||||||
|
final $Val _value;
|
||||||
|
// ignore: unused_field
|
||||||
|
final $Res Function($Val) _then;
|
||||||
|
|
||||||
|
/// Create a copy of TenderDetailResponseModel
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@pragma('vm:prefer-inline')
|
||||||
|
@override
|
||||||
|
$Res call({
|
||||||
|
Object? date = freezed,
|
||||||
|
Object? status = freezed,
|
||||||
|
Object? title = freezed,
|
||||||
|
Object? id = freezed,
|
||||||
|
Object? approvalDate = freezed,
|
||||||
|
Object? submissionDate = freezed,
|
||||||
|
Object? client = freezed,
|
||||||
|
Object? deliveryLocation = freezed,
|
||||||
|
Object? referenceNumber = freezed,
|
||||||
|
Object? country = freezed,
|
||||||
|
Object? flagAsset = freezed,
|
||||||
|
Object? locationTitle = freezed,
|
||||||
|
Object? locationDescription = freezed,
|
||||||
|
Object? documentName = freezed,
|
||||||
|
Object? documentUrl = freezed,
|
||||||
|
Object? profileMatch = freezed,
|
||||||
|
Object? incompleteResume = freezed,
|
||||||
|
Object? incompleteResumeReason = freezed,
|
||||||
|
}) {
|
||||||
|
return _then(
|
||||||
|
_value.copyWith(
|
||||||
|
date:
|
||||||
|
freezed == date
|
||||||
|
? _value.date
|
||||||
|
: date // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String?,
|
||||||
|
status:
|
||||||
|
freezed == status
|
||||||
|
? _value.status
|
||||||
|
: status // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String?,
|
||||||
|
title:
|
||||||
|
freezed == title
|
||||||
|
? _value.title
|
||||||
|
: title // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String?,
|
||||||
|
id:
|
||||||
|
freezed == id
|
||||||
|
? _value.id
|
||||||
|
: id // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String?,
|
||||||
|
approvalDate:
|
||||||
|
freezed == approvalDate
|
||||||
|
? _value.approvalDate
|
||||||
|
: approvalDate // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String?,
|
||||||
|
submissionDate:
|
||||||
|
freezed == submissionDate
|
||||||
|
? _value.submissionDate
|
||||||
|
: submissionDate // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String?,
|
||||||
|
client:
|
||||||
|
freezed == client
|
||||||
|
? _value.client
|
||||||
|
: client // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String?,
|
||||||
|
deliveryLocation:
|
||||||
|
freezed == deliveryLocation
|
||||||
|
? _value.deliveryLocation
|
||||||
|
: deliveryLocation // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String?,
|
||||||
|
referenceNumber:
|
||||||
|
freezed == referenceNumber
|
||||||
|
? _value.referenceNumber
|
||||||
|
: referenceNumber // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String?,
|
||||||
|
country:
|
||||||
|
freezed == country
|
||||||
|
? _value.country
|
||||||
|
: country // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String?,
|
||||||
|
flagAsset:
|
||||||
|
freezed == flagAsset
|
||||||
|
? _value.flagAsset
|
||||||
|
: flagAsset // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String?,
|
||||||
|
locationTitle:
|
||||||
|
freezed == locationTitle
|
||||||
|
? _value.locationTitle
|
||||||
|
: locationTitle // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String?,
|
||||||
|
locationDescription:
|
||||||
|
freezed == locationDescription
|
||||||
|
? _value.locationDescription
|
||||||
|
: locationDescription // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String?,
|
||||||
|
documentName:
|
||||||
|
freezed == documentName
|
||||||
|
? _value.documentName
|
||||||
|
: documentName // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String?,
|
||||||
|
documentUrl:
|
||||||
|
freezed == documentUrl
|
||||||
|
? _value.documentUrl
|
||||||
|
: documentUrl // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String?,
|
||||||
|
profileMatch:
|
||||||
|
freezed == profileMatch
|
||||||
|
? _value.profileMatch
|
||||||
|
: profileMatch // ignore: cast_nullable_to_non_nullable
|
||||||
|
as double?,
|
||||||
|
incompleteResume:
|
||||||
|
freezed == incompleteResume
|
||||||
|
? _value.incompleteResume
|
||||||
|
: incompleteResume // ignore: cast_nullable_to_non_nullable
|
||||||
|
as bool?,
|
||||||
|
incompleteResumeReason:
|
||||||
|
freezed == incompleteResumeReason
|
||||||
|
? _value.incompleteResumeReason
|
||||||
|
: incompleteResumeReason // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String?,
|
||||||
|
)
|
||||||
|
as $Val,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
abstract class _$$TenderDetailResponseModelImplCopyWith<$Res>
|
||||||
|
implements $TenderDetailResponseModelCopyWith<$Res> {
|
||||||
|
factory _$$TenderDetailResponseModelImplCopyWith(
|
||||||
|
_$TenderDetailResponseModelImpl value,
|
||||||
|
$Res Function(_$TenderDetailResponseModelImpl) then,
|
||||||
|
) = __$$TenderDetailResponseModelImplCopyWithImpl<$Res>;
|
||||||
|
@override
|
||||||
|
@useResult
|
||||||
|
$Res call({
|
||||||
|
String? date,
|
||||||
|
String? status,
|
||||||
|
String? title,
|
||||||
|
String? id,
|
||||||
|
String? approvalDate,
|
||||||
|
String? submissionDate,
|
||||||
|
String? client,
|
||||||
|
String? deliveryLocation,
|
||||||
|
String? referenceNumber,
|
||||||
|
String? country,
|
||||||
|
String? flagAsset,
|
||||||
|
String? locationTitle,
|
||||||
|
String? locationDescription,
|
||||||
|
String? documentName,
|
||||||
|
String? documentUrl,
|
||||||
|
double? profileMatch,
|
||||||
|
bool? incompleteResume,
|
||||||
|
String? incompleteResumeReason,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
class __$$TenderDetailResponseModelImplCopyWithImpl<$Res>
|
||||||
|
extends
|
||||||
|
_$TenderDetailResponseModelCopyWithImpl<
|
||||||
|
$Res,
|
||||||
|
_$TenderDetailResponseModelImpl
|
||||||
|
>
|
||||||
|
implements _$$TenderDetailResponseModelImplCopyWith<$Res> {
|
||||||
|
__$$TenderDetailResponseModelImplCopyWithImpl(
|
||||||
|
_$TenderDetailResponseModelImpl _value,
|
||||||
|
$Res Function(_$TenderDetailResponseModelImpl) _then,
|
||||||
|
) : super(_value, _then);
|
||||||
|
|
||||||
|
/// Create a copy of TenderDetailResponseModel
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@pragma('vm:prefer-inline')
|
||||||
|
@override
|
||||||
|
$Res call({
|
||||||
|
Object? date = freezed,
|
||||||
|
Object? status = freezed,
|
||||||
|
Object? title = freezed,
|
||||||
|
Object? id = freezed,
|
||||||
|
Object? approvalDate = freezed,
|
||||||
|
Object? submissionDate = freezed,
|
||||||
|
Object? client = freezed,
|
||||||
|
Object? deliveryLocation = freezed,
|
||||||
|
Object? referenceNumber = freezed,
|
||||||
|
Object? country = freezed,
|
||||||
|
Object? flagAsset = freezed,
|
||||||
|
Object? locationTitle = freezed,
|
||||||
|
Object? locationDescription = freezed,
|
||||||
|
Object? documentName = freezed,
|
||||||
|
Object? documentUrl = freezed,
|
||||||
|
Object? profileMatch = freezed,
|
||||||
|
Object? incompleteResume = freezed,
|
||||||
|
Object? incompleteResumeReason = freezed,
|
||||||
|
}) {
|
||||||
|
return _then(
|
||||||
|
_$TenderDetailResponseModelImpl(
|
||||||
|
date:
|
||||||
|
freezed == date
|
||||||
|
? _value.date
|
||||||
|
: date // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String?,
|
||||||
|
status:
|
||||||
|
freezed == status
|
||||||
|
? _value.status
|
||||||
|
: status // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String?,
|
||||||
|
title:
|
||||||
|
freezed == title
|
||||||
|
? _value.title
|
||||||
|
: title // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String?,
|
||||||
|
id:
|
||||||
|
freezed == id
|
||||||
|
? _value.id
|
||||||
|
: id // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String?,
|
||||||
|
approvalDate:
|
||||||
|
freezed == approvalDate
|
||||||
|
? _value.approvalDate
|
||||||
|
: approvalDate // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String?,
|
||||||
|
submissionDate:
|
||||||
|
freezed == submissionDate
|
||||||
|
? _value.submissionDate
|
||||||
|
: submissionDate // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String?,
|
||||||
|
client:
|
||||||
|
freezed == client
|
||||||
|
? _value.client
|
||||||
|
: client // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String?,
|
||||||
|
deliveryLocation:
|
||||||
|
freezed == deliveryLocation
|
||||||
|
? _value.deliveryLocation
|
||||||
|
: deliveryLocation // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String?,
|
||||||
|
referenceNumber:
|
||||||
|
freezed == referenceNumber
|
||||||
|
? _value.referenceNumber
|
||||||
|
: referenceNumber // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String?,
|
||||||
|
country:
|
||||||
|
freezed == country
|
||||||
|
? _value.country
|
||||||
|
: country // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String?,
|
||||||
|
flagAsset:
|
||||||
|
freezed == flagAsset
|
||||||
|
? _value.flagAsset
|
||||||
|
: flagAsset // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String?,
|
||||||
|
locationTitle:
|
||||||
|
freezed == locationTitle
|
||||||
|
? _value.locationTitle
|
||||||
|
: locationTitle // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String?,
|
||||||
|
locationDescription:
|
||||||
|
freezed == locationDescription
|
||||||
|
? _value.locationDescription
|
||||||
|
: locationDescription // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String?,
|
||||||
|
documentName:
|
||||||
|
freezed == documentName
|
||||||
|
? _value.documentName
|
||||||
|
: documentName // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String?,
|
||||||
|
documentUrl:
|
||||||
|
freezed == documentUrl
|
||||||
|
? _value.documentUrl
|
||||||
|
: documentUrl // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String?,
|
||||||
|
profileMatch:
|
||||||
|
freezed == profileMatch
|
||||||
|
? _value.profileMatch
|
||||||
|
: profileMatch // ignore: cast_nullable_to_non_nullable
|
||||||
|
as double?,
|
||||||
|
incompleteResume:
|
||||||
|
freezed == incompleteResume
|
||||||
|
? _value.incompleteResume
|
||||||
|
: incompleteResume // ignore: cast_nullable_to_non_nullable
|
||||||
|
as bool?,
|
||||||
|
incompleteResumeReason:
|
||||||
|
freezed == incompleteResumeReason
|
||||||
|
? _value.incompleteResumeReason
|
||||||
|
: incompleteResumeReason // ignore: cast_nullable_to_non_nullable
|
||||||
|
as String?,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
|
||||||
|
@JsonSerializable(explicitToJson: true)
|
||||||
|
class _$TenderDetailResponseModelImpl implements _TenderDetailResponseModel {
|
||||||
|
const _$TenderDetailResponseModelImpl({
|
||||||
|
required this.date,
|
||||||
|
required this.status,
|
||||||
|
required this.title,
|
||||||
|
required this.id,
|
||||||
|
required this.approvalDate,
|
||||||
|
required this.submissionDate,
|
||||||
|
required this.client,
|
||||||
|
required this.deliveryLocation,
|
||||||
|
required this.referenceNumber,
|
||||||
|
required this.country,
|
||||||
|
required this.flagAsset,
|
||||||
|
required this.locationTitle,
|
||||||
|
required this.locationDescription,
|
||||||
|
required this.documentName,
|
||||||
|
required this.documentUrl,
|
||||||
|
required this.profileMatch,
|
||||||
|
required this.incompleteResume,
|
||||||
|
required this.incompleteResumeReason,
|
||||||
|
});
|
||||||
|
|
||||||
|
factory _$TenderDetailResponseModelImpl.fromJson(Map<String, dynamic> json) =>
|
||||||
|
_$$TenderDetailResponseModelImplFromJson(json);
|
||||||
|
|
||||||
|
@override
|
||||||
|
final String? date;
|
||||||
|
@override
|
||||||
|
final String? status;
|
||||||
|
@override
|
||||||
|
final String? title;
|
||||||
|
@override
|
||||||
|
final String? id;
|
||||||
|
@override
|
||||||
|
final String? approvalDate;
|
||||||
|
@override
|
||||||
|
final String? submissionDate;
|
||||||
|
@override
|
||||||
|
final String? client;
|
||||||
|
@override
|
||||||
|
final String? deliveryLocation;
|
||||||
|
@override
|
||||||
|
final String? referenceNumber;
|
||||||
|
@override
|
||||||
|
final String? country;
|
||||||
|
@override
|
||||||
|
final String? flagAsset;
|
||||||
|
@override
|
||||||
|
final String? locationTitle;
|
||||||
|
@override
|
||||||
|
final String? locationDescription;
|
||||||
|
@override
|
||||||
|
final String? documentName;
|
||||||
|
@override
|
||||||
|
final String? documentUrl;
|
||||||
|
@override
|
||||||
|
final double? profileMatch;
|
||||||
|
@override
|
||||||
|
final bool? incompleteResume;
|
||||||
|
@override
|
||||||
|
final String? incompleteResumeReason;
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return 'TenderDetailResponseModel(date: $date, status: $status, title: $title, id: $id, approvalDate: $approvalDate, submissionDate: $submissionDate, client: $client, deliveryLocation: $deliveryLocation, referenceNumber: $referenceNumber, country: $country, flagAsset: $flagAsset, locationTitle: $locationTitle, locationDescription: $locationDescription, documentName: $documentName, documentUrl: $documentUrl, profileMatch: $profileMatch, incompleteResume: $incompleteResume, incompleteResumeReason: $incompleteResumeReason)';
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) {
|
||||||
|
return identical(this, other) ||
|
||||||
|
(other.runtimeType == runtimeType &&
|
||||||
|
other is _$TenderDetailResponseModelImpl &&
|
||||||
|
(identical(other.date, date) || other.date == date) &&
|
||||||
|
(identical(other.status, status) || other.status == status) &&
|
||||||
|
(identical(other.title, title) || other.title == title) &&
|
||||||
|
(identical(other.id, id) || other.id == id) &&
|
||||||
|
(identical(other.approvalDate, approvalDate) ||
|
||||||
|
other.approvalDate == approvalDate) &&
|
||||||
|
(identical(other.submissionDate, submissionDate) ||
|
||||||
|
other.submissionDate == submissionDate) &&
|
||||||
|
(identical(other.client, client) || other.client == client) &&
|
||||||
|
(identical(other.deliveryLocation, deliveryLocation) ||
|
||||||
|
other.deliveryLocation == deliveryLocation) &&
|
||||||
|
(identical(other.referenceNumber, referenceNumber) ||
|
||||||
|
other.referenceNumber == referenceNumber) &&
|
||||||
|
(identical(other.country, country) || other.country == country) &&
|
||||||
|
(identical(other.flagAsset, flagAsset) ||
|
||||||
|
other.flagAsset == flagAsset) &&
|
||||||
|
(identical(other.locationTitle, locationTitle) ||
|
||||||
|
other.locationTitle == locationTitle) &&
|
||||||
|
(identical(other.locationDescription, locationDescription) ||
|
||||||
|
other.locationDescription == locationDescription) &&
|
||||||
|
(identical(other.documentName, documentName) ||
|
||||||
|
other.documentName == documentName) &&
|
||||||
|
(identical(other.documentUrl, documentUrl) ||
|
||||||
|
other.documentUrl == documentUrl) &&
|
||||||
|
(identical(other.profileMatch, profileMatch) ||
|
||||||
|
other.profileMatch == profileMatch) &&
|
||||||
|
(identical(other.incompleteResume, incompleteResume) ||
|
||||||
|
other.incompleteResume == incompleteResume) &&
|
||||||
|
(identical(other.incompleteResumeReason, incompleteResumeReason) ||
|
||||||
|
other.incompleteResumeReason == incompleteResumeReason));
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
|
@override
|
||||||
|
int get hashCode => Object.hash(
|
||||||
|
runtimeType,
|
||||||
|
date,
|
||||||
|
status,
|
||||||
|
title,
|
||||||
|
id,
|
||||||
|
approvalDate,
|
||||||
|
submissionDate,
|
||||||
|
client,
|
||||||
|
deliveryLocation,
|
||||||
|
referenceNumber,
|
||||||
|
country,
|
||||||
|
flagAsset,
|
||||||
|
locationTitle,
|
||||||
|
locationDescription,
|
||||||
|
documentName,
|
||||||
|
documentUrl,
|
||||||
|
profileMatch,
|
||||||
|
incompleteResume,
|
||||||
|
incompleteResumeReason,
|
||||||
|
);
|
||||||
|
|
||||||
|
/// Create a copy of TenderDetailResponseModel
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
|
@override
|
||||||
|
@pragma('vm:prefer-inline')
|
||||||
|
_$$TenderDetailResponseModelImplCopyWith<_$TenderDetailResponseModelImpl>
|
||||||
|
get copyWith => __$$TenderDetailResponseModelImplCopyWithImpl<
|
||||||
|
_$TenderDetailResponseModelImpl
|
||||||
|
>(this, _$identity);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
return _$$TenderDetailResponseModelImplToJson(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class _TenderDetailResponseModel implements TenderDetailResponseModel {
|
||||||
|
const factory _TenderDetailResponseModel({
|
||||||
|
required final String? date,
|
||||||
|
required final String? status,
|
||||||
|
required final String? title,
|
||||||
|
required final String? id,
|
||||||
|
required final String? approvalDate,
|
||||||
|
required final String? submissionDate,
|
||||||
|
required final String? client,
|
||||||
|
required final String? deliveryLocation,
|
||||||
|
required final String? referenceNumber,
|
||||||
|
required final String? country,
|
||||||
|
required final String? flagAsset,
|
||||||
|
required final String? locationTitle,
|
||||||
|
required final String? locationDescription,
|
||||||
|
required final String? documentName,
|
||||||
|
required final String? documentUrl,
|
||||||
|
required final double? profileMatch,
|
||||||
|
required final bool? incompleteResume,
|
||||||
|
required final String? incompleteResumeReason,
|
||||||
|
}) = _$TenderDetailResponseModelImpl;
|
||||||
|
|
||||||
|
factory _TenderDetailResponseModel.fromJson(Map<String, dynamic> json) =
|
||||||
|
_$TenderDetailResponseModelImpl.fromJson;
|
||||||
|
|
||||||
|
@override
|
||||||
|
String? get date;
|
||||||
|
@override
|
||||||
|
String? get status;
|
||||||
|
@override
|
||||||
|
String? get title;
|
||||||
|
@override
|
||||||
|
String? get id;
|
||||||
|
@override
|
||||||
|
String? get approvalDate;
|
||||||
|
@override
|
||||||
|
String? get submissionDate;
|
||||||
|
@override
|
||||||
|
String? get client;
|
||||||
|
@override
|
||||||
|
String? get deliveryLocation;
|
||||||
|
@override
|
||||||
|
String? get referenceNumber;
|
||||||
|
@override
|
||||||
|
String? get country;
|
||||||
|
@override
|
||||||
|
String? get flagAsset;
|
||||||
|
@override
|
||||||
|
String? get locationTitle;
|
||||||
|
@override
|
||||||
|
String? get locationDescription;
|
||||||
|
@override
|
||||||
|
String? get documentName;
|
||||||
|
@override
|
||||||
|
String? get documentUrl;
|
||||||
|
@override
|
||||||
|
double? get profileMatch;
|
||||||
|
@override
|
||||||
|
bool? get incompleteResume;
|
||||||
|
@override
|
||||||
|
String? get incompleteResumeReason;
|
||||||
|
|
||||||
|
/// Create a copy of TenderDetailResponseModel
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@override
|
||||||
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
|
_$$TenderDetailResponseModelImplCopyWith<_$TenderDetailResponseModelImpl>
|
||||||
|
get copyWith => throw _privateConstructorUsedError;
|
||||||
|
}
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
|
||||||
|
part of 'tender_detail_response_model.dart';
|
||||||
|
|
||||||
|
// **************************************************************************
|
||||||
|
// JsonSerializableGenerator
|
||||||
|
// **************************************************************************
|
||||||
|
|
||||||
|
_$TenderDetailResponseModelImpl _$$TenderDetailResponseModelImplFromJson(
|
||||||
|
Map<String, dynamic> json,
|
||||||
|
) => _$TenderDetailResponseModelImpl(
|
||||||
|
date: json['date'] as String?,
|
||||||
|
status: json['status'] as String?,
|
||||||
|
title: json['title'] as String?,
|
||||||
|
id: json['id'] as String?,
|
||||||
|
approvalDate: json['approvalDate'] as String?,
|
||||||
|
submissionDate: json['submissionDate'] as String?,
|
||||||
|
client: json['client'] as String?,
|
||||||
|
deliveryLocation: json['deliveryLocation'] as String?,
|
||||||
|
referenceNumber: json['referenceNumber'] as String?,
|
||||||
|
country: json['country'] as String?,
|
||||||
|
flagAsset: json['flagAsset'] as String?,
|
||||||
|
locationTitle: json['locationTitle'] as String?,
|
||||||
|
locationDescription: json['locationDescription'] as String?,
|
||||||
|
documentName: json['documentName'] as String?,
|
||||||
|
documentUrl: json['documentUrl'] as String?,
|
||||||
|
profileMatch: (json['profileMatch'] as num?)?.toDouble(),
|
||||||
|
incompleteResume: json['incompleteResume'] as bool?,
|
||||||
|
incompleteResumeReason: json['incompleteResumeReason'] as String?,
|
||||||
|
);
|
||||||
|
|
||||||
|
Map<String, dynamic> _$$TenderDetailResponseModelImplToJson(
|
||||||
|
_$TenderDetailResponseModelImpl instance,
|
||||||
|
) => <String, dynamic>{
|
||||||
|
'date': instance.date,
|
||||||
|
'status': instance.status,
|
||||||
|
'title': instance.title,
|
||||||
|
'id': instance.id,
|
||||||
|
'approvalDate': instance.approvalDate,
|
||||||
|
'submissionDate': instance.submissionDate,
|
||||||
|
'client': instance.client,
|
||||||
|
'deliveryLocation': instance.deliveryLocation,
|
||||||
|
'referenceNumber': instance.referenceNumber,
|
||||||
|
'country': instance.country,
|
||||||
|
'flagAsset': instance.flagAsset,
|
||||||
|
'locationTitle': instance.locationTitle,
|
||||||
|
'locationDescription': instance.locationDescription,
|
||||||
|
'documentName': instance.documentName,
|
||||||
|
'documentUrl': instance.documentUrl,
|
||||||
|
'profileMatch': instance.profileMatch,
|
||||||
|
'incompleteResume': instance.incompleteResume,
|
||||||
|
'incompleteResumeReason': instance.incompleteResumeReason,
|
||||||
|
};
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
import 'dart:convert';
|
||||||
|
|
||||||
|
import 'package:dio/dio.dart';
|
||||||
|
import 'package:tm_app/core/utils/logger.dart';
|
||||||
|
import 'package:tm_app/core/utils/result.dart';
|
||||||
|
import 'package:tm_app/data/services/mock_data/tender_detail_mock.dart';
|
||||||
|
import 'package:tm_app/data/services/model/tender_detail_request/tender_detail_request.dart';
|
||||||
|
import 'package:tm_app/data/services/model/tender_detail_response/tender_detail_response_model.dart';
|
||||||
|
import 'package:tm_app/data/services/network_manager.dart';
|
||||||
|
|
||||||
|
class TenderDetailService {
|
||||||
|
TenderDetailService({required NetworkManager networkManager})
|
||||||
|
: _networkManager = networkManager;
|
||||||
|
|
||||||
|
final NetworkManager _networkManager;
|
||||||
|
|
||||||
|
Future<Result<TenderDetailResponseModel>> getTenderDetail({
|
||||||
|
required TenderDetailRequest request,
|
||||||
|
}) async {
|
||||||
|
try {
|
||||||
|
await Future.delayed(const Duration(seconds: 2));
|
||||||
|
appLogger.info('get tender detail success');
|
||||||
|
|
||||||
|
return Result.ok(
|
||||||
|
TenderDetailResponseModel.fromJson(
|
||||||
|
jsonDecode(tenderDetailMockData)['data'],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
} catch (e, stackTrace) {
|
||||||
|
appLogger.error('get tender detail failed: $e', stackTrace: stackTrace);
|
||||||
|
return Result.error(Exception(e));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,5 +1,4 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
import '../core/utils/result.dart';
|
import '../core/utils/result.dart';
|
||||||
import '../data/models/user_model.dart';
|
import '../data/models/user_model.dart';
|
||||||
import '../data/repositories/auth_repository.dart';
|
import '../data/repositories/auth_repository.dart';
|
||||||
@@ -8,8 +7,25 @@ class AuthViewModel with ChangeNotifier {
|
|||||||
final AuthRepository _authRepository;
|
final AuthRepository _authRepository;
|
||||||
|
|
||||||
AuthViewModel({required AuthRepository authRepository})
|
AuthViewModel({required AuthRepository authRepository})
|
||||||
: _authRepository = authRepository;
|
: _authRepository = authRepository {
|
||||||
|
usernameController.addListener(_onTextChanged);
|
||||||
|
passwordController.addListener(_onTextChanged);
|
||||||
|
usernameFocus.addListener(_onTextChanged);
|
||||||
|
passwordFocus.addListener(_onTextChanged);
|
||||||
|
}
|
||||||
|
|
||||||
|
final TextEditingController usernameController = TextEditingController();
|
||||||
|
final TextEditingController passwordController = TextEditingController();
|
||||||
|
final FocusNode usernameFocus = FocusNode();
|
||||||
|
final FocusNode passwordFocus = FocusNode();
|
||||||
|
|
||||||
|
bool _obscurePassword = true;
|
||||||
|
bool get obscurePassword => _obscurePassword;
|
||||||
|
bool get isLoginEnabled =>
|
||||||
|
usernameController.text.isNotEmpty &&
|
||||||
|
passwordController.text.isNotEmpty;
|
||||||
|
|
||||||
|
// Auth state
|
||||||
bool _isLoading = false;
|
bool _isLoading = false;
|
||||||
String? _errorMessage;
|
String? _errorMessage;
|
||||||
UserModel? _loggedInUser;
|
UserModel? _loggedInUser;
|
||||||
@@ -18,25 +34,44 @@ class AuthViewModel with ChangeNotifier {
|
|||||||
String? get errorMessage => _errorMessage;
|
String? get errorMessage => _errorMessage;
|
||||||
UserModel? get loggedInUser => _loggedInUser;
|
UserModel? get loggedInUser => _loggedInUser;
|
||||||
|
|
||||||
Future<void> login(String email, String password) async {
|
void togglePasswordVisibility() {
|
||||||
|
_obscurePassword = !_obscurePassword;
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
|
||||||
|
void _onTextChanged() {
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> login() async {
|
||||||
_isLoading = true;
|
_isLoading = true;
|
||||||
_errorMessage = null;
|
_errorMessage = null;
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
|
|
||||||
final result = await _authRepository.login(email, password);
|
final result = await _authRepository.login(
|
||||||
|
usernameController.text.trim(),
|
||||||
|
passwordController.text.trim(),
|
||||||
|
);
|
||||||
|
|
||||||
switch (result) {
|
switch (result) {
|
||||||
case Ok<UserModel>():
|
case Ok<UserModel>():
|
||||||
_loggedInUser = result.value;
|
_loggedInUser = result.value;
|
||||||
// موفقیتآمیز
|
|
||||||
break;
|
break;
|
||||||
case Error<UserModel>():
|
case Error<UserModel>():
|
||||||
_errorMessage = result.error.toString();
|
_errorMessage = result.error.toString();
|
||||||
// خطا
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
_isLoading = false;
|
_isLoading = false;
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
usernameController.dispose();
|
||||||
|
passwordController.dispose();
|
||||||
|
usernameFocus.dispose();
|
||||||
|
passwordFocus.dispose();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,42 +0,0 @@
|
|||||||
// lib/view_models/login_view_model.dart
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
|
|
||||||
class LoginViewModel with ChangeNotifier {
|
|
||||||
final TextEditingController usernameController = TextEditingController();
|
|
||||||
final TextEditingController passwordController = TextEditingController();
|
|
||||||
|
|
||||||
final FocusNode usernameFocus = FocusNode();
|
|
||||||
final FocusNode passwordFocus = FocusNode();
|
|
||||||
|
|
||||||
bool _obscurePassword = true;
|
|
||||||
|
|
||||||
LoginViewModel() {
|
|
||||||
usernameController.addListener(_onTextChanged);
|
|
||||||
passwordController.addListener(_onTextChanged);
|
|
||||||
usernameFocus.addListener(_onTextChanged);
|
|
||||||
passwordFocus.addListener(_onTextChanged);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool get obscurePassword => _obscurePassword;
|
|
||||||
bool get isLoginEnabled =>
|
|
||||||
usernameController.text.isNotEmpty &&
|
|
||||||
passwordController.text.isNotEmpty;
|
|
||||||
|
|
||||||
void togglePasswordVisibility() {
|
|
||||||
_obscurePassword = !_obscurePassword;
|
|
||||||
notifyListeners();
|
|
||||||
}
|
|
||||||
|
|
||||||
void _onTextChanged() {
|
|
||||||
notifyListeners();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void dispose() {
|
|
||||||
usernameController.dispose();
|
|
||||||
passwordController.dispose();
|
|
||||||
usernameFocus.dispose();
|
|
||||||
passwordFocus.dispose();
|
|
||||||
super.dispose();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:tm_app/core/utils/result.dart';
|
||||||
|
import 'package:tm_app/data/repositories/tender_detail_repository.dart';
|
||||||
|
import 'package:tm_app/data/services/model/tender_detail_request/tender_detail_request.dart';
|
||||||
|
import 'package:tm_app/data/services/model/tender_detail_response/tender_detail_response_model.dart';
|
||||||
|
|
||||||
|
class TenderDetailViewModel with ChangeNotifier {
|
||||||
|
final TenderDetailRepository _tenderDetailRepository;
|
||||||
|
|
||||||
|
TenderDetailViewModel({required TenderDetailRepository tenderDetailRepository})
|
||||||
|
: _tenderDetailRepository = tenderDetailRepository;
|
||||||
|
|
||||||
|
bool _isLoading = false;
|
||||||
|
String? _errorMessage;
|
||||||
|
TenderDetailResponseModel? _tenderDetail;
|
||||||
|
|
||||||
|
bool get isLoading => _isLoading;
|
||||||
|
String? get errorMessage => _errorMessage;
|
||||||
|
TenderDetailResponseModel? get tenderDetail => _tenderDetail;
|
||||||
|
|
||||||
|
Future<void> getTenderDetail({required String id}) async {
|
||||||
|
_isLoading = true;
|
||||||
|
_errorMessage = null;
|
||||||
|
notifyListeners();
|
||||||
|
|
||||||
|
final request = TenderDetailRequest(id: id);
|
||||||
|
final result = await _tenderDetailRepository.getTenderDetail(request: request);
|
||||||
|
switch (result) {
|
||||||
|
case Ok<TenderDetailResponseModel>():
|
||||||
|
_tenderDetail = result.value;
|
||||||
|
break;
|
||||||
|
case Error<TenderDetailResponseModel>():
|
||||||
|
_errorMessage = result.error.toString();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
_isLoading = false;
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,67 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:flutter_svg/flutter_svg.dart';
|
|
||||||
import 'package:tm_app/core/constants/assets.dart';
|
|
||||||
import 'package:tm_app/core/constants/strings.dart';
|
|
||||||
import 'package:tm_app/core/utils/size_config.dart';
|
|
||||||
import 'package:tm_app/views/detail/widgets/tender_detail_action.dart';
|
|
||||||
import 'package:tm_app/views/detail/widgets/tender_detail_card.dart';
|
|
||||||
import 'package:tm_app/views/detail/widgets/tender_detail_header.dart';
|
|
||||||
|
|
||||||
class TenderDetailDesktopScreen extends StatelessWidget {
|
|
||||||
const TenderDetailDesktopScreen({super.key});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Scaffold(
|
|
||||||
backgroundColor: Colors.white,
|
|
||||||
appBar: _buildAppBar(context),
|
|
||||||
body: SingleChildScrollView(
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.all(16.0),
|
|
||||||
child: Center(
|
|
||||||
child: SizedBox(
|
|
||||||
width: 740,
|
|
||||||
child: Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
TenderDetailHeader(isBig: true,),
|
|
||||||
SizedBox(height: 24.0.h()),
|
|
||||||
const TenderDetailCard(),
|
|
||||||
SizedBox(height: 24.0.h()),
|
|
||||||
TenderDetailActions(),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
PreferredSizeWidget _buildAppBar(BuildContext context) {
|
|
||||||
return PreferredSize(
|
|
||||||
preferredSize: const Size.fromHeight(60),
|
|
||||||
child: AppBar(
|
|
||||||
backgroundColor: Colors.white,
|
|
||||||
elevation: 0,
|
|
||||||
titleSpacing: 0,
|
|
||||||
leading: IconButton(
|
|
||||||
icon: SvgPicture.asset(
|
|
||||||
AssetsManager.arrowLeft,
|
|
||||||
height: 24.0.w(),
|
|
||||||
width: 24.0.w(),
|
|
||||||
),
|
|
||||||
onPressed: () => Navigator.pop(context),
|
|
||||||
),
|
|
||||||
title: Text(
|
|
||||||
AppStrings.tenderDetailTitle,
|
|
||||||
style: TextStyle(
|
|
||||||
color: Colors.black,
|
|
||||||
fontWeight: FontWeight.w600,
|
|
||||||
fontSize: 20.0.sp(),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,62 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:flutter_svg/flutter_svg.dart';
|
|
||||||
import 'package:tm_app/core/constants/assets.dart';
|
|
||||||
import 'package:tm_app/core/constants/strings.dart';
|
|
||||||
import 'package:tm_app/core/utils/size_config.dart';
|
|
||||||
import 'package:tm_app/views/detail/widgets/tender_detail_action.dart';
|
|
||||||
import 'package:tm_app/views/detail/widgets/tender_detail_card.dart';
|
|
||||||
import 'package:tm_app/views/detail/widgets/tender_detail_header.dart';
|
|
||||||
|
|
||||||
class TenderDetailMobileScreen extends StatelessWidget {
|
|
||||||
const TenderDetailMobileScreen({super.key});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Scaffold(
|
|
||||||
backgroundColor: Colors.white,
|
|
||||||
appBar: _buildAppBar(context),
|
|
||||||
body: SingleChildScrollView(
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.all(16.0),
|
|
||||||
child: Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
TenderDetailHeader(isBig: false),
|
|
||||||
SizedBox(height: 24.0.h()),
|
|
||||||
const TenderDetailCard(),
|
|
||||||
SizedBox(height: 24.0.h()),
|
|
||||||
TenderDetailActions(),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
PreferredSizeWidget _buildAppBar(BuildContext context) {
|
|
||||||
return PreferredSize(
|
|
||||||
preferredSize: const Size.fromHeight(60),
|
|
||||||
child: AppBar(
|
|
||||||
backgroundColor: Colors.white,
|
|
||||||
elevation: 0,
|
|
||||||
titleSpacing: 0,
|
|
||||||
leading: IconButton(
|
|
||||||
icon: SvgPicture.asset(
|
|
||||||
AssetsManager.arrowLeft,
|
|
||||||
height: 24.0.w(),
|
|
||||||
width: 24.0.w(),
|
|
||||||
),
|
|
||||||
onPressed: () => Navigator.pop(context),
|
|
||||||
),
|
|
||||||
title: Text(
|
|
||||||
AppStrings.tenderDetailTitle,
|
|
||||||
style: TextStyle(
|
|
||||||
color: Colors.black,
|
|
||||||
fontWeight: FontWeight.w600,
|
|
||||||
fontSize: 20.0.sp(),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:tm_app/core/utils/display_size_detector.dart';
|
|
||||||
import 'package:tm_app/views/detail/detail_desktop_screen.dart';
|
|
||||||
import 'package:tm_app/views/detail/detail_mobile_screen.dart';
|
|
||||||
import 'package:tm_app/views/detail/detail_tablet_screen.dart';
|
|
||||||
|
|
||||||
class TenderDetailScreen extends StatelessWidget {
|
|
||||||
const TenderDetailScreen({super.key});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
final displaySize = MediaQuery.of(context).size.displaySize;
|
|
||||||
|
|
||||||
switch (displaySize) {
|
|
||||||
case DisplaySize.large:
|
|
||||||
case DisplaySize.medium:
|
|
||||||
return const TenderDetailDesktopScreen();
|
|
||||||
case DisplaySize.small:
|
|
||||||
return const TenderDetailTabletScreen();
|
|
||||||
case DisplaySize.extraSmall:
|
|
||||||
return const TenderDetailMobileScreen();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,67 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:flutter_svg/flutter_svg.dart';
|
|
||||||
import 'package:tm_app/core/constants/assets.dart';
|
|
||||||
import 'package:tm_app/core/constants/strings.dart';
|
|
||||||
import 'package:tm_app/core/utils/size_config.dart';
|
|
||||||
import 'package:tm_app/views/detail/widgets/tender_detail_action.dart';
|
|
||||||
import 'package:tm_app/views/detail/widgets/tender_detail_card.dart';
|
|
||||||
import 'package:tm_app/views/detail/widgets/tender_detail_header.dart';
|
|
||||||
|
|
||||||
class TenderDetailTabletScreen extends StatelessWidget {
|
|
||||||
const TenderDetailTabletScreen({super.key});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Scaffold(
|
|
||||||
backgroundColor: Colors.white,
|
|
||||||
appBar: _buildAppBar(context),
|
|
||||||
body: SingleChildScrollView(
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.all(16.0),
|
|
||||||
child: Center(
|
|
||||||
child: SizedBox(
|
|
||||||
width: 768,
|
|
||||||
child: Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
TenderDetailHeader(isBig: true,),
|
|
||||||
SizedBox(height: 24.0.h()),
|
|
||||||
const TenderDetailCard(),
|
|
||||||
SizedBox(height: 24.0.h()),
|
|
||||||
TenderDetailActions(),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
PreferredSizeWidget _buildAppBar(BuildContext context) {
|
|
||||||
return PreferredSize(
|
|
||||||
preferredSize: const Size.fromHeight(60),
|
|
||||||
child: AppBar(
|
|
||||||
backgroundColor: Colors.white,
|
|
||||||
elevation: 0,
|
|
||||||
titleSpacing: 0,
|
|
||||||
leading: IconButton(
|
|
||||||
icon: SvgPicture.asset(
|
|
||||||
AssetsManager.arrowLeft,
|
|
||||||
height: 24.0.w(),
|
|
||||||
width: 24.0.w(),
|
|
||||||
),
|
|
||||||
onPressed: () => Navigator.pop(context),
|
|
||||||
),
|
|
||||||
title: Text(
|
|
||||||
AppStrings.tenderDetailTitle,
|
|
||||||
style: TextStyle(
|
|
||||||
color: Colors.black,
|
|
||||||
fontWeight: FontWeight.w600,
|
|
||||||
fontSize: 20.0.sp(),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,103 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_svg/flutter_svg.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
import 'package:tm_app/core/constants/assets.dart';
|
||||||
|
import 'package:tm_app/core/constants/strings.dart';
|
||||||
|
import 'package:tm_app/core/theme/colors.dart';
|
||||||
|
import 'package:tm_app/core/utils/size_config.dart';
|
||||||
|
import 'package:tm_app/view_models/tender_detail_view_model.dart';
|
||||||
|
import 'package:tm_app/views/detail/widgets/tender_detail_action.dart';
|
||||||
|
import 'package:tm_app/views/detail/widgets/tender_detail_header.dart';
|
||||||
|
|
||||||
|
class TenderDetailDesktopPage extends StatefulWidget {
|
||||||
|
final String tenderId;
|
||||||
|
const TenderDetailDesktopPage({required this.tenderId, super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<TenderDetailDesktopPage> createState() =>
|
||||||
|
_TenderDetailDesktopPageState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _TenderDetailDesktopPageState extends State<TenderDetailDesktopPage> {
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
Future.microtask(() {
|
||||||
|
context.read<TenderDetailViewModel>().getTenderDetail(
|
||||||
|
id: widget.tenderId,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
backgroundColor: AppColors.backgroundColor,
|
||||||
|
appBar: _buildAppBar(context),
|
||||||
|
body: Consumer<TenderDetailViewModel>(
|
||||||
|
builder: (context, tenderViewModel, child) {
|
||||||
|
if (tenderViewModel.isLoading) {
|
||||||
|
return const Center(
|
||||||
|
child: CircularProgressIndicator(color: AppColors.secondary50),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tenderViewModel.errorMessage != null) {
|
||||||
|
return Center(child: Text(tenderViewModel.errorMessage!));
|
||||||
|
}
|
||||||
|
|
||||||
|
final detail = tenderViewModel.tenderDetail;
|
||||||
|
if (detail == null) {
|
||||||
|
return const Center(child: Text('No tender details available'));
|
||||||
|
}
|
||||||
|
|
||||||
|
return SingleChildScrollView(
|
||||||
|
child: Center(
|
||||||
|
child: SizedBox(
|
||||||
|
width: 740,
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(32.0),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
TenderDetailHeader(isScreenBig: true, detail: detail),
|
||||||
|
SizedBox(height: 32.0.h()),
|
||||||
|
TenderDetailActions(isScreenBig: true),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
PreferredSizeWidget _buildAppBar(BuildContext context) {
|
||||||
|
return PreferredSize(
|
||||||
|
preferredSize: const Size.fromHeight(60),
|
||||||
|
child: AppBar(
|
||||||
|
backgroundColor: AppColors.backgroundColor,
|
||||||
|
elevation: 0,
|
||||||
|
titleSpacing: 0,
|
||||||
|
leading: IconButton(
|
||||||
|
icon: SvgPicture.asset(
|
||||||
|
AssetsManager.arrowLeft,
|
||||||
|
height: 24.0.w(),
|
||||||
|
width: 24.0.w(),
|
||||||
|
),
|
||||||
|
onPressed: () => Navigator.pop(context),
|
||||||
|
),
|
||||||
|
title: Text(
|
||||||
|
AppStrings.tenderDetailTitle,
|
||||||
|
style: TextStyle(
|
||||||
|
color: AppColors.grey70,
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
fontSize: 20.0.sp(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,98 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_svg/flutter_svg.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
import 'package:tm_app/core/constants/assets.dart';
|
||||||
|
import 'package:tm_app/core/constants/strings.dart';
|
||||||
|
import 'package:tm_app/core/theme/colors.dart';
|
||||||
|
import 'package:tm_app/core/utils/size_config.dart';
|
||||||
|
import 'package:tm_app/view_models/tender_detail_view_model.dart';
|
||||||
|
import 'package:tm_app/views/detail/widgets/tender_detail_action.dart';
|
||||||
|
import 'package:tm_app/views/detail/widgets/tender_detail_header.dart';
|
||||||
|
|
||||||
|
class TenderDetailMobilePage extends StatefulWidget {
|
||||||
|
final String tenderId;
|
||||||
|
const TenderDetailMobilePage({super.key, required this.tenderId});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<TenderDetailMobilePage> createState() => _TenderDetailMobilePageState();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class _TenderDetailMobilePageState extends State<TenderDetailMobilePage> {
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
Future.microtask(() {
|
||||||
|
context.read<TenderDetailViewModel>().getTenderDetail(id: widget.tenderId);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
backgroundColor: AppColors.backgroundColor,
|
||||||
|
appBar: _buildAppBar(context),
|
||||||
|
body: Consumer<TenderDetailViewModel>(
|
||||||
|
builder: (context, tenderViewModel, child) {
|
||||||
|
if (tenderViewModel.isLoading) {
|
||||||
|
return const Center(
|
||||||
|
child: CircularProgressIndicator(color: AppColors.secondary50),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tenderViewModel.errorMessage != null) {
|
||||||
|
return Center(child: Text(tenderViewModel.errorMessage!));
|
||||||
|
}
|
||||||
|
|
||||||
|
final detail = tenderViewModel.tenderDetail;
|
||||||
|
if (detail == null) {
|
||||||
|
return const Center(child: Text("No tender details available"));
|
||||||
|
}
|
||||||
|
|
||||||
|
return SingleChildScrollView(
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(16.0),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
TenderDetailHeader(isScreenBig: false, detail: detail),
|
||||||
|
SizedBox(height: 24.0.h()),
|
||||||
|
TenderDetailActions(isScreenBig: false),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
PreferredSizeWidget _buildAppBar(BuildContext context) {
|
||||||
|
return PreferredSize(
|
||||||
|
preferredSize: const Size.fromHeight(60),
|
||||||
|
child: AppBar(
|
||||||
|
backgroundColor: AppColors.backgroundColor,
|
||||||
|
elevation: 0,
|
||||||
|
titleSpacing: 0,
|
||||||
|
leading: IconButton(
|
||||||
|
icon: SvgPicture.asset(
|
||||||
|
AssetsManager.arrowLeft,
|
||||||
|
height: 24.0.w(),
|
||||||
|
width: 24.0.w(),
|
||||||
|
),
|
||||||
|
onPressed: () => Navigator.pop(context),
|
||||||
|
),
|
||||||
|
title: Text(
|
||||||
|
AppStrings.tenderDetailTitle,
|
||||||
|
style: TextStyle(
|
||||||
|
color: AppColors.grey70,
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
fontSize: 20.0.sp(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:tm_app/core/utils/size_config.dart';
|
||||||
|
import 'package:tm_app/views/detail/pages/detail_desktop_page.dart';
|
||||||
|
import 'package:tm_app/views/detail/pages/detail_mobile_page.dart';
|
||||||
|
import 'package:tm_app/views/detail/pages/detail_tablet_page.dart';
|
||||||
|
import 'package:tm_app/views/shared/responsive_builder.dart';
|
||||||
|
|
||||||
|
class TenderDetailScreen extends StatelessWidget {
|
||||||
|
const TenderDetailScreen({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
SizeConfig.init(context);
|
||||||
|
return ResponsiveBuilder(
|
||||||
|
mobile: TenderDetailMobilePage(tenderId: 'JNDFKMDV-100JF',),
|
||||||
|
tablet: TenderDetailTabletPage(tenderId: 'JNDFKMDV-100JF',),
|
||||||
|
desktop: TenderDetailDesktopPage(tenderId: 'JNDFKMDV-100JF',),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,102 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_svg/flutter_svg.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
import 'package:tm_app/core/constants/assets.dart';
|
||||||
|
import 'package:tm_app/core/constants/strings.dart';
|
||||||
|
import 'package:tm_app/core/theme/colors.dart';
|
||||||
|
import 'package:tm_app/core/utils/size_config.dart';
|
||||||
|
import 'package:tm_app/view_models/tender_detail_view_model.dart';
|
||||||
|
import 'package:tm_app/views/detail/widgets/tender_detail_action.dart';
|
||||||
|
import 'package:tm_app/views/detail/widgets/tender_detail_header.dart';
|
||||||
|
|
||||||
|
class TenderDetailTabletPage extends StatefulWidget {
|
||||||
|
final String tenderId;
|
||||||
|
const TenderDetailTabletPage({required this.tenderId, super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<TenderDetailTabletPage> createState() => _TenderDetailTabletPageState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _TenderDetailTabletPageState extends State<TenderDetailTabletPage> {
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
Future.microtask(() {
|
||||||
|
context.read<TenderDetailViewModel>().getTenderDetail(
|
||||||
|
id: widget.tenderId,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
backgroundColor: AppColors.backgroundColor,
|
||||||
|
appBar: _buildAppBar(context),
|
||||||
|
body: Consumer<TenderDetailViewModel>(
|
||||||
|
builder: (context, tenderViewModel, child) {
|
||||||
|
if (tenderViewModel.isLoading) {
|
||||||
|
return const Center(
|
||||||
|
child: CircularProgressIndicator(color: AppColors.secondary50),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tenderViewModel.errorMessage != null) {
|
||||||
|
return Center(child: Text(tenderViewModel.errorMessage!));
|
||||||
|
}
|
||||||
|
|
||||||
|
final detail = tenderViewModel.tenderDetail;
|
||||||
|
if (detail == null) {
|
||||||
|
return const Center(child: Text('No tender details available'));
|
||||||
|
}
|
||||||
|
return SingleChildScrollView(
|
||||||
|
child: Center(
|
||||||
|
child: SizedBox(
|
||||||
|
width: 768,
|
||||||
|
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(24.0),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
TenderDetailHeader(isScreenBig: true, detail: detail),
|
||||||
|
SizedBox(height: 28.0.h()),
|
||||||
|
TenderDetailActions(isScreenBig: true),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
PreferredSizeWidget _buildAppBar(BuildContext context) {
|
||||||
|
return PreferredSize(
|
||||||
|
preferredSize: const Size.fromHeight(60),
|
||||||
|
child: AppBar(
|
||||||
|
backgroundColor: AppColors.backgroundColor,
|
||||||
|
elevation: 0,
|
||||||
|
titleSpacing: 0,
|
||||||
|
leading: IconButton(
|
||||||
|
icon: SvgPicture.asset(
|
||||||
|
AssetsManager.arrowLeft,
|
||||||
|
height: 24.0.w(),
|
||||||
|
width: 24.0.w(),
|
||||||
|
),
|
||||||
|
onPressed: () => Navigator.pop(context),
|
||||||
|
),
|
||||||
|
title: Text(
|
||||||
|
AppStrings.tenderDetailTitle,
|
||||||
|
style: TextStyle(
|
||||||
|
color: AppColors.grey70,
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
fontSize: 20.0.sp(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -8,156 +8,164 @@ class DeadlineItem extends StatelessWidget {
|
|||||||
final String approvalDate;
|
final String approvalDate;
|
||||||
final String submissionText;
|
final String submissionText;
|
||||||
final String submissionDate;
|
final String submissionDate;
|
||||||
final bool isBig;
|
final bool isScreenBig;
|
||||||
|
|
||||||
const DeadlineItem({
|
const DeadlineItem({
|
||||||
required this.title, required this.approvalText, required this.approvalDate, required this.submissionText, required this.submissionDate, required this.isBig, super.key,
|
required this.title,
|
||||||
|
required this.approvalText,
|
||||||
|
required this.approvalDate,
|
||||||
|
required this.submissionText,
|
||||||
|
required this.submissionDate,
|
||||||
|
required this.isScreenBig,
|
||||||
|
super.key,
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return isBig ? Padding(
|
return isScreenBig
|
||||||
padding: EdgeInsets.symmetric(vertical: 0),
|
? Padding(
|
||||||
child: Column(
|
padding: EdgeInsets.symmetric(vertical: 0),
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
child: Column(
|
||||||
children: [
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
SizedBox(
|
children: [
|
||||||
height: 45.0.h(),
|
SizedBox(
|
||||||
child: Text(
|
height: 45.0.h(),
|
||||||
title,
|
child: Text(
|
||||||
style: TextStyle(
|
title,
|
||||||
color: AppColors.grey80,
|
style: TextStyle(
|
||||||
fontWeight: FontWeight.w600,
|
color: AppColors.grey80,
|
||||||
fontSize: 16.0.sp(),
|
fontWeight: FontWeight.w600,
|
||||||
),
|
fontSize: 16.0.sp(),
|
||||||
),
|
|
||||||
),
|
|
||||||
IntrinsicHeight(
|
|
||||||
child: Row(
|
|
||||||
children: [
|
|
||||||
Expanded(
|
|
||||||
child: Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
Text(
|
|
||||||
approvalText,
|
|
||||||
style: TextStyle(
|
|
||||||
color: AppColors.grey70,
|
|
||||||
fontWeight: FontWeight.w400,
|
|
||||||
fontSize: 14.0.sp(),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
SizedBox(height: 4.0.h()),
|
|
||||||
Text(
|
|
||||||
approvalDate,
|
|
||||||
style: TextStyle(
|
|
||||||
color: AppColors.grey80,
|
|
||||||
fontWeight: FontWeight.w400,
|
|
||||||
fontSize: 14.0.sp(),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
VerticalDivider(
|
),
|
||||||
color: AppColors.grey30,
|
IntrinsicHeight(
|
||||||
thickness: 1,
|
child: Row(
|
||||||
width: 24,
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
approvalText,
|
||||||
|
style: TextStyle(
|
||||||
|
color: AppColors.grey70,
|
||||||
|
fontWeight: FontWeight.w400,
|
||||||
|
fontSize: 14.0.sp(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(height: 4.0.h()),
|
||||||
|
Text(
|
||||||
|
approvalDate,
|
||||||
|
style: TextStyle(
|
||||||
|
color: AppColors.grey80,
|
||||||
|
fontWeight: FontWeight.w400,
|
||||||
|
fontSize: 14.0.sp(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
VerticalDivider(
|
||||||
|
color: AppColors.grey30,
|
||||||
|
thickness: 1,
|
||||||
|
width: 24,
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
submissionText,
|
||||||
|
style: TextStyle(
|
||||||
|
color: AppColors.grey70,
|
||||||
|
fontWeight: FontWeight.w400,
|
||||||
|
fontSize: 14.0.sp(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(height: 4.0.h()),
|
||||||
|
Text(
|
||||||
|
submissionDate,
|
||||||
|
style: TextStyle(
|
||||||
|
color: AppColors.grey80,
|
||||||
|
fontWeight: FontWeight.w400,
|
||||||
|
fontSize: 14.0.sp(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
Expanded(
|
),
|
||||||
child: Column(
|
SizedBox(height: 8.0.h()),
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
const Divider(),
|
||||||
children: [
|
],
|
||||||
Text(
|
),
|
||||||
submissionText,
|
)
|
||||||
style: TextStyle(
|
: Padding(
|
||||||
color: AppColors.grey70,
|
padding: EdgeInsets.symmetric(vertical: 0),
|
||||||
fontWeight: FontWeight.w400,
|
child: Column(
|
||||||
fontSize: 14.0.sp(),
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
),
|
children: [
|
||||||
),
|
SizedBox(
|
||||||
SizedBox(height: 4.0.h()),
|
height: 45.0.h(),
|
||||||
Text(
|
child: Text(
|
||||||
submissionDate,
|
title,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: AppColors.grey80,
|
color: AppColors.grey80,
|
||||||
fontWeight: FontWeight.w400,
|
fontWeight: FontWeight.w600,
|
||||||
fontSize: 14.0.sp(),
|
fontSize: 16.0.sp(),
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
SizedBox(height: 8.0.h()),
|
|
||||||
const Divider(),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
) : Padding(
|
|
||||||
padding: EdgeInsets.symmetric(vertical: 0),
|
|
||||||
child: Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
SizedBox(
|
|
||||||
height: 45.0.h(),
|
|
||||||
child: Text(
|
|
||||||
title,
|
|
||||||
style: TextStyle(
|
|
||||||
color: AppColors.grey80,
|
|
||||||
fontWeight: FontWeight.w600,
|
|
||||||
fontSize: 16.0.sp(),
|
|
||||||
),
|
),
|
||||||
),
|
Row(
|
||||||
),
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
Row(
|
children: [
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
Text(
|
||||||
children: [
|
approvalText,
|
||||||
Text(
|
style: TextStyle(
|
||||||
approvalText,
|
color: AppColors.grey70,
|
||||||
style: TextStyle(
|
fontWeight: FontWeight.w400,
|
||||||
color: AppColors.grey70,
|
fontSize: 14.0.sp(),
|
||||||
fontWeight: FontWeight.w400,
|
),
|
||||||
fontSize: 14.0.sp(),
|
),
|
||||||
),
|
Text(
|
||||||
|
approvalDate,
|
||||||
|
style: TextStyle(
|
||||||
|
color: AppColors.grey70,
|
||||||
|
fontWeight: FontWeight.w400,
|
||||||
|
fontSize: 14.0.sp(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
Text(
|
SizedBox(height: 4.0.h()),
|
||||||
approvalDate,
|
Row(
|
||||||
style: TextStyle(
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
color: AppColors.grey70,
|
children: [
|
||||||
fontWeight: FontWeight.w400,
|
Text(
|
||||||
fontSize: 14.0.sp(),
|
submissionText,
|
||||||
),
|
style: TextStyle(
|
||||||
|
color: AppColors.grey70,
|
||||||
|
fontWeight: FontWeight.w400,
|
||||||
|
fontSize: 14.0.sp(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
submissionDate,
|
||||||
|
style: TextStyle(
|
||||||
|
color: AppColors.grey70,
|
||||||
|
fontWeight: FontWeight.w400,
|
||||||
|
fontSize: 14.0.sp(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
|
SizedBox(height: 8.0.h()),
|
||||||
|
const Divider(),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
SizedBox(height: 4.0.h()),
|
);
|
||||||
Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
||||||
children: [
|
|
||||||
Text(
|
|
||||||
submissionText,
|
|
||||||
style: TextStyle(
|
|
||||||
color: AppColors.grey70,
|
|
||||||
fontWeight: FontWeight.w400,
|
|
||||||
fontSize: 14.0.sp(),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Text(
|
|
||||||
submissionDate,
|
|
||||||
style: TextStyle(
|
|
||||||
color: AppColors.grey70,
|
|
||||||
fontWeight: FontWeight.w400,
|
|
||||||
fontSize: 14.0.sp(),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
SizedBox(height: 8.0.h()),
|
|
||||||
const Divider(),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,31 +5,56 @@ import 'package:tm_app/core/utils/size_config.dart';
|
|||||||
import 'package:tm_app/views/login/widgets/login_button.dart';
|
import 'package:tm_app/views/login/widgets/login_button.dart';
|
||||||
|
|
||||||
class TenderDetailActions extends StatelessWidget {
|
class TenderDetailActions extends StatelessWidget {
|
||||||
const TenderDetailActions({super.key});
|
final bool isScreenBig;
|
||||||
|
const TenderDetailActions({required this.isScreenBig, super.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Column(
|
return isScreenBig
|
||||||
children: [
|
? Row(
|
||||||
BaseButton(
|
children: [
|
||||||
isEnabled: true,
|
Spacer(),
|
||||||
text: AppStrings.tenderSubmitButton,
|
BaseButton(
|
||||||
backgroundColor: AppColors.lightBlue,
|
isEnabled: true,
|
||||||
textColor: AppColors.mainBlue,
|
text: AppStrings.tenderRejectButton,
|
||||||
onPressed: () {},
|
textColor: AppColors.red10,
|
||||||
),
|
backgroundColor: AppColors.backgroundColor,
|
||||||
SizedBox(height: 16.0.h()),
|
borderWidth: 1,
|
||||||
BaseButton(
|
onPressed: () {},
|
||||||
isEnabled: true,
|
width: 120.0.w(),
|
||||||
text: AppStrings.tenderRejectButton,
|
),
|
||||||
borderColor: AppColors.red10,
|
SizedBox(width: 5.0.w()),
|
||||||
textColor: AppColors.red10,
|
BaseButton(
|
||||||
backgroundColor: Colors.white,
|
isEnabled: true,
|
||||||
borderWidth: 1,
|
text: AppStrings.tenderSubmitButton,
|
||||||
onPressed: () {},
|
backgroundColor: AppColors.lightBlue,
|
||||||
),
|
textColor: AppColors.mainBlue,
|
||||||
SizedBox(height: 16.0.h()),
|
onPressed: () {},
|
||||||
],
|
width: 120.0.w(),
|
||||||
);
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
: Column(
|
||||||
|
children: [
|
||||||
|
BaseButton(
|
||||||
|
isEnabled: true,
|
||||||
|
text: AppStrings.tenderSubmitButton,
|
||||||
|
backgroundColor: AppColors.lightBlue,
|
||||||
|
textColor: AppColors.mainBlue,
|
||||||
|
onPressed: () {},
|
||||||
|
),
|
||||||
|
SizedBox(height: 16.0.h()),
|
||||||
|
BaseButton(
|
||||||
|
isEnabled: true,
|
||||||
|
text: AppStrings.tenderRejectButton,
|
||||||
|
borderColor: AppColors.red10,
|
||||||
|
textColor: AppColors.red10,
|
||||||
|
backgroundColor: AppColors.backgroundColor,
|
||||||
|
borderWidth: 1,
|
||||||
|
onPressed: () {},
|
||||||
|
),
|
||||||
|
SizedBox(height: 16.0.h()),
|
||||||
|
],
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,11 +20,11 @@ class TenderDetailCard extends StatelessWidget {
|
|||||||
Row(
|
Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: [
|
children: [
|
||||||
const Text(
|
Text(
|
||||||
AppStrings.tenderMatchProfile,
|
AppStrings.tenderMatchProfile,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 12.0,
|
fontSize: 12.0.sp(),
|
||||||
color: Colors.black87,
|
color: AppColors.grey80,
|
||||||
fontWeight: FontWeight.w400,
|
fontWeight: FontWeight.w400,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -46,7 +46,7 @@ class TenderDetailCard extends StatelessWidget {
|
|||||||
value: 0.75,
|
value: 0.75,
|
||||||
backgroundColor: AppColors.grey20,
|
backgroundColor: AppColors.grey20,
|
||||||
valueColor: AlwaysStoppedAnimation<Color>(AppColors.jellyBean),
|
valueColor: AlwaysStoppedAnimation<Color>(AppColors.jellyBean),
|
||||||
minHeight: 6,
|
minHeight: 6.0.h(),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
SizedBox(height: 16.0.h()),
|
SizedBox(height: 16.0.h()),
|
||||||
@@ -54,26 +54,26 @@ class TenderDetailCard extends StatelessWidget {
|
|||||||
Row(
|
Row(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
const Icon(Icons.warning_rounded, color: Colors.red),
|
const Icon(Icons.warning_rounded, color: AppColors.red),
|
||||||
SizedBox(width: 8.0.w()),
|
SizedBox(width: 8.0.w()),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: const [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
AppStrings.tenderIncompleteResume,
|
AppStrings.tenderIncompleteResume,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontWeight: FontWeight.w600,
|
fontWeight: FontWeight.w600,
|
||||||
fontSize: 16.0,
|
fontSize: 16.0.sp(),
|
||||||
color: Colors.black87,
|
color: AppColors.grey80,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
SizedBox(height: 4.0),
|
SizedBox(height: 4.0.h()),
|
||||||
Text(
|
Text(
|
||||||
AppStrings.tenderNoExperience,
|
AppStrings.tenderNoExperience,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 14.0,
|
fontSize: 14.0.sp(),
|
||||||
color: Colors.black54,
|
color: AppColors.grey70,
|
||||||
fontWeight: FontWeight.w400,
|
fontWeight: FontWeight.w400,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -86,4 +86,4 @@ class TenderDetailCard extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,22 +1,24 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:tm_app/core/constants/strings.dart';
|
|
||||||
import 'package:tm_app/core/theme/colors.dart';
|
import 'package:tm_app/core/theme/colors.dart';
|
||||||
import 'package:tm_app/core/utils/size_config.dart';
|
import 'package:tm_app/core/utils/size_config.dart';
|
||||||
|
import 'package:tm_app/data/services/model/tender_detail_response/tender_detail_response_model.dart';
|
||||||
import 'package:tm_app/views/detail/widgets/status_tag.dart';
|
import 'package:tm_app/views/detail/widgets/status_tag.dart';
|
||||||
import 'package:tm_app/views/detail/widgets/tender_detail_info_section.dart';
|
import 'package:tm_app/views/detail/widgets/tender_detail_info_section.dart';
|
||||||
import 'package:tm_app/views/detail/widgets/tender_document_section.dart';
|
import 'package:tm_app/views/detail/widgets/tender_document_section.dart';
|
||||||
import 'package:tm_app/views/detail/widgets/tender_location_section.dart';
|
import 'package:tm_app/views/detail/widgets/tender_location_section.dart';
|
||||||
|
|
||||||
class TenderDetailHeader extends StatelessWidget {
|
class TenderDetailHeader extends StatelessWidget {
|
||||||
final bool isBig;
|
final bool isScreenBig;
|
||||||
const TenderDetailHeader({required this.isBig, super.key});
|
final TenderDetailResponseModel detail;
|
||||||
|
|
||||||
|
const TenderDetailHeader({required this.isScreenBig, required this.detail, super.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Container(
|
return Container(
|
||||||
padding: const EdgeInsets.all(16),
|
padding: const EdgeInsets.all(16),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Colors.white,
|
color: AppColors.backgroundColor,
|
||||||
borderRadius: BorderRadius.circular(5),
|
borderRadius: BorderRadius.circular(5),
|
||||||
border: Border.all(width: 0.5, color: AppColors.grey50),
|
border: Border.all(width: 0.5, color: AppColors.grey50),
|
||||||
),
|
),
|
||||||
@@ -29,10 +31,10 @@ class TenderDetailHeader extends StatelessWidget {
|
|||||||
SizedBox(height: 10.0.h()),
|
SizedBox(height: 10.0.h()),
|
||||||
const Divider(),
|
const Divider(),
|
||||||
SizedBox(height: 5.0.h()),
|
SizedBox(height: 5.0.h()),
|
||||||
TenderDetailInfoSection(isBig: isBig,),
|
TenderDetailInfoSection(isScreenBig: isScreenBig, detail: detail),
|
||||||
TenderLocationSection(),
|
TenderLocationSection(detail: detail),
|
||||||
SizedBox(height: 16.0.h()),
|
SizedBox(height: 16.0.h()),
|
||||||
TenderDocumentSection(),
|
TenderDocumentSection(detail: detail),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@@ -42,15 +44,15 @@ class TenderDetailHeader extends StatelessWidget {
|
|||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
AppStrings.tenderDateExample,
|
detail.date ?? '',
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: AppColors.grey60,
|
color: AppColors.grey60,
|
||||||
fontWeight: FontWeight.w400,
|
fontWeight: FontWeight.w400,
|
||||||
fontSize: 12.0.sp(),
|
fontSize: 12.0.sp(),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const StatusTag(
|
StatusTag(
|
||||||
text: AppStrings.tenderStatusOpen,
|
text: detail.status ?? '',
|
||||||
textColor: AppColors.cyanTeal,
|
textColor: AppColors.cyanTeal,
|
||||||
backgroundColor: AppColors.cyanAqua,
|
backgroundColor: AppColors.cyanAqua,
|
||||||
),
|
),
|
||||||
@@ -58,7 +60,7 @@ class TenderDetailHeader extends StatelessWidget {
|
|||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildTitle() => Text(
|
Widget _buildTitle() => Text(
|
||||||
AppStrings.tenderTitleExample,
|
detail.title ?? '',
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: AppColors.grey80,
|
color: AppColors.grey80,
|
||||||
fontWeight: FontWeight.w600,
|
fontWeight: FontWeight.w600,
|
||||||
|
|||||||
@@ -1,12 +1,14 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:tm_app/core/constants/strings.dart';
|
import 'package:tm_app/core/constants/strings.dart';
|
||||||
|
import 'package:tm_app/data/services/model/tender_detail_response/tender_detail_response_model.dart';
|
||||||
import 'package:tm_app/views/detail/widgets/deadline_item.dart';
|
import 'package:tm_app/views/detail/widgets/deadline_item.dart';
|
||||||
import 'package:tm_app/views/detail/widgets/info_item.dart';
|
import 'package:tm_app/views/detail/widgets/info_item.dart';
|
||||||
|
|
||||||
class TenderDetailInfoSection extends StatelessWidget {
|
class TenderDetailInfoSection extends StatelessWidget {
|
||||||
final bool isBig;
|
final bool isScreenBig;
|
||||||
|
final TenderDetailResponseModel detail;
|
||||||
|
|
||||||
const TenderDetailInfoSection({required this.isBig ,super.key});
|
const TenderDetailInfoSection({required this.isScreenBig, required this.detail, super.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
@@ -15,26 +17,27 @@ class TenderDetailInfoSection extends StatelessWidget {
|
|||||||
children: [
|
children: [
|
||||||
InfoItem(
|
InfoItem(
|
||||||
title: AppStrings.tenderIdLabel,
|
title: AppStrings.tenderIdLabel,
|
||||||
value: AppStrings.tenderIdExample,
|
value: detail.id ?? '',
|
||||||
),
|
),
|
||||||
DeadlineItem(
|
DeadlineItem(
|
||||||
title: AppStrings.tenderDeadlineLabel,
|
title: AppStrings.tenderDeadlineLabel,
|
||||||
approvalText: AppStrings.tenderApprovalText,
|
approvalText: AppStrings.tenderApprovalText,
|
||||||
approvalDate: AppStrings.tenderApprovalDateExample,
|
approvalDate: detail.approvalDate ?? '',
|
||||||
submissionText: AppStrings.tenderSubmissionText,
|
submissionText: AppStrings.tenderSubmissionText,
|
||||||
submissionDate: AppStrings.tenderSubmissionDateExample, isBig: isBig,
|
submissionDate: detail.submissionDate ?? '',
|
||||||
|
isScreenBig: isScreenBig,
|
||||||
),
|
),
|
||||||
InfoItem(
|
InfoItem(
|
||||||
title: AppStrings.tenderClientLabel,
|
title: AppStrings.tenderClientLabel,
|
||||||
value: AppStrings.tenderClientExample,
|
value: detail.client ?? '',
|
||||||
),
|
),
|
||||||
InfoItem(
|
InfoItem(
|
||||||
title: AppStrings.tenderDeliveryLocationsLabel,
|
title: AppStrings.tenderDeliveryLocationsLabel,
|
||||||
value: AppStrings.tenderDeliveryLocationExample,
|
value: detail.deliveryLocation ?? '',
|
||||||
),
|
),
|
||||||
InfoItem(
|
InfoItem(
|
||||||
title: AppStrings.tenderReferenceNumberLabel,
|
title: AppStrings.tenderReferenceNumberLabel,
|
||||||
value: AppStrings.tenderReferenceNumberExample,
|
value: detail.referenceNumber ?? '',
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,29 +1,38 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_svg/flutter_svg.dart';
|
import 'package:flutter_svg/flutter_svg.dart';
|
||||||
import 'package:tm_app/core/constants/assets.dart';
|
import 'package:tm_app/core/constants/assets.dart';
|
||||||
import 'package:tm_app/core/constants/strings.dart';
|
import 'package:tm_app/core/theme/colors.dart';
|
||||||
import 'package:tm_app/core/utils/size_config.dart';
|
import 'package:tm_app/core/utils/size_config.dart';
|
||||||
|
import 'package:tm_app/data/services/model/tender_detail_response/tender_detail_response_model.dart';
|
||||||
class TenderDocumentSection extends StatelessWidget {
|
class TenderDocumentSection extends StatelessWidget {
|
||||||
const TenderDocumentSection({super.key});
|
final TenderDetailResponseModel detail;
|
||||||
|
|
||||||
|
const TenderDocumentSection({super.key, required this.detail});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Column(
|
return InkWell(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
onTap: () {
|
||||||
children: [
|
if (detail.documentUrl != null) {
|
||||||
SvgPicture.asset(AssetsManager.export),
|
//launchUrl(Uri.parse(detail.documentUrl!));
|
||||||
SizedBox(height: 6.0.h()),
|
}
|
||||||
Text(
|
},
|
||||||
AppStrings.tenderPdfDocument,
|
child: Column(
|
||||||
style: TextStyle(
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
fontWeight: FontWeight.w400,
|
children: [
|
||||||
fontSize: 16.0.sp(),
|
SvgPicture.asset(AssetsManager.export),
|
||||||
color: Colors.blue,
|
SizedBox(height: 6.0.h()),
|
||||||
decoration: TextDecoration.underline,
|
Text(
|
||||||
|
detail.documentName ?? '',
|
||||||
|
style: TextStyle(
|
||||||
|
fontWeight: FontWeight.w400,
|
||||||
|
fontSize: 16.0.sp(),
|
||||||
|
color: AppColors.textBlue,
|
||||||
|
decoration: TextDecoration.underline,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
],
|
||||||
],
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,9 +4,12 @@ import 'package:tm_app/core/constants/assets.dart';
|
|||||||
import 'package:tm_app/core/constants/strings.dart';
|
import 'package:tm_app/core/constants/strings.dart';
|
||||||
import 'package:tm_app/core/theme/colors.dart';
|
import 'package:tm_app/core/theme/colors.dart';
|
||||||
import 'package:tm_app/core/utils/size_config.dart';
|
import 'package:tm_app/core/utils/size_config.dart';
|
||||||
|
import 'package:tm_app/data/services/model/tender_detail_response/tender_detail_response_model.dart';
|
||||||
|
|
||||||
class TenderLocationSection extends StatelessWidget {
|
class TenderLocationSection extends StatelessWidget {
|
||||||
const TenderLocationSection({super.key});
|
final TenderDetailResponseModel detail;
|
||||||
|
|
||||||
|
const TenderLocationSection({super.key, required this.detail});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
@@ -18,7 +21,7 @@ class TenderLocationSection extends StatelessWidget {
|
|||||||
SizedBox(
|
SizedBox(
|
||||||
height: 45.0.h(),
|
height: 45.0.h(),
|
||||||
child: Text(
|
child: Text(
|
||||||
AppStrings.tenderReferenceNumberLabel,
|
detail.locationTitle ?? '',
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: AppColors.grey80,
|
color: AppColors.grey80,
|
||||||
fontWeight: FontWeight.w600,
|
fontWeight: FontWeight.w600,
|
||||||
@@ -35,7 +38,7 @@ class TenderLocationSection extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
SizedBox(width: 4.0.w()),
|
SizedBox(width: 4.0.w()),
|
||||||
Text(
|
Text(
|
||||||
AppStrings.tenderLocationCountry,
|
detail.country ?? '',
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: AppColors.grey70,
|
color: AppColors.grey70,
|
||||||
fontSize: 14.0.sp(),
|
fontSize: 14.0.sp(),
|
||||||
@@ -44,7 +47,7 @@ class TenderLocationSection extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
SizedBox(width: 4.0.w()),
|
SizedBox(width: 4.0.w()),
|
||||||
Image.asset(
|
Image.asset(
|
||||||
AssetsManager.seFlag,
|
detail.flagAsset ?? AssetsManager.seFlag,
|
||||||
height: 20.0.h(),
|
height: 20.0.h(),
|
||||||
width: 20.0.w(),
|
width: 20.0.w(),
|
||||||
),
|
),
|
||||||
@@ -57,7 +60,7 @@ class TenderLocationSection extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
SizedBox(height: 8.0.h()),
|
SizedBox(height: 8.0.h()),
|
||||||
Text(
|
Text(
|
||||||
AppStrings.locationDescription,
|
detail.locationDescription ?? '',
|
||||||
style: TextStyle(fontWeight: FontWeight.w400, fontSize: 14.0.sp()),
|
style: TextStyle(fontWeight: FontWeight.w400, fontSize: 14.0.sp()),
|
||||||
),
|
),
|
||||||
SizedBox(height: 16.0.h()),
|
SizedBox(height: 16.0.h()),
|
||||||
|
|||||||
@@ -1,94 +0,0 @@
|
|||||||
// lib/views/login_desktop_screen.dart
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:tm_app/core/routes/app_routes.dart';
|
|
||||||
|
|
||||||
import '../../core/constants/assets.dart';
|
|
||||||
import '../../core/constants/strings.dart';
|
|
||||||
import '../../core/utils/size_config.dart';
|
|
||||||
import 'widgets/widgets.dart';
|
|
||||||
import '../../view_models/login_view_model.dart';
|
|
||||||
|
|
||||||
class LoginDesktopScreen extends StatefulWidget {
|
|
||||||
const LoginDesktopScreen({super.key});
|
|
||||||
|
|
||||||
@override
|
|
||||||
State<LoginDesktopScreen> createState() => _LoginDesktopScreenState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _LoginDesktopScreenState extends State<LoginDesktopScreen> {
|
|
||||||
late final LoginViewModel _viewModel;
|
|
||||||
|
|
||||||
@override
|
|
||||||
void initState() {
|
|
||||||
super.initState();
|
|
||||||
_viewModel = LoginViewModel();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void dispose() {
|
|
||||||
_viewModel.dispose();
|
|
||||||
super.dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
SizeConfig.init(context);
|
|
||||||
return Scaffold(
|
|
||||||
backgroundColor: Colors.white,
|
|
||||||
body: Center(
|
|
||||||
child: SingleChildScrollView(
|
|
||||||
padding: EdgeInsets.symmetric(horizontal: 24.0.w()),
|
|
||||||
child: SizedBox(
|
|
||||||
width: 120.0.w(),
|
|
||||||
child: ListenableBuilder(
|
|
||||||
listenable: _viewModel,
|
|
||||||
builder: (context, _) {
|
|
||||||
return Column(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
children: [
|
|
||||||
LoginLogo(width: 190.0.w(), height: 88.0.h()),
|
|
||||||
SizedBox(height: 32.0.h()),
|
|
||||||
const LoginTitle(),
|
|
||||||
SizedBox(height: 32.0.h()),
|
|
||||||
|
|
||||||
LoginTextField(
|
|
||||||
controller: _viewModel.usernameController,
|
|
||||||
focusNode: _viewModel.usernameFocus,
|
|
||||||
label: AppStrings.usernameLabel,
|
|
||||||
iconPath: AssetsManager.userIcon,
|
|
||||||
fieldHeight: 60.0.h(),
|
|
||||||
borderRedus: 4.0.w(),
|
|
||||||
prefixIconPadding: 4.0.w(),
|
|
||||||
),
|
|
||||||
SizedBox(height: 16.0.h()),
|
|
||||||
|
|
||||||
LoginTextField(
|
|
||||||
controller: _viewModel.passwordController,
|
|
||||||
focusNode: _viewModel.passwordFocus,
|
|
||||||
label: AppStrings.passwordLabel,
|
|
||||||
iconPath: AssetsManager.passwordIcon,
|
|
||||||
prefixIconPadding: 4.0.w(),
|
|
||||||
isPassword: true,
|
|
||||||
obscureText: _viewModel.obscurePassword,
|
|
||||||
fieldHeight: 60.0.h(),
|
|
||||||
onToggleVisibility: _viewModel.togglePasswordVisibility,
|
|
||||||
borderRedus: 4.0.w(),
|
|
||||||
),
|
|
||||||
SizedBox(height: 32.0.h()),
|
|
||||||
|
|
||||||
BaseButton(
|
|
||||||
isEnabled: _viewModel.isLoginEnabled,
|
|
||||||
onPressed: _viewModel.isLoginEnabled
|
|
||||||
? () => HomeRouteData().go(context)
|
|
||||||
: null,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,88 +0,0 @@
|
|||||||
// lib/views/login_screen.dart
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:tm_app/core/routes/app_routes.dart';
|
|
||||||
|
|
||||||
import '../../core/constants/assets.dart';
|
|
||||||
import '../../core/constants/strings.dart';
|
|
||||||
import '../../core/utils/size_config.dart';
|
|
||||||
import 'widgets/widgets.dart';
|
|
||||||
import '../../view_models/login_view_model.dart';
|
|
||||||
|
|
||||||
class LoginMobileScreen extends StatefulWidget {
|
|
||||||
const LoginMobileScreen({super.key});
|
|
||||||
|
|
||||||
@override
|
|
||||||
State<LoginMobileScreen> createState() => _LoginMobileScreenState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _LoginMobileScreenState extends State<LoginMobileScreen> {
|
|
||||||
late final LoginViewModel _viewModel;
|
|
||||||
|
|
||||||
@override
|
|
||||||
void initState() {
|
|
||||||
super.initState();
|
|
||||||
_viewModel = LoginViewModel();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void dispose() {
|
|
||||||
_viewModel.dispose();
|
|
||||||
super.dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
SizeConfig.init(context);
|
|
||||||
|
|
||||||
return Scaffold(
|
|
||||||
backgroundColor: Colors.white,
|
|
||||||
body: Center(
|
|
||||||
child: SingleChildScrollView(
|
|
||||||
padding: EdgeInsets.symmetric(horizontal: 24.0.w()),
|
|
||||||
child: ListenableBuilder(
|
|
||||||
listenable: _viewModel,
|
|
||||||
builder: (context, _) {
|
|
||||||
return Column(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
children: [
|
|
||||||
LoginLogo(width: 190.0.w(), height: 88.0.h()),
|
|
||||||
SizedBox(height: 32.0.h()),
|
|
||||||
const LoginTitle(),
|
|
||||||
SizedBox(height: 32.0.h()),
|
|
||||||
|
|
||||||
LoginTextField(
|
|
||||||
controller: _viewModel.usernameController,
|
|
||||||
focusNode: _viewModel.usernameFocus,
|
|
||||||
label: AppStrings.usernameLabel,
|
|
||||||
iconPath: AssetsManager.userIcon,
|
|
||||||
),
|
|
||||||
SizedBox(height: 16.0.h()),
|
|
||||||
|
|
||||||
LoginTextField(
|
|
||||||
controller: _viewModel.passwordController,
|
|
||||||
focusNode: _viewModel.passwordFocus,
|
|
||||||
label: AppStrings.passwordLabel,
|
|
||||||
iconPath: AssetsManager.passwordIcon,
|
|
||||||
isPassword: true,
|
|
||||||
obscureText: _viewModel.obscurePassword,
|
|
||||||
onToggleVisibility: _viewModel.togglePasswordVisibility,
|
|
||||||
),
|
|
||||||
SizedBox(height: 32.0.h()),
|
|
||||||
|
|
||||||
BaseButton(
|
|
||||||
isEnabled: _viewModel.isLoginEnabled,
|
|
||||||
onPressed: _viewModel.isLoginEnabled
|
|
||||||
? () {
|
|
||||||
HomeRouteData().go(context);
|
|
||||||
}
|
|
||||||
: null,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:tm_app/core/utils/display_size_detector.dart';
|
|
||||||
import 'package:tm_app/views/login/login_desktop_screen.dart';
|
|
||||||
import 'package:tm_app/views/login/login_mobile_screen.dart';
|
|
||||||
import 'package:tm_app/views/login/login_tablet_screen.dart';
|
|
||||||
|
|
||||||
class LoginScreen extends StatelessWidget {
|
|
||||||
const LoginScreen({super.key});
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
final displaySize = MediaQuery.of(context).size.displaySize;
|
|
||||||
|
|
||||||
switch (displaySize) {
|
|
||||||
case DisplaySize.large:
|
|
||||||
case DisplaySize.medium:
|
|
||||||
return const LoginDesktopScreen();
|
|
||||||
case DisplaySize.small:
|
|
||||||
return const LoginTabletScreen();
|
|
||||||
case DisplaySize.extraSmall:
|
|
||||||
return const LoginMobileScreen();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,94 +0,0 @@
|
|||||||
// lib/views/login_tablet_screen.dart
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:tm_app/core/routes/app_routes.dart';
|
|
||||||
|
|
||||||
import '../../core/constants/assets.dart';
|
|
||||||
import '../../core/constants/strings.dart';
|
|
||||||
import '../../core/utils/size_config.dart';
|
|
||||||
import 'widgets/widgets.dart';
|
|
||||||
import '../../view_models/login_view_model.dart';
|
|
||||||
|
|
||||||
class LoginTabletScreen extends StatefulWidget {
|
|
||||||
const LoginTabletScreen({super.key});
|
|
||||||
|
|
||||||
@override
|
|
||||||
State<LoginTabletScreen> createState() => _LoginTabletScreenState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _LoginTabletScreenState extends State<LoginTabletScreen> {
|
|
||||||
late final LoginViewModel _viewModel;
|
|
||||||
|
|
||||||
@override
|
|
||||||
void initState() {
|
|
||||||
super.initState();
|
|
||||||
_viewModel = LoginViewModel();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void dispose() {
|
|
||||||
_viewModel.dispose();
|
|
||||||
super.dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
SizeConfig.init(context);
|
|
||||||
return Scaffold(
|
|
||||||
backgroundColor: Colors.white,
|
|
||||||
body: Center(
|
|
||||||
child: SingleChildScrollView(
|
|
||||||
padding: EdgeInsets.symmetric(horizontal: 24.0.w()),
|
|
||||||
child: SizedBox(
|
|
||||||
width: 120.0.w(),
|
|
||||||
child: ListenableBuilder(
|
|
||||||
listenable: _viewModel,
|
|
||||||
builder: (context, _) {
|
|
||||||
return Column(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
children: [
|
|
||||||
LoginLogo(width: 190.0.w(), height: 88.0.h()),
|
|
||||||
SizedBox(height: 32.0.h()),
|
|
||||||
const LoginTitle(),
|
|
||||||
SizedBox(height: 32.0.h()),
|
|
||||||
|
|
||||||
LoginTextField(
|
|
||||||
controller: _viewModel.usernameController,
|
|
||||||
focusNode: _viewModel.usernameFocus,
|
|
||||||
label: AppStrings.usernameLabel,
|
|
||||||
iconPath: AssetsManager.userIcon,
|
|
||||||
fieldHeight: 60.0.h(),
|
|
||||||
borderRedus: 4.0.w(),
|
|
||||||
prefixIconPadding: 4.0.w(),
|
|
||||||
),
|
|
||||||
SizedBox(height: 16.0.h()),
|
|
||||||
|
|
||||||
LoginTextField(
|
|
||||||
controller: _viewModel.passwordController,
|
|
||||||
focusNode: _viewModel.passwordFocus,
|
|
||||||
label: AppStrings.passwordLabel,
|
|
||||||
iconPath: AssetsManager.passwordIcon,
|
|
||||||
prefixIconPadding: 4.0.w(),
|
|
||||||
isPassword: true,
|
|
||||||
obscureText: _viewModel.obscurePassword,
|
|
||||||
fieldHeight: 60.0.h(),
|
|
||||||
onToggleVisibility: _viewModel.togglePasswordVisibility,
|
|
||||||
borderRedus: 4.0.w(),
|
|
||||||
),
|
|
||||||
SizedBox(height: 32.0.h()),
|
|
||||||
|
|
||||||
BaseButton(
|
|
||||||
isEnabled: _viewModel.isLoginEnabled,
|
|
||||||
onPressed: _viewModel.isLoginEnabled
|
|
||||||
? () => HomeRouteData().go(context)
|
|
||||||
: null,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,90 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
import 'package:tm_app/core/routes/app_routes.dart';
|
||||||
|
import 'package:tm_app/core/theme/colors.dart';
|
||||||
|
|
||||||
|
import '../../../core/constants/assets.dart';
|
||||||
|
import '../../../core/constants/strings.dart';
|
||||||
|
import '../../../core/utils/size_config.dart';
|
||||||
|
import '../../../view_models/auth_view_model.dart';
|
||||||
|
import '../widgets/widgets.dart';
|
||||||
|
|
||||||
|
class LoginDesktopPage extends StatelessWidget {
|
||||||
|
const LoginDesktopPage({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
SizeConfig.init(context);
|
||||||
|
return Scaffold(
|
||||||
|
backgroundColor: AppColors.backgroundColor,
|
||||||
|
body: Center(
|
||||||
|
child: SingleChildScrollView(
|
||||||
|
padding: EdgeInsets.symmetric(horizontal: 24.0.w()),
|
||||||
|
child: SizedBox(
|
||||||
|
width: 526,
|
||||||
|
child: Consumer<AuthViewModel>(
|
||||||
|
builder: (context, viewModel, _) {
|
||||||
|
return Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
LoginLogo(width: 190.0.w(), height: 88.0.h()),
|
||||||
|
SizedBox(height: 32.0.h()),
|
||||||
|
const LoginTitle(),
|
||||||
|
SizedBox(height: 32.0.h()),
|
||||||
|
|
||||||
|
LoginTextField(
|
||||||
|
controller: viewModel.usernameController,
|
||||||
|
focusNode: viewModel.usernameFocus,
|
||||||
|
label: AppStrings.usernameLabel,
|
||||||
|
iconPath: AssetsManager.userIcon,
|
||||||
|
fieldHeight: 60.0.h(),
|
||||||
|
borderRedus: 4.0.w(),
|
||||||
|
prefixIconPadding: 4.0.w(),
|
||||||
|
),
|
||||||
|
SizedBox(height: 16.0.h()),
|
||||||
|
|
||||||
|
LoginTextField(
|
||||||
|
controller: viewModel.passwordController,
|
||||||
|
focusNode: viewModel.passwordFocus,
|
||||||
|
label: AppStrings.passwordLabel,
|
||||||
|
iconPath: AssetsManager.passwordIcon,
|
||||||
|
prefixIconPadding: 4.0.w(),
|
||||||
|
isPassword: true,
|
||||||
|
obscureText: viewModel.obscurePassword,
|
||||||
|
fieldHeight: 60.0.h(),
|
||||||
|
onToggleVisibility: viewModel.togglePasswordVisibility,
|
||||||
|
borderRedus: 4.0.w(),
|
||||||
|
),
|
||||||
|
SizedBox(height: 32.0.h()),
|
||||||
|
|
||||||
|
if (viewModel.isLoading)
|
||||||
|
const CircularProgressIndicator()
|
||||||
|
else
|
||||||
|
BaseButton(
|
||||||
|
isEnabled: viewModel.isLoginEnabled,
|
||||||
|
onPressed:
|
||||||
|
viewModel.isLoginEnabled
|
||||||
|
? () async {
|
||||||
|
await viewModel.login();
|
||||||
|
if (viewModel.loggedInUser != null) {
|
||||||
|
HomeRouteData().go(context);
|
||||||
|
} else if (viewModel.errorMessage != null) {
|
||||||
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
|
SnackBar(
|
||||||
|
content: Text(viewModel.errorMessage!),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
: null,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,82 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
import 'package:tm_app/core/routes/app_routes.dart';
|
||||||
|
import 'package:tm_app/core/theme/colors.dart';
|
||||||
|
|
||||||
|
import '../../../core/constants/assets.dart';
|
||||||
|
import '../../../core/constants/strings.dart';
|
||||||
|
import '../../../core/utils/size_config.dart';
|
||||||
|
import '../../../view_models/auth_view_model.dart';
|
||||||
|
import '../widgets/widgets.dart';
|
||||||
|
|
||||||
|
class LoginMobilePage extends StatelessWidget {
|
||||||
|
const LoginMobilePage({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
SizeConfig.init(context);
|
||||||
|
|
||||||
|
return Scaffold(
|
||||||
|
backgroundColor: AppColors.backgroundColor,
|
||||||
|
body: Center(
|
||||||
|
child: SingleChildScrollView(
|
||||||
|
padding: EdgeInsets.symmetric(horizontal: 24.0.w()),
|
||||||
|
child: Consumer<AuthViewModel>(
|
||||||
|
builder: (context, viewModel, _) {
|
||||||
|
return Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
LoginLogo(width: 190.0.w(), height: 88.0.h()),
|
||||||
|
SizedBox(height: 32.0.h()),
|
||||||
|
const LoginTitle(),
|
||||||
|
SizedBox(height: 32.0.h()),
|
||||||
|
|
||||||
|
LoginTextField(
|
||||||
|
controller: viewModel.usernameController,
|
||||||
|
focusNode: viewModel.usernameFocus,
|
||||||
|
label: AppStrings.usernameLabel,
|
||||||
|
iconPath: AssetsManager.userIcon,
|
||||||
|
),
|
||||||
|
SizedBox(height: 16.0.h()),
|
||||||
|
|
||||||
|
LoginTextField(
|
||||||
|
controller: viewModel.passwordController,
|
||||||
|
focusNode: viewModel.passwordFocus,
|
||||||
|
label: AppStrings.passwordLabel,
|
||||||
|
iconPath: AssetsManager.passwordIcon,
|
||||||
|
isPassword: true,
|
||||||
|
obscureText: viewModel.obscurePassword,
|
||||||
|
onToggleVisibility: viewModel.togglePasswordVisibility,
|
||||||
|
),
|
||||||
|
SizedBox(height: 32.0.h()),
|
||||||
|
|
||||||
|
if (viewModel.isLoading)
|
||||||
|
const CircularProgressIndicator()
|
||||||
|
else
|
||||||
|
BaseButton(
|
||||||
|
isEnabled: viewModel.isLoginEnabled,
|
||||||
|
onPressed:
|
||||||
|
viewModel.isLoginEnabled
|
||||||
|
? () async {
|
||||||
|
await viewModel.login();
|
||||||
|
if (viewModel.loggedInUser != null) {
|
||||||
|
HomeRouteData().go(context);
|
||||||
|
} else if (viewModel.errorMessage != null) {
|
||||||
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
|
SnackBar(
|
||||||
|
content: Text(viewModel.errorMessage!),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
: null,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:tm_app/core/utils/size_config.dart';
|
||||||
|
import 'package:tm_app/views/login/pages/login_desktop_page.dart';
|
||||||
|
import 'package:tm_app/views/login/pages/login_mobile_page.dart';
|
||||||
|
import 'package:tm_app/views/login/pages/login_tablet_page.dart';
|
||||||
|
import 'package:tm_app/views/shared/responsive_builder.dart';
|
||||||
|
|
||||||
|
class LoginScreen extends StatelessWidget {
|
||||||
|
const LoginScreen({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
SizeConfig.init(context);
|
||||||
|
return ResponsiveBuilder(
|
||||||
|
mobile: LoginMobilePage(),
|
||||||
|
tablet: LoginTabletPage(),
|
||||||
|
desktop: LoginDesktopPage(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,90 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
import 'package:tm_app/core/routes/app_routes.dart';
|
||||||
|
import 'package:tm_app/core/theme/colors.dart';
|
||||||
|
|
||||||
|
import '../../../core/constants/assets.dart';
|
||||||
|
import '../../../core/constants/strings.dart';
|
||||||
|
import '../../../core/utils/size_config.dart';
|
||||||
|
import '../../../view_models/auth_view_model.dart';
|
||||||
|
import '../widgets/widgets.dart';
|
||||||
|
|
||||||
|
class LoginTabletPage extends StatelessWidget {
|
||||||
|
const LoginTabletPage({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
SizeConfig.init(context);
|
||||||
|
return Scaffold(
|
||||||
|
backgroundColor: AppColors.backgroundColor,
|
||||||
|
body: Center(
|
||||||
|
child: SingleChildScrollView(
|
||||||
|
padding: EdgeInsets.symmetric(horizontal: 24.0.w()),
|
||||||
|
child: SizedBox(
|
||||||
|
width: 526,
|
||||||
|
child: Consumer<AuthViewModel>(
|
||||||
|
builder: (context, viewModel, _) {
|
||||||
|
return Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
LoginLogo(width: 190.0.w(), height: 88.0.h()),
|
||||||
|
SizedBox(height: 32.0.h()),
|
||||||
|
const LoginTitle(),
|
||||||
|
SizedBox(height: 32.0.h()),
|
||||||
|
|
||||||
|
LoginTextField(
|
||||||
|
controller: viewModel.usernameController,
|
||||||
|
focusNode: viewModel.usernameFocus,
|
||||||
|
label: AppStrings.usernameLabel,
|
||||||
|
iconPath: AssetsManager.userIcon,
|
||||||
|
fieldHeight: 60.0.h(),
|
||||||
|
borderRedus: 4.0.w(),
|
||||||
|
prefixIconPadding: 4.0.w(),
|
||||||
|
),
|
||||||
|
SizedBox(height: 16.0.h()),
|
||||||
|
|
||||||
|
LoginTextField(
|
||||||
|
controller: viewModel.passwordController,
|
||||||
|
focusNode: viewModel.passwordFocus,
|
||||||
|
label: AppStrings.passwordLabel,
|
||||||
|
iconPath: AssetsManager.passwordIcon,
|
||||||
|
prefixIconPadding: 4.0.w(),
|
||||||
|
isPassword: true,
|
||||||
|
obscureText: viewModel.obscurePassword,
|
||||||
|
fieldHeight: 60.0.h(),
|
||||||
|
onToggleVisibility: viewModel.togglePasswordVisibility,
|
||||||
|
borderRedus: 4.0.w(),
|
||||||
|
),
|
||||||
|
SizedBox(height: 32.0.h()),
|
||||||
|
|
||||||
|
if (viewModel.isLoading)
|
||||||
|
const CircularProgressIndicator()
|
||||||
|
else
|
||||||
|
BaseButton(
|
||||||
|
isEnabled: viewModel.isLoginEnabled,
|
||||||
|
onPressed:
|
||||||
|
viewModel.isLoginEnabled
|
||||||
|
? () async {
|
||||||
|
await viewModel.login();
|
||||||
|
if (viewModel.loggedInUser != null) {
|
||||||
|
HomeRouteData().go(context);
|
||||||
|
} else if (viewModel.errorMessage != null) {
|
||||||
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
|
SnackBar(
|
||||||
|
content: Text(viewModel.errorMessage!),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
: null,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -14,6 +14,7 @@ class BaseButton extends StatelessWidget {
|
|||||||
final double? borderWidth;
|
final double? borderWidth;
|
||||||
final double? borderRadius;
|
final double? borderRadius;
|
||||||
final double? elevation;
|
final double? elevation;
|
||||||
|
final double? width;
|
||||||
|
|
||||||
const BaseButton({
|
const BaseButton({
|
||||||
required this.isEnabled,
|
required this.isEnabled,
|
||||||
@@ -25,21 +26,22 @@ class BaseButton extends StatelessWidget {
|
|||||||
this.borderWidth,
|
this.borderWidth,
|
||||||
this.borderRadius,
|
this.borderRadius,
|
||||||
this.elevation,
|
this.elevation,
|
||||||
|
this.width,
|
||||||
super.key,
|
super.key,
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return SizedBox(
|
return SizedBox(
|
||||||
width: double.infinity,
|
width: width ?? double.infinity,
|
||||||
height: 55.0.h(),
|
height: 55.0.h(),
|
||||||
child: ElevatedButton(
|
child: ElevatedButton(
|
||||||
onPressed: isEnabled ? onPressed : null,
|
onPressed: isEnabled ? onPressed : null,
|
||||||
style: ElevatedButton.styleFrom(
|
style: ElevatedButton.styleFrom(
|
||||||
backgroundColor:
|
backgroundColor:
|
||||||
backgroundColor ??
|
backgroundColor ??
|
||||||
(isEnabled ? AppColors.mainBlue : Colors.grey[300]),
|
(isEnabled ? AppColors.mainBlue : AppColors.backgroundColor),
|
||||||
foregroundColor: textColor ?? Colors.white,
|
foregroundColor: textColor ?? AppColors.backgroundColor,
|
||||||
elevation: elevation ?? 0,
|
elevation: elevation ?? 0,
|
||||||
shape: RoundedRectangleBorder(
|
shape: RoundedRectangleBorder(
|
||||||
borderRadius: BorderRadius.circular(borderRadius ?? 28.0.w()),
|
borderRadius: BorderRadius.circular(borderRadius ?? 28.0.w()),
|
||||||
@@ -54,7 +56,7 @@ class BaseButton extends StatelessWidget {
|
|||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 16.0.sp(),
|
fontSize: 16.0.sp(),
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
color: textColor ?? Colors.white,
|
color: textColor ?? AppColors.backgroundColor,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ class LoginTextField extends StatelessWidget {
|
|||||||
width: 24.0.w(),
|
width: 24.0.w(),
|
||||||
height: 24.0.h(),
|
height: 24.0.h(),
|
||||||
colorFilter: ColorFilter.mode(
|
colorFilter: ColorFilter.mode(
|
||||||
focusNode.hasFocus ? Colors.black87 : Colors.grey,
|
focusNode.hasFocus ? AppColors.grey80 : AppColors.grey60,
|
||||||
BlendMode.srcIn,
|
BlendMode.srcIn,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -68,7 +68,7 @@ class LoginTextField extends StatelessWidget {
|
|||||||
width: 24.0.w(),
|
width: 24.0.w(),
|
||||||
height: 24.0.h(),
|
height: 24.0.h(),
|
||||||
colorFilter: ColorFilter.mode(
|
colorFilter: ColorFilter.mode(
|
||||||
focusNode.hasFocus ? Colors.black87 : Colors.grey,
|
focusNode.hasFocus ? AppColors.grey80 : AppColors.grey60,
|
||||||
BlendMode.srcIn,
|
BlendMode.srcIn,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:tm_app/core/theme/colors.dart';
|
||||||
|
|
||||||
import '../../../core/constants/strings.dart';
|
import '../../../core/constants/strings.dart';
|
||||||
import '../../../core/utils/size_config.dart';
|
import '../../../core/utils/size_config.dart';
|
||||||
@@ -20,7 +21,7 @@ class LoginTitle extends StatelessWidget {
|
|||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 14.0.sp(),
|
fontSize: 14.0.sp(),
|
||||||
fontWeight: FontWeight.w400,
|
fontWeight: FontWeight.w400,
|
||||||
color: Colors.grey,
|
color: AppColors.grey60,
|
||||||
),
|
),
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
),
|
),
|
||||||
|
|||||||
+27
-48
@@ -29,10 +29,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: async
|
name: async
|
||||||
sha256: "758e6d74e971c3e5aceb4110bfd6698efc7f501675bcfe0c775459a8140750eb"
|
sha256: d2872f9c19731c2e5f10444b14686eb7cc85c76274bd6c16e1816bff9a3bab63
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.13.0"
|
version: "2.12.0"
|
||||||
boolean_selector:
|
boolean_selector:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -101,10 +101,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: built_value
|
name: built_value
|
||||||
sha256: "0b1b12a0a549605e5f04476031cd0bc91ead1d7c8e830773a18ee54179b3cb62"
|
sha256: ba95c961bafcd8686d1cf63be864eb59447e795e124d98d6a27d91fcd13602fb
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "8.11.0"
|
version: "8.11.1"
|
||||||
characters:
|
characters:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -177,30 +177,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.1.1"
|
version: "3.1.1"
|
||||||
device_frame:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: device_frame
|
|
||||||
sha256: "7b2ebb2a09d6cc0f086b51bd1412d7be83e0170056a7290349169be41164c86a"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "1.4.0"
|
|
||||||
device_preview:
|
|
||||||
dependency: "direct main"
|
|
||||||
description:
|
|
||||||
name: device_preview
|
|
||||||
sha256: "88aa1cc73ee9a8ec771b309dcbc4000cc66b5d8456b825980997640ab1195bf5"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "1.3.1"
|
|
||||||
dio:
|
dio:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: dio
|
name: dio
|
||||||
sha256: "253a18bbd4851fecba42f7343a1df3a9a4c1d31a2c1b37e221086b4fa8c8dbc9"
|
sha256: d90ee57923d1828ac14e492ca49440f65477f4bb1263575900be731a3dac66a9
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "5.8.0+1"
|
version: "5.9.0"
|
||||||
dio_web_adapter:
|
dio_web_adapter:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -213,10 +197,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: fake_async
|
name: fake_async
|
||||||
sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44"
|
sha256: "6a95e56b2449df2273fd8c45a662d6947ce1ebb7aafe80e550a3f68297f3cacc"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.3.3"
|
version: "1.3.2"
|
||||||
ffi:
|
ffi:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -254,11 +238,6 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "5.0.0"
|
version: "5.0.0"
|
||||||
flutter_localizations:
|
|
||||||
dependency: transitive
|
|
||||||
description: flutter
|
|
||||||
source: sdk
|
|
||||||
version: "0.0.0"
|
|
||||||
flutter_svg:
|
flutter_svg:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@@ -337,10 +316,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: http
|
name: http
|
||||||
sha256: "2c11f3f94c687ee9bad77c171151672986360b2b001d109814ee7140b2cf261b"
|
sha256: bb2ce4590bc2667c96f318d68cac1b5a7987ec819351d32b1c987239a815e007
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.4.0"
|
version: "1.5.0"
|
||||||
http_multi_server:
|
http_multi_server:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -357,14 +336,6 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "4.1.2"
|
version: "4.1.2"
|
||||||
intl:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: intl
|
|
||||||
sha256: "3df61194eb431efc39c4ceba583b95633a403f46c9fd341e550ce0bfa50e9aa5"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "0.20.2"
|
|
||||||
io:
|
io:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -382,21 +353,29 @@ packages:
|
|||||||
source: hosted
|
source: hosted
|
||||||
version: "0.7.2"
|
version: "0.7.2"
|
||||||
json_annotation:
|
json_annotation:
|
||||||
dependency: transitive
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: json_annotation
|
name: json_annotation
|
||||||
sha256: "1ce844379ca14835a50d2f019a3099f419082cfdd231cd86a142af94dd5c6bb1"
|
sha256: "1ce844379ca14835a50d2f019a3099f419082cfdd231cd86a142af94dd5c6bb1"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "4.9.0"
|
version: "4.9.0"
|
||||||
|
json_serializable:
|
||||||
|
dependency: "direct dev"
|
||||||
|
description:
|
||||||
|
name: json_serializable
|
||||||
|
sha256: c50ef5fc083d5b5e12eef489503ba3bf5ccc899e487d691584699b4bdefeea8c
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "6.9.5"
|
||||||
leak_tracker:
|
leak_tracker:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: leak_tracker
|
name: leak_tracker
|
||||||
sha256: "6bb818ecbdffe216e81182c2f0714a2e62b593f4a4f13098713ff1685dfb6ab0"
|
sha256: c35baad643ba394b40aac41080300150a4f08fd0fd6a10378f8f7c6bc161acec
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "10.0.9"
|
version: "10.0.8"
|
||||||
leak_tracker_flutter_testing:
|
leak_tracker_flutter_testing:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -593,10 +572,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: shared_preferences_android
|
name: shared_preferences_android
|
||||||
sha256: "20cbd561f743a342c76c151d6ddb93a9ce6005751e7aa458baad3858bfbfb6ac"
|
sha256: "5bcf0772a761b04f8c6bf814721713de6f3e5d9d89caf8d3fe031b02a342379e"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.4.10"
|
version: "2.4.11"
|
||||||
shared_preferences_foundation:
|
shared_preferences_foundation:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -782,10 +761,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: vm_service
|
name: vm_service
|
||||||
sha256: ddfa8d30d89985b96407efce8acbdd124701f96741f2d981ca860662f1c0dc02
|
sha256: "0968250880a6c5fe7edc067ed0a13d4bae1577fe2771dcf3010d52c4a9d3ca14"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "15.0.0"
|
version: "14.3.1"
|
||||||
watcher:
|
watcher:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -843,5 +822,5 @@ packages:
|
|||||||
source: hosted
|
source: hosted
|
||||||
version: "3.1.3"
|
version: "3.1.3"
|
||||||
sdks:
|
sdks:
|
||||||
dart: ">=3.8.0 <4.0.0"
|
dart: ">=3.7.2 <4.0.0"
|
||||||
flutter: ">=3.32.0"
|
flutter: ">=3.27.0"
|
||||||
|
|||||||
+5
-1
@@ -20,7 +20,7 @@ dependencies:
|
|||||||
logger: ^2.6.0
|
logger: ^2.6.0
|
||||||
dio: ^5.8.0+1
|
dio: ^5.8.0+1
|
||||||
shared_preferences: ^2.5.3
|
shared_preferences: ^2.5.3
|
||||||
|
json_annotation: ^4.8.1
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
@@ -29,7 +29,11 @@ dev_dependencies:
|
|||||||
flutter_gen_runner:
|
flutter_gen_runner:
|
||||||
build_runner: ^2.5.4
|
build_runner: ^2.5.4
|
||||||
go_router_builder: ^3.0.0
|
go_router_builder: ^3.0.0
|
||||||
|
<<<<<<< HEAD
|
||||||
json_serializable: ^6.9.5
|
json_serializable: ^6.9.5
|
||||||
|
=======
|
||||||
|
json_serializable: ^6.7.1
|
||||||
|
>>>>>>> origin/refactor_dark_mood_repository
|
||||||
|
|
||||||
|
|
||||||
flutter:
|
flutter:
|
||||||
|
|||||||
Reference in New Issue
Block a user