step 3 : hapus ai_barcode_scanner, ai barcode, update permission_handler, flutter_map,latlong2

This commit is contained in:
sindhu
2025-04-11 13:39:17 +07:00
parent aa05bb5d51
commit 25fdce45f9
141 changed files with 19594 additions and 165 deletions

View File

@@ -0,0 +1,207 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import '/models/history_model.dart';
import '/screen/detail_history_screen/detail_history_screen.dart';
import '/widget/chip_type.dart';
import 'package:intl/intl.dart';
import '../../app/constant.dart';
import '../../provider/current_user_provider.dart';
class HistoryListCard extends HookConsumerWidget {
const HistoryListCard({
super.key,
required this.ListRiwayat,
});
final List<HistoryModel> ListRiwayat;
@override
Widget build(BuildContext context, WidgetRef ref) {
final mCourirID =
ref.watch(currentUserProvider)?.model.user?.mCourierID ?? "0";
return ListView.builder(
itemCount: ListRiwayat.length,
itemBuilder: (context, index) {
var data = ListRiwayat[index];
String originalDateString = data.cdate.toString();
DateTime originalDate =
DateFormat('dd-MM-yyyy HH:mm:ss').parse(originalDateString);
// String formattedDate = DateFormat.yMMMMd('id').format(originalDate);
String formattedDate = DateFormat('d MMM HH:mm').format(originalDate);
// Output: 30 Mei 2023
return Container(
margin: EdgeInsets.only(
top: Constant.getActualY(context: context, y: 24)),
padding: EdgeInsets.symmetric(
horizontal: Constant.getActualX(context: context, x: 31)),
child: ElevatedButton(
onPressed: () {
showModalBottomSheet(
enableDrag: true,
isScrollControlled: true,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(16),
topRight: Radius.circular(16)),
),
backgroundColor: Theme.of(context).scaffoldBackgroundColor,
context: context,
builder: (context) {
return DraggableScrollableSheet(
initialChildSize: 0.9,
maxChildSize: 0.95,
minChildSize: 0.5,
expand: false,
builder: (_, scrollController) => Stack(
children: [
Container(
padding: EdgeInsets.symmetric(
horizontal: Constant.getActualX(
context: context, x: 125)),
child: Divider(
thickness: 3,
color: Constant.textPrimary,
),
),
SingleChildScrollView(
controller: scrollController,
child: DetailHistoryScreen(
data: {
"id": "1",
"alamat": "Cabang Kertajaya",
"jarak": "1,2 KM",
"tanggal": "02 Desember 14:50",
"tipe": "Pengantaran hasil Instansi",
"tipe_id": 4
},
prop: DetailHistoryProp(
data.tipeid.toString(),
mCourirID,
data.id.toString()),
)),
],
));
},
);
},
style: ElevatedButton.styleFrom(
padding: const EdgeInsets.all(10),
elevation: 0,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(16))),
backgroundColor: data.ispending == 'N'
? Constant.historyCardColor
: Constant.historyCardColorPending,
foregroundColor: Colors.grey),
child: Column(
children: [
SizedBox(
height: Constant.getActualY(context: context, y: 14),
),
Row(
children: [
Image.asset(
"assets/icon_riwayat_motor.png",
width: Constant.getActualX(context: context, x: 64),
height: Constant.getActualX(context: context, x: 64),
),
SizedBox(
width: Constant.getActualX(context: context, x: 12),
),
Container(
height: Constant.getActualX(context: context, x: 70),
width: Constant.getActualX(context: context, x: 232),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Container(
constraints: BoxConstraints(
maxWidth: Constant.getActualX(
context: context, x: 130)),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
data.noSuratJalan.toString(),
textAlign: TextAlign.start,
style: Constant.caption1(context: context)
.copyWith(
fontWeight: FontWeight.w600,
color: Constant.primaryBlue),
),
Text(
data.nama.toString(),
maxLines: 2,
overflow: TextOverflow.ellipsis,
style: Constant.caption2(context: context)
.copyWith(
fontWeight: FontWeight.w600,
color: Constant.textBlack),
),
],
),
),
Container(
constraints: BoxConstraints(
maxWidth: Constant.getActualX(
context: context, x: 100)),
child: Text(
"${data.distance ?? '0'} Km",
style: Constant.heading3(context: context)
.copyWith(
fontWeight: FontWeight.w600,
color: Constant.textBlack),
),
)
],
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: Text(
formattedDate,
maxLines: 2,
overflow: TextOverflow.ellipsis,
style: Constant.caption1(context: context)
.copyWith(
fontWeight: FontWeight.w500,
color: Constant.textBlack),
),
),
Container(
constraints: BoxConstraints(
maxWidth: Constant.getActualX(
context: context, x: 150)),
child: ChipType(
name: data.tipe.toString(),
tipe: data.tipeid!,
isDetailHistory: false,
),
)
],
)
],
),
),
],
),
SizedBox(
height: Constant.getActualY(context: context, y: 14),
),
],
),
),
);
},
);
}
}

View File

@@ -0,0 +1,69 @@
import 'package:equatable/equatable.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import '/models/history_model.dart';
import '../../repository/history_screen_repository.dart';
import '/screen/history_screen/history_screen.dart';
import '../../models/pending_work_model.dart';
import '../../provider/dio_provider.dart';
import '../../repository/base_repository.dart';
import '../../repository/home_screen_repository.dart';
abstract class HistoryListState extends Equatable {
final DateTime date;
const HistoryListState(this.date);
@override
List<Object?> get props => [date];
}
class HistoryListStateInit extends HistoryListState {
HistoryListStateInit() : super(DateTime.now());
}
class HistoryListStateLoading extends HistoryListState {
HistoryListStateLoading() : super(DateTime.now());
}
class HistoryListStateError extends HistoryListState {
final String message;
HistoryListStateError({
required this.message,
}) : super(DateTime.now());
}
class HistoryListStateDone extends HistoryListState {
final List<HistoryModel> model;
HistoryListStateDone({
required this.model,
}) : super(DateTime.now());
}
//notifier
class HistoryListNotifier extends StateNotifier<HistoryListState> {
final Ref ref;
HistoryListNotifier({
required this.ref,
}) : super(HistoryListStateInit());
void getData(
{required String id, required String date, required String type}) async {
try {
state = HistoryListStateLoading();
final dio = ref.read(dioProvider);
final resp = await HistoryRepository(dio: dio)
.getData(date: date, id: id, type: type);
state = HistoryListStateDone(model: resp);
} catch (e) {
if (e is BaseRepositoryException) {
state = HistoryListStateError(message: e.message.toString());
} else {
state = HistoryListStateError(message: e.toString());
}
}
}
}
//provider
final HistoryListProvider =
StateNotifierProvider<HistoryListNotifier, HistoryListState>(
(ref) => HistoryListNotifier(ref: ref));

View File

@@ -0,0 +1,466 @@
import 'dart:async';
import 'dart:convert';
import 'package:dropdown_button2/dropdown_button2.dart';
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:intl/intl.dart';
import '/models/history_model.dart';
import '/models/history_type_model.dart';
import '/provider/history_filter_provider.dart';
import '/screen/history_screen/history_list_card.dart';
import '/screen/history_screen/history_list_provider.dart';
import '/screen/history_screen/history_type_provider.dart';
import 'package:loading_animation_widget/loading_animation_widget.dart';
// import 'package:eva_icons_flutter/eva_icons_flutter.dart';
import '../../app/constant.dart';
import '../../provider/current_user_provider.dart';
import '../../widget/header_widget.dart';
import '../../widget/snackbar_widget.dart';
class HistoryScreen extends HookConsumerWidget {
const HistoryScreen({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
final historyListData = useState<List<HistoryModel>>([]);
final historyListLoading = useState(false);
final isMounted = useIsMounted();
final mCourirID =
ref.watch(currentUserProvider)?.model.user?.mCourierID ?? "0";
final dateFilter =
DateFormat('d MMM y').format(ref.watch(dateFilterProvider));
final SelectedTypeFilter = ref.watch(selectedTypeProvider);
fetchData() {
ref.read(HistoryListProvider.notifier).getData(
id: mCourirID,
date: DateFormat('dd-MM-yyyy').format(ref.watch(dateFilterProvider)),
type: SelectedTypeFilter.tipeid.toString());
}
final dateInput = useTextEditingController(
text: DateFormat('yyyy-MM-dd').format(DateTime.now()));
// ref.watch(dateFilterProvider);
ref.listen<HistoryListState>(
HistoryListProvider,
(previous, next) {
if (next is HistoryListStateLoading) {
historyListLoading.value = true;
} else if (next is HistoryListStateError) {
print(next.message);
historyListLoading.value = false;
SanckbarWidget(context, next.message, snackbarType.error);
} else if (next is HistoryListStateDone) {
print(next.model);
historyListData.value = next.model;
historyListLoading.value = false;
}
},
);
useEffect(() {
// final cancellationSource = CancellationSource();
if (isMounted.call()) {
WidgetsBinding.instance.addPostFrameCallback((timeStamp) async {
fetchData();
});
}
return () {};
}, []);
return RefreshIndicator(
onRefresh: () async {
fetchData();
},
child: Container(
// color: const Color(0XFFF4F6F8),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
color: Colors.white,
height: Constant.getActualY(context: context, y: 56),
),
HeaderWidget(teks: "Riwayat"),
SizedBox(
height: Constant.getActualY(context: context, y: 24),
),
Container(
width: double.infinity,
margin: EdgeInsets.only(
left: Constant.getActualX(context: context, x: 31),
right: Constant.getActualX(context: context, x: 31)),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
Text(
SelectedTypeFilter.tipename.toString(),
style: Constant.body1(context: context)
.copyWith(fontWeight: FontWeight.w600),
),
SizedBox(
width: Constant.getActualX(context: context, x: 5),
),
Icon(
Icons.fiber_manual_record_rounded,
size: 9,
),
SizedBox(
width: Constant.getActualX(context: context, x: 5),
),
Chip(
label: Text(
dateFilter,
style: Constant.body3(context: context).copyWith(
fontWeight: FontWeight.w700,
color: Colors.grey.shade600),
),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(6))),
)
],
),
InkWell(
onTap: () {
showModalBottomSheet<void>(
isScrollControlled: true,
context: context,
builder: (BuildContext context) {
return HookConsumer(
builder: (BuildContext context, WidgetRef ref, a) {
final typeLoading = useState(false);
final typeData =
useState<List<HistoryTypeModel>>(List.empty());
final dateCtr = useTextEditingController(
// d MMMM y'
text: DateFormat('yyyy-MM-dd')
.format(ref.read(dateFilterProvider)));
final selectedType = useState<HistoryTypeModel>(
ref.watch(selectedTypeProvider));
getData() {
ref
.read(HistoryTypeListProvider.notifier)
.getHistoryType();
}
useEffect(() {
WidgetsBinding.instance
.addPostFrameCallback((timeStamp) async {
getData();
});
return () {};
}, []);
ref.listen(HistoryTypeListProvider, (previous, next) {
if (next is HistoryTypeListStateInit) {
typeLoading.value = true;
} else if (next is HistoryTypeListStateLoading) {
typeLoading.value = true;
} else if (next is HistoryTypeListStateError) {
typeLoading.value = false;
} else if (next is HistoryTypeListStateDone) {
print(jsonEncode(next.model));
typeData.value = next.model;
typeLoading.value = false;
}
});
return Container(
margin: EdgeInsets.symmetric(
horizontal: Constant.getActualX(
context: context, x: 31)),
height:
Constant.getActualY(context: context, y: 370),
child: Column(
// mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
SizedBox(
height: Constant.getActualY(
context: context, y: 20),
),
SizedBox(
width: Constant.getActualX(
context: context, x: 100),
child: Divider(
color: Colors.grey,
height: 2,
thickness: 2,
)),
SizedBox(
height: Constant.getActualY(
context: context, y: 20),
),
Text(
"Filter",
style: Constant.heading3(context: context)
.copyWith(
fontWeight: FontWeight.w600,
color: Constant.primaryBlue),
),
SizedBox(
height: Constant.getActualY(
context: context, y: 20),
),
TextField(
controller: dateCtr,
decoration: InputDecoration(
suffixIcon: Icon(Icons.today_rounded),
border: OutlineInputBorder(
borderRadius: BorderRadius.all(
Radius.circular(8))),
labelText:
"Tanggal (yyyy-mm-dd)" //label text of field
),
readOnly: true,
onTap: () async {
DateTime? pickedDate = await showDatePicker(
context: context,
initialDate:
DateTime.parse(dateCtr.text),
// initialDate:
// DateTime.parse(dateCtr.text),
firstDate: DateTime(1950),
initialEntryMode:
DatePickerEntryMode.calendarOnly,
//DateTime.now() - not to allow to choose before today.
lastDate: DateTime(2100));
if (pickedDate != null) {
print(
pickedDate); //pickedDate output format => 2021-03-10 00:00:00.000
String formattedDate =
DateFormat('yyyy-MM-dd')
.format(pickedDate);
print(
formattedDate); //formatted date output using intl package => 2021-03-16
dateCtr.text =
formattedDate; //set output date to TextField value.
// ref
// .read(dateFilterProvider.notifier)
// .state = pickedDate;
} else {}
},
),
SizedBox(
height: Constant.getActualY(
context: context, y: 20),
),
Container(
// width: Constant.getActualX(
// context: context, x: 320),
// height: Constant.getActualY(
// context: context, y: 56),
child: DropdownButtonHideUnderline(
child: DropdownButton2<HistoryTypeModel>(
isExpanded: true,
hint: Row(
children: [
Expanded(
child: Text(
'Select Item',
style: Constant.body1(
context: context)
.copyWith(
fontWeight:
FontWeight.w600,
color:
Constant.primaryDark),
overflow: TextOverflow.ellipsis,
),
),
],
),
items: typeData.value
.map((HistoryTypeModel option) {
return DropdownMenuItem<
HistoryTypeModel>(
value: option,
child: Text(
option.tipename.toString(),
style: Constant.body1(
context: context)
.copyWith(
color: Constant.textBlack,
fontWeight:
FontWeight.w600),
),
);
}).toList(),
value: selectedType.value,
onChanged: (HistoryTypeModel? newValue) {
selectedType.value = newValue!;
// if (newValue) {
// ref
// .read(selectedTypeProvider.notifier)
// .state = newValue!;
print(
"Branch ID Selected : ${selectedType.value.tipename}");
print(
"Branch Code Selected : ${selectedType.value.tipename}");
// }
},
buttonStyleData: ButtonStyleData(
padding: EdgeInsets.only(
left: Constant.getActualX(
context: context, x: 10),
right: Constant.getActualX(
context: context, x: 10),
),
decoration: BoxDecoration(
// color: Colors.white,
border: Border.all(
color: Colors.grey.shade400),
borderRadius:
BorderRadius.circular(8),
),
// elevation: 2,
),
iconStyleData: IconStyleData(
icon: typeLoading.value
? LoadingAnimationWidget
.discreteCircle(
color: Constant.primaryBlue,
size: 20)
: Icon(
Icons
.keyboard_arrow_down_outlined,
),
iconSize: 24,
iconEnabledColor: Constant.textBlack,
iconDisabledColor: Colors.grey,
),
dropdownStyleData: DropdownStyleData(
maxHeight: Constant.getActualY(
context: context, y: 120),
width: Constant.getActualX(
context: context, x: 320),
padding: EdgeInsets.only(
top: Constant.getActualY(
context: context, y: 10),
left: Constant.getActualX(
context: context, x: 10),
right: Constant.getActualX(
context: context, x: 10),
bottom: Constant.getActualY(
context: context, y: 10),
),
decoration: BoxDecoration(
// color: Constant.backgroundWhite,
borderRadius:
BorderRadius.circular(8),
),
// elevation: 8,
scrollbarTheme: ScrollbarThemeData(
radius: const Radius.circular(40),
thickness:
MaterialStateProperty.all<double>(
6),
thumbVisibility:
MaterialStateProperty.all<bool>(
true),
),
),
menuItemStyleData: MenuItemStyleData(
height: Constant.getActualY(
context: context, y: 56),
padding: EdgeInsets.only(
top: Constant.getActualY(
context: context, y: 10),
left: Constant.getActualX(
context: context, x: 10),
right: Constant.getActualX(
context: context, x: 10),
),
),
),
),
),
SizedBox(
height: Constant.getActualY(
context: context, y: 40),
),
Container(
width: double.infinity,
height: Constant.getActualY(
context: context, y: 48),
child: ElevatedButton(
onPressed: () {
ref
.read(selectedTypeProvider.notifier)
.state = selectedType.value;
ref
.read(dateFilterProvider.notifier)
.state = DateTime.parse(dateCtr.text);
ref
.read(HistoryListProvider.notifier)
.getData(
id: mCourirID,
date: DateFormat('dd-MM-yyyy')
.format(ref.watch(
dateFilterProvider)),
type: ref
.watch(selectedTypeProvider)
.tipeid!);
Navigator.pop(context);
},
child: Text(
"Cari",
style: Constant.heading3(context: context)
.copyWith(
fontWeight: FontWeight.w700),
),
style: ButtonStyle(
backgroundColor:
MaterialStateColor.resolveWith(
(st) => Constant.primaryBlue),
shape: MaterialStateProperty.all<
RoundedRectangleBorder>(
RoundedRectangleBorder(
borderRadius:
BorderRadius.circular(8),
// side: BorderSide(color: Colors.red),
),
),
shadowColor: MaterialStateProperty.all(
const Color(0xffff48423d)),
elevation: MaterialStateProperty.all(4.0),
),
),
)
],
),
);
});
},
);
},
child: Icon(
Icons.filter_alt_outlined,
size: 25,
),
)
],
),
),
Container(
// color: Colors.red,
height: Constant.getActualY(context: context, y: 588),
child: historyListLoading.value
? Center(
child: LoadingAnimationWidget.fourRotatingDots(
color: Constant.primaryBlue, size: 50),
)
: HistoryListCard(ListRiwayat: historyListData.value),
),
],
)),
);
}
}

View File

@@ -0,0 +1,68 @@
import 'package:equatable/equatable.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import '/models/history_model.dart';
import '../../repository/history_screen_repository.dart';
import '/screen/history_screen/history_screen.dart';
import '../../models/history_type_model.dart';
import '../../models/pending_work_model.dart';
import '../../provider/dio_provider.dart';
import '../../repository/base_repository.dart';
import '../../repository/home_screen_repository.dart';
abstract class HistoryTypeListState extends Equatable {
final DateTime date;
const HistoryTypeListState(this.date);
@override
List<Object?> get props => [date];
}
class HistoryTypeListStateInit extends HistoryTypeListState {
HistoryTypeListStateInit() : super(DateTime.now());
}
class HistoryTypeListStateLoading extends HistoryTypeListState {
HistoryTypeListStateLoading() : super(DateTime.now());
}
class HistoryTypeListStateError extends HistoryTypeListState {
final String message;
HistoryTypeListStateError({
required this.message,
}) : super(DateTime.now());
}
class HistoryTypeListStateDone extends HistoryTypeListState {
final List<HistoryTypeModel> model;
HistoryTypeListStateDone({
required this.model,
}) : super(DateTime.now());
}
//notifier
class HistoryTypeListNotifier extends StateNotifier<HistoryTypeListState> {
final Ref ref;
HistoryTypeListNotifier({
required this.ref,
}) : super(HistoryTypeListStateInit());
void getHistoryType() async {
try {
state = HistoryTypeListStateLoading();
final dio = ref.read(dioProvider);
final resp = await HistoryRepository(dio: dio).getHistoryType();
state = HistoryTypeListStateDone(model: resp);
} catch (e) {
if (e is BaseRepositoryException) {
state = HistoryTypeListStateError(message: e.message.toString());
} else {
state = HistoryTypeListStateError(message: e.toString());
}
}
}
}
//provider
final HistoryTypeListProvider =
StateNotifierProvider<HistoryTypeListNotifier, HistoryTypeListState>(
(ref) => HistoryTypeListNotifier(ref: ref));