implemented IconPicker for Car class
This commit is contained in:
136
lib/bups/iconpicker-1.dart
Normal file
136
lib/bups/iconpicker-1.dart
Normal file
@@ -0,0 +1,136 @@
|
||||
import 'dart:convert';
|
||||
import 'dart:async';
|
||||
import 'package:flutter/material.dart';
|
||||
// import '../images/car_icons.svg';
|
||||
|
||||
class IconPicker extends StatefulWidget {
|
||||
IconPicker({super.key});
|
||||
|
||||
late final String? selectedIcon;
|
||||
|
||||
@override
|
||||
State<IconPicker> createState() => _IconPickerState();
|
||||
}
|
||||
|
||||
class _IconPickerState extends State<IconPicker> {
|
||||
late Future mfst;
|
||||
late final Future<String> manifestJson;
|
||||
late final Future<List<String>> icons;
|
||||
late List<String> iconList;
|
||||
late List<String> iconNames;
|
||||
late Map iconMap;
|
||||
late List<String> searchableList = [];
|
||||
late List<String> items;
|
||||
|
||||
TextEditingController editingController = TextEditingController();
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
icons = loadAssets();
|
||||
// iconNames = buildIconList(icons);
|
||||
}
|
||||
|
||||
Future<List<String>> loadAssets() async {
|
||||
final manifestJson =
|
||||
await DefaultAssetBundle.of(context).loadString('AssetManifest.json');
|
||||
// ignore: no_leading_underscores_for_local_identifiers
|
||||
final _icons = json
|
||||
.decode(manifestJson)
|
||||
.keys
|
||||
.where((String key) => key.startsWith('images/car_icons/'))
|
||||
.toList();
|
||||
return _icons;
|
||||
}
|
||||
|
||||
List<String> buildIconList(List icons) {
|
||||
List<String> iN = [];
|
||||
for (var i in icons) {
|
||||
iN.add(i.substring(17, i.length - 4));
|
||||
}
|
||||
return iN;
|
||||
}
|
||||
|
||||
void filterSearch(String query, List<String> iconList) {
|
||||
if (query.isNotEmpty) {
|
||||
for (var item in iconList) {
|
||||
if (item.contains(query)) {
|
||||
searchableList.add(item);
|
||||
}
|
||||
}
|
||||
setState(() {
|
||||
items.clear();
|
||||
items.addAll(searchableList);
|
||||
print(items);
|
||||
});
|
||||
return;
|
||||
} else {
|
||||
setState(() {
|
||||
items.clear();
|
||||
items.addAll(iconList);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
// mfst = DefaultAssetBundle.of(context).loadString('AssetManifest.json');
|
||||
// icons = json.decode(mfst).keys.where((String key) => key.startsWith('assets/images/car_icons_svg')).toList();
|
||||
// icons = loadAssets() as List;
|
||||
return FutureBuilder(
|
||||
future: icons,
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.connectionState == ConnectionState.waiting) {
|
||||
return const Center(child: CircularProgressIndicator());
|
||||
} else {
|
||||
if (snapshot.error != null) {
|
||||
return const Center(
|
||||
child: Text('An error occurred'),
|
||||
);
|
||||
} else {
|
||||
iconList = snapshot.data!;
|
||||
iconNames = buildIconList(iconList);
|
||||
print('iconlist is ${iconList.sublist(0, 5)}...');
|
||||
print('iconNames is ${iconNames.sublist(0, 5)}...');
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: const Text('test'),
|
||||
backgroundColor: const Color.fromARGB(255, 185, 47, 5),
|
||||
),
|
||||
body: Column(children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: TextField(
|
||||
onChanged: (value) {
|
||||
filterSearch(value, snapshot.data!);
|
||||
},
|
||||
controller: editingController,
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: ListView.builder(
|
||||
itemCount: iconList.length,
|
||||
itemBuilder: (context, index) => ListTile(
|
||||
leading: CircleAvatar(
|
||||
backgroundImage: AssetImage(iconList[index]),
|
||||
backgroundColor: Colors.white,
|
||||
),
|
||||
title: Text(iconNames[index]),
|
||||
onTap: (() => VoidCallback)),
|
||||
))
|
||||
]));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/* Widget build(BuildContext context) {
|
||||
return ListView.builder(
|
||||
itemCount: icons.length,
|
||||
itemBuilder: (context, index) => ListTile(
|
||||
leading: Image(image: AssetImage(icons[index])),
|
||||
title: const Text('title'),
|
||||
),
|
||||
);
|
||||
} */
|
||||
}
|
||||
@@ -70,6 +70,20 @@ class MyDrawer extends StatelessWidget {
|
||||
print('dbsetup');
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
leading: const Icon(Icons.tune),
|
||||
title: const Text('IconPicker'),
|
||||
onTap: () {
|
||||
showDialog(
|
||||
barrierColor: Colors.black.withOpacity(.5),
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return IconPicker();
|
||||
});
|
||||
/* Navigator.of(context).push(
|
||||
MaterialPageRoute(builder: (context) => IconPicker())); */
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
leading: const Icon(Icons.info_outline),
|
||||
title: const Text('About'),
|
||||
|
||||
@@ -5,8 +5,9 @@ class Car {
|
||||
static const colNickname = 'nickname';
|
||||
static const colPlate = 'plate';
|
||||
static const colMileage = 'mileage';
|
||||
static const colIcon = 'icon';
|
||||
|
||||
Car({this.id, this.vin, this.plate, this.nickname, this.mileage});
|
||||
Car({this.id, this.vin, this.plate, this.nickname, this.mileage, this.icon});
|
||||
|
||||
Car.fromMap(Map<String, dynamic> map) {
|
||||
id = map[colId];
|
||||
@@ -14,6 +15,7 @@ class Car {
|
||||
nickname = map[colNickname];
|
||||
plate = map[colPlate];
|
||||
mileage = map[colMileage];
|
||||
icon = map[colIcon];
|
||||
}
|
||||
|
||||
int? id;
|
||||
@@ -21,6 +23,7 @@ class Car {
|
||||
String? plate;
|
||||
String? nickname;
|
||||
int? mileage;
|
||||
String? icon;
|
||||
|
||||
Map<String, dynamic> toMap() {
|
||||
var map = <String, dynamic>{
|
||||
@@ -28,6 +31,7 @@ class Car {
|
||||
colPlate: plate,
|
||||
colNickname: nickname,
|
||||
colMileage: mileage,
|
||||
colIcon: icon,
|
||||
};
|
||||
// if (id != null) {
|
||||
// map[colId] = id; //not sure https://www.youtube.com/watch?v=tj7Lj9a3fyM
|
||||
|
||||
@@ -9,6 +9,7 @@ import 'package:dash/screens/screens.dart';
|
||||
class CarDetailScreen extends StatefulWidget {
|
||||
const CarDetailScreen({super.key, required this.carIndex});
|
||||
final int carIndex;
|
||||
// late Car car;
|
||||
|
||||
@override
|
||||
State<CarDetailScreen> createState() => _CarDetailScreenState();
|
||||
@@ -20,13 +21,13 @@ class _CarDetailScreenState extends State<CarDetailScreen> {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
// late Car car = Provider.of<GarageModel>(context).cars[widget.carIndex];
|
||||
late Car car = Provider.of<GarageModel>(context).cars[widget.carIndex];
|
||||
// late Car car = context.watch<GarageModel>()_cars[widget.carIndex];
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
backgroundColor: const Color.fromARGB(255, 185, 47, 5),
|
||||
// title: Text(car.nickname ?? ""),
|
||||
title: const Text("View Car"),
|
||||
title: Text(car.nickname ?? ""),
|
||||
// title: const Text("View Car"),
|
||||
),
|
||||
body: Padding(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
@@ -36,7 +37,6 @@ class _CarDetailScreenState extends State<CarDetailScreen> {
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||
children: [
|
||||
const Text("plh img picker"),
|
||||
Center(
|
||||
// edit car screen
|
||||
child: Ink(
|
||||
@@ -58,11 +58,6 @@ class _CarDetailScreenState extends State<CarDetailScreen> {
|
||||
),
|
||||
],
|
||||
),
|
||||
IconButton(
|
||||
iconSize: 48.0,
|
||||
icon: const Icon(Icons.directions_car),
|
||||
onPressed: (() => VoidCallback),
|
||||
),
|
||||
Consumer<GarageModel>(
|
||||
builder: (context, garage, child) => Column(
|
||||
children: [
|
||||
@@ -71,6 +66,11 @@ class _CarDetailScreenState extends State<CarDetailScreen> {
|
||||
Text("License Plate: ${garage.cars[widget.carIndex].plate}"),
|
||||
Text(
|
||||
"Mileage: ${garage.cars[widget.carIndex].mileage.toString()}"),
|
||||
CircleAvatar(
|
||||
backgroundImage: AssetImage(
|
||||
garage.cars[widget.carIndex].icon ??
|
||||
'images/car.png'),
|
||||
backgroundColor: Colors.white),
|
||||
],
|
||||
),
|
||||
),
|
||||
@@ -97,10 +97,10 @@ class CarTxns extends StatefulWidget {
|
||||
final int carIndex;
|
||||
|
||||
@override
|
||||
State<CarTxns> createState() => _CurrentCar();
|
||||
State<CarTxns> createState() => _CarTxns();
|
||||
}
|
||||
|
||||
class _CurrentCar extends State<CarTxns> {
|
||||
class _CarTxns extends State<CarTxns> {
|
||||
late Future _txns;
|
||||
late Car car;
|
||||
|
||||
@@ -112,10 +112,22 @@ class _CurrentCar extends State<CarTxns> {
|
||||
super.initState();
|
||||
}
|
||||
|
||||
Icon getIcon(String? txntype) {
|
||||
if (txntype == 'Gas') {
|
||||
return (const Icon(Icons.local_gas_station));
|
||||
} else if (txntype == 'Oil') {
|
||||
return (const Icon(Icons.water_drop));
|
||||
} else if (txntype == 'Other') {
|
||||
return (const Icon(Icons.build));
|
||||
} else {
|
||||
return (const Icon(Icons.question_mark));
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
// car =
|
||||
// Provider.of<GarageModel>(context, listen: false).cars[widget.carIndex];
|
||||
// Provider.of<GarageModel>(context, listen: false).cars[widget.carIndex];
|
||||
// _txns = Provider.of<GarageModel>(context, listen: false).getTxns(car.id!);
|
||||
return FutureBuilder(
|
||||
future: _txns,
|
||||
@@ -139,7 +151,7 @@ class _CurrentCar extends State<CarTxns> {
|
||||
// dense: true, //only affects text, use visualDensity instead
|
||||
visualDensity:
|
||||
const VisualDensity(horizontal: 0, vertical: -4),
|
||||
leading: const Icon(Icons.local_gas_station),
|
||||
leading: getIcon(garage.txns[index].txntype),
|
||||
title: Text(garage.txns[index].txntype ?? "type"),
|
||||
subtitle: Text(garage.txns[index].note ?? "note"),
|
||||
onTap: (() => VoidCallback)),
|
||||
|
||||
@@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:dash/utils/garage_model.dart';
|
||||
import 'package:dash/models/car.dart';
|
||||
import 'package:dash/screens/iconpicker.dart';
|
||||
|
||||
class EditCarScreen extends StatefulWidget {
|
||||
const EditCarScreen({super.key, required this.carIndex});
|
||||
@@ -16,6 +17,8 @@ class _EditCarScreenState extends State<EditCarScreen> {
|
||||
late GarageModel garage;
|
||||
late Car car;
|
||||
late int carIndex = widget.carIndex;
|
||||
late IconPicker ip = IconPicker();
|
||||
late String selectedIcon = 'images/car.png';
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
@@ -98,6 +101,22 @@ class _EditCarScreenState extends State<EditCarScreen> {
|
||||
return null;
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
leading: CircleAvatar(
|
||||
backgroundImage: AssetImage(car.icon ?? selectedIcon),
|
||||
backgroundColor: Colors.white),
|
||||
title: const Text("Change Icon"),
|
||||
onTap: () => showDialog(
|
||||
barrierColor: Colors.black.withOpacity(.5),
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return ip;
|
||||
}).then((value) => setState(
|
||||
() {
|
||||
// selectedIcon = ip.selectedIcon;
|
||||
selectedIcon = value;
|
||||
},
|
||||
))),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 4.0),
|
||||
child: ElevatedButton(
|
||||
@@ -107,6 +126,7 @@ class _EditCarScreenState extends State<EditCarScreen> {
|
||||
//validate form
|
||||
updateForm
|
||||
.save(); //save values (reqd before putting them anywhere)
|
||||
car.icon = selectedIcon;
|
||||
garage.update(car, carIndex);
|
||||
updateForm.reset();
|
||||
Navigator.pop(context);
|
||||
|
||||
@@ -2,7 +2,7 @@ import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:dash/utils/garage_model.dart';
|
||||
import 'package:dash/models/car.dart';
|
||||
import '../utils/garage_model.dart';
|
||||
import 'package:dash/screens/screens.dart';
|
||||
|
||||
class NewCarScreen extends StatefulWidget {
|
||||
const NewCarScreen({super.key});
|
||||
@@ -14,6 +14,8 @@ class NewCarScreen extends StatefulWidget {
|
||||
class _NewCarScreenState extends State<NewCarScreen> {
|
||||
final GlobalKey<FormState> formKey = GlobalKey<FormState>();
|
||||
Car car = Car(); //initialization is required
|
||||
late IconPicker ip = IconPicker();
|
||||
late String selectedIcon = 'images/car.png';
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@@ -29,7 +31,6 @@ class _NewCarScreenState extends State<NewCarScreen> {
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
//new car form text fields
|
||||
TextFormField(
|
||||
decoration: const InputDecoration(
|
||||
labelText: 'Nickname',
|
||||
@@ -81,6 +82,22 @@ class _NewCarScreenState extends State<NewCarScreen> {
|
||||
return null;
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
leading: CircleAvatar(
|
||||
backgroundImage: AssetImage(selectedIcon),
|
||||
backgroundColor: Colors.white),
|
||||
title: const Text("Change Icon"),
|
||||
onTap: () => showDialog(
|
||||
barrierColor: Colors.black.withOpacity(.5),
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return ip;
|
||||
}).then((value) => setState(
|
||||
() {
|
||||
// selectedIcon = ip.selectedIcon;
|
||||
selectedIcon = value;
|
||||
},
|
||||
))),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 16.0),
|
||||
child: ElevatedButton(
|
||||
@@ -96,6 +113,7 @@ class _NewCarScreenState extends State<NewCarScreen> {
|
||||
vin: car.vin,
|
||||
nickname: car.nickname,
|
||||
plate: car.plate,
|
||||
icon: selectedIcon,
|
||||
mileage: car.mileage);
|
||||
});
|
||||
// var garage = context.read<GarageModel>();
|
||||
|
||||
97
lib/screens/iconpicker.dart
Normal file
97
lib/screens/iconpicker.dart
Normal file
@@ -0,0 +1,97 @@
|
||||
import 'dart:convert';
|
||||
import 'dart:async';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class IconPicker extends StatefulWidget {
|
||||
IconPicker({super.key});
|
||||
|
||||
late String selectedIcon = 'images/car.png';
|
||||
|
||||
@override
|
||||
State<IconPicker> createState() => _IconPickerState();
|
||||
}
|
||||
|
||||
class _IconPickerState extends State<IconPicker> {
|
||||
late Future<String> manifestJson;
|
||||
late List<String> icons;
|
||||
late List<String> iconList;
|
||||
late List<String> items;
|
||||
|
||||
TextEditingController editingController = TextEditingController();
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
loadAssets();
|
||||
}
|
||||
|
||||
Future<List<String>> loadAssets() async {
|
||||
final manifestJson =
|
||||
await DefaultAssetBundle.of(context).loadString('AssetManifest.json');
|
||||
// ignore: no_leading_underscores_for_local_identifiers
|
||||
final _icons = await json
|
||||
.decode(manifestJson)
|
||||
.keys
|
||||
.where((String key) => key.startsWith('images/car_icons/'))
|
||||
.toList();
|
||||
setState(() {
|
||||
icons = _icons;
|
||||
items = _icons;
|
||||
});
|
||||
return _icons;
|
||||
}
|
||||
|
||||
void runFilter(String query) {
|
||||
List<String> results = [];
|
||||
if (query.isEmpty) {
|
||||
results = icons;
|
||||
} else {
|
||||
results = icons
|
||||
.where((i) => i.substring(17, i.length - 4).contains(query))
|
||||
.toList();
|
||||
}
|
||||
setState(() {
|
||||
items = results;
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Dialog(
|
||||
child: Column(children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: TextField(
|
||||
decoration: const InputDecoration(
|
||||
prefixIcon: Icon(Icons.search),
|
||||
hintText: "Search icons",
|
||||
),
|
||||
onChanged: (value) {
|
||||
// filterSearch(value, iconList);
|
||||
runFilter(value);
|
||||
print('items found: $items');
|
||||
},
|
||||
// controller: editingController,
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: ListView.builder(
|
||||
itemCount: items.length,
|
||||
itemBuilder: (context, index) => ListTile(
|
||||
leading: CircleAvatar(
|
||||
// backgroundImage: AssetImage(iconList[index]),
|
||||
backgroundImage: AssetImage(items[index]),
|
||||
backgroundColor: Colors.white,
|
||||
),
|
||||
title: Text(items[index].substring(17, items[index].length - 4)),
|
||||
// title: Text(items[index]),
|
||||
onTap: () =>
|
||||
Navigator.of(context, rootNavigator: true).pop(items[index]),
|
||||
// onTap: (() => setState(() {
|
||||
// widget.selectedIcon = items[index];
|
||||
// })))),
|
||||
),
|
||||
)),
|
||||
]));
|
||||
}
|
||||
}
|
||||
@@ -4,3 +4,4 @@ export 'package:dash/screens/car_detail.dart';
|
||||
export 'package:dash/screens/car_edit.dart';
|
||||
export 'package:dash/screens/txn_new.dart';
|
||||
export 'package:dash/screens/txn_type.dart';
|
||||
export 'package:dash/screens/iconpicker.dart';
|
||||
|
||||
@@ -79,7 +79,14 @@ class _NewTxnScreenState extends State<NewTxnScreen> {
|
||||
decoration: const InputDecoration(
|
||||
labelText: 'Cost',
|
||||
),
|
||||
initialValue: "0",
|
||||
initialValue: "",
|
||||
onTap: () {
|
||||
final ft = TextEditingController();
|
||||
ft.clear();
|
||||
setState(() {
|
||||
ft.text = "";
|
||||
});
|
||||
},
|
||||
onSaved: (val) =>
|
||||
setState(() => txn.cost = double.parse(val ?? "0")),
|
||||
keyboardType: TextInputType.number,
|
||||
@@ -117,8 +124,6 @@ class _NewTxnScreenState extends State<NewTxnScreen> {
|
||||
setState(() {
|
||||
txn.datetime = DateTime.now().millisecondsSinceEpoch;
|
||||
txn.txntype = txnType.selectedText;
|
||||
print(
|
||||
"txntype set to ${txn.txntype} from radio ${txnType.selectedText}");
|
||||
txn.carid = car.id;
|
||||
car.mileage = txn.mileage; // update car mileage too
|
||||
});
|
||||
|
||||
@@ -32,7 +32,9 @@ class TxnTypeState extends State<TxnType> {
|
||||
|
||||
Widget rIcon(
|
||||
{required int index, required String text, required IconData icon}) {
|
||||
return Container(
|
||||
return AnimatedContainer(
|
||||
duration: const Duration(milliseconds: 300),
|
||||
curve: Curves.easeIn,
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
decoration: BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
|
||||
@@ -43,7 +43,8 @@ class DbHelperSqlite {
|
||||
${Car.colVin} TEXT UNIQUE,
|
||||
${Car.colNickname} TEXT,
|
||||
${Car.colMileage} INTEGER,
|
||||
${Car.colPlate} TEXT);
|
||||
${Car.colPlate} TEXT,
|
||||
${Car.colIcon} TEXT);
|
||||
''');
|
||||
await db.execute('''
|
||||
CREATE TABLE ${Txn.tblTxns} (
|
||||
|
||||
@@ -120,7 +120,10 @@ class _Garage extends State<Garage> {
|
||||
return ListView.separated(
|
||||
itemCount: garage._cars.length,
|
||||
itemBuilder: (context, index) => ListTile(
|
||||
leading: const Icon(Icons.directions_car),
|
||||
leading: CircleAvatar(
|
||||
backgroundImage: AssetImage(
|
||||
garage.cars[index].icon ?? 'images/car.png'),
|
||||
backgroundColor: Colors.white),
|
||||
title: Text(garage.cars[index].nickname ?? "nick_ph"),
|
||||
subtitle: Text(garage.cars[index].vin ?? "vin_ph"),
|
||||
onTap: () {
|
||||
|
||||
Reference in New Issue
Block a user