feat:synchro stores
parent
49115109d5
commit
394cf68976
Binary file not shown.
|
After Width: | Height: | Size: 3.4 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 20 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 15 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 16 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 17 KiB |
|
|
@ -0,0 +1,38 @@
|
||||||
|
import 'package:objectbox/objectbox.dart';
|
||||||
|
import 'package:mobdr/objectbox.g.dart';
|
||||||
|
|
||||||
|
// ignore_for_file: public_member_api_docs
|
||||||
|
|
||||||
|
@Entity()
|
||||||
|
class Etab {
|
||||||
|
// specify the id
|
||||||
|
@Id()
|
||||||
|
int id = 0;
|
||||||
|
|
||||||
|
int id_etab;
|
||||||
|
String nom;
|
||||||
|
String mail;
|
||||||
|
String tel;
|
||||||
|
String url_photo_principale;
|
||||||
|
String longitude;
|
||||||
|
String latitude;
|
||||||
|
|
||||||
|
Etab(
|
||||||
|
{this.id = 0,
|
||||||
|
required this.id_etab,
|
||||||
|
required this.nom,
|
||||||
|
required this.mail,
|
||||||
|
required this.tel,
|
||||||
|
required this.url_photo_principale,
|
||||||
|
required this.longitude,
|
||||||
|
required this.latitude});
|
||||||
|
|
||||||
|
Etab.fromJson(Map<String, dynamic> json)
|
||||||
|
: id_etab = json['id_etab'],
|
||||||
|
nom = json['nom'],
|
||||||
|
mail = json['mail'],
|
||||||
|
tel = json['tel'],
|
||||||
|
url_photo_principale = json['url_photo_principale'],
|
||||||
|
longitude = json['longitude'],
|
||||||
|
latitude = json['latitude'];
|
||||||
|
}
|
||||||
|
|
@ -20,9 +20,14 @@ class ApiProvider {
|
||||||
try {
|
try {
|
||||||
dio.options.headers['content-Type'] = 'application/json';
|
dio.options.headers['content-Type'] = 'application/json';
|
||||||
dio.options.headers['Accept'] = 'application/json';
|
dio.options.headers['Accept'] = 'application/json';
|
||||||
|
dio.options.headers['Cookie'] = "pguid=${SharedPrefs().guid}";
|
||||||
|
|
||||||
dio.options.connectTimeout = Duration(seconds: 5);
|
dio.options.connectTimeout = Duration(seconds: 5);
|
||||||
dio.options.receiveTimeout = Duration(seconds: 4);
|
dio.options.receiveTimeout = Duration(seconds: 4);
|
||||||
dio.options.queryParameters = body;
|
|
||||||
|
if (body != null) {
|
||||||
|
dio.options.queryParameters = body;
|
||||||
|
}
|
||||||
|
|
||||||
return await dio.get(url);
|
return await dio.get(url);
|
||||||
} on DioError catch (e) {
|
} on DioError catch (e) {
|
||||||
|
|
@ -196,6 +201,29 @@ class ApiProvider {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Synchronize stores
|
||||||
|
Future<String> SyncEtablissements() async {
|
||||||
|
try {
|
||||||
|
var body = null;
|
||||||
|
response = await getCrud(
|
||||||
|
ApiConstants.baseUrl +
|
||||||
|
ApiConstants.externalEndpoint +
|
||||||
|
ApiConstants.restEndpoint +
|
||||||
|
'/mobDR/etablissement',
|
||||||
|
body);
|
||||||
|
|
||||||
|
if (response.statusCode == STATUS_OK) {
|
||||||
|
/// create box etab
|
||||||
|
objectbox.addEtabs(response.data['boutiques']);
|
||||||
|
return 'OK';
|
||||||
|
} else {
|
||||||
|
return response.statusMessage ?? 'Unknow error ...';
|
||||||
|
}
|
||||||
|
} catch (ex) {
|
||||||
|
return ex.toString(); // return ex.response!.data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Future<String> getExample(apiToken) async {
|
Future<String> getExample(apiToken) async {
|
||||||
response =
|
response =
|
||||||
await getConnect(ApiConstants.baseUrl + '/example/getData', apiToken);
|
await getConnect(ApiConstants.baseUrl + '/example/getData', apiToken);
|
||||||
|
|
|
||||||
|
|
@ -114,9 +114,58 @@
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"relations": []
|
"relations": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "5:6220645616537106928",
|
||||||
|
"lastPropertyId": "9:4862523104151141465",
|
||||||
|
"name": "Etab",
|
||||||
|
"properties": [
|
||||||
|
{
|
||||||
|
"id": "1:2951125380051176697",
|
||||||
|
"name": "id",
|
||||||
|
"type": 6,
|
||||||
|
"flags": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "2:986806885009634082",
|
||||||
|
"name": "id_etab",
|
||||||
|
"type": 6
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "3:2138930560668315243",
|
||||||
|
"name": "nom",
|
||||||
|
"type": 9
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "4:6458474884283325627",
|
||||||
|
"name": "mail",
|
||||||
|
"type": 9
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "5:8380062137599693463",
|
||||||
|
"name": "tel",
|
||||||
|
"type": 9
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "7:5547045221255607235",
|
||||||
|
"name": "longitude",
|
||||||
|
"type": 9
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "8:5768827910047585940",
|
||||||
|
"name": "latitude",
|
||||||
|
"type": 9
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "9:4862523104151141465",
|
||||||
|
"name": "url_photo_principale",
|
||||||
|
"type": 9
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"relations": []
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"lastEntityId": "4:4389962693874538546",
|
"lastEntityId": "5:6220645616537106928",
|
||||||
"lastIndexId": "0:0",
|
"lastIndexId": "0:0",
|
||||||
"lastRelationId": "0:0",
|
"lastRelationId": "0:0",
|
||||||
"lastSequenceId": "0:0",
|
"lastSequenceId": "0:0",
|
||||||
|
|
@ -128,7 +177,8 @@
|
||||||
"retiredIndexUids": [],
|
"retiredIndexUids": [],
|
||||||
"retiredPropertyUids": [
|
"retiredPropertyUids": [
|
||||||
402019719780433349,
|
402019719780433349,
|
||||||
2876428622751679696
|
2876428622751679696,
|
||||||
|
6435857490868115471
|
||||||
],
|
],
|
||||||
"retiredRelationUids": [],
|
"retiredRelationUids": [],
|
||||||
"version": 1
|
"version": 1
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
import 'package:mobdr/db/box_user.dart';
|
import 'package:mobdr/db/box_user.dart';
|
||||||
import 'package:mobdr/db/box_log.dart';
|
import 'package:mobdr/db/box_log.dart';
|
||||||
|
import 'package:mobdr/db/box_etab.dart';
|
||||||
import 'model.dart';
|
import 'model.dart';
|
||||||
|
import 'dart:convert';
|
||||||
import 'objectbox.g.dart'; // created by `flutter pub run build_runner build`
|
import 'objectbox.g.dart'; // created by `flutter pub run build_runner build`
|
||||||
|
|
||||||
/// Provides access to the ObjectBox Store throughout the app.
|
/// Provides access to the ObjectBox Store throughout the app.
|
||||||
|
|
@ -16,12 +18,16 @@ class ObjectBox {
|
||||||
/// A Box of user.
|
/// A Box of user.
|
||||||
late final Box<User> userBox;
|
late final Box<User> userBox;
|
||||||
|
|
||||||
|
/// A Box of Etab.
|
||||||
|
late final Box<Etab> etabBox;
|
||||||
|
|
||||||
/// A Box of log.
|
/// A Box of log.
|
||||||
late final Box<Log> logBox;
|
late final Box<Log> logBox;
|
||||||
|
|
||||||
ObjectBox._create(this.store) {
|
ObjectBox._create(this.store) {
|
||||||
noteBox = Box<Note>(store);
|
noteBox = Box<Note>(store);
|
||||||
userBox = Box<User>(store);
|
userBox = Box<User>(store);
|
||||||
|
etabBox = Box<Etab>(store);
|
||||||
logBox = Box<Log>(store);
|
logBox = Box<Log>(store);
|
||||||
|
|
||||||
// Add some demo data if the box is empty.
|
// Add some demo data if the box is empty.
|
||||||
|
|
@ -53,13 +59,6 @@ class ObjectBox {
|
||||||
store.runInTransactionAsync(TxMode.write, _putNotesInTx, demoNotes);
|
store.runInTransactionAsync(TxMode.write, _putNotesInTx, demoNotes);
|
||||||
}
|
}
|
||||||
|
|
||||||
String getUserAvatar(int id_utilisateur) {
|
|
||||||
final query =
|
|
||||||
userBox.query(User_.id_utilisateur.equals(id_utilisateur)).build();
|
|
||||||
var p = query.findFirst();
|
|
||||||
return p!.photo;
|
|
||||||
}
|
|
||||||
|
|
||||||
void _putUserAdminData() {
|
void _putUserAdminData() {
|
||||||
//addUSer(0, 'root', 'admim', 'admin', '');
|
//addUSer(0, 'root', 'admim', 'admin', '');
|
||||||
}
|
}
|
||||||
|
|
@ -98,6 +97,9 @@ class ObjectBox {
|
||||||
store.box<Note>().put(Note(text));
|
store.box<Note>().put(Note(text));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// USER ---------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
|
||||||
Future<void> addUSer(int _id_utilisateur, String _login, String _nom,
|
Future<void> addUSer(int _id_utilisateur, String _login, String _nom,
|
||||||
String _prenom, String _photo) =>
|
String _prenom, String _photo) =>
|
||||||
store.runInTransactionAsync(
|
store.runInTransactionAsync(
|
||||||
|
|
@ -116,6 +118,68 @@ class ObjectBox {
|
||||||
store.box<User>().put(_User);
|
store.box<User>().put(_User);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String getUserAvatar(int id_utilisateur) {
|
||||||
|
final query =
|
||||||
|
userBox.query(User_.id_utilisateur.equals(id_utilisateur)).build();
|
||||||
|
var p = query.findFirst();
|
||||||
|
return p!.photo;
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// /USER --------------------------------------------------------------------
|
||||||
|
|
||||||
|
/// ETAB ---------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
|
||||||
|
// A function that converts a response body into a List<Etab>.
|
||||||
|
List<Etab> parseEtabs(List responseData) {
|
||||||
|
final parsed = responseData.cast<Map<String, dynamic>>();
|
||||||
|
|
||||||
|
return parsed.map<Etab>((json) => Etab.fromJson(json)).toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> addEtabs(List<dynamic> _etabs) => store.runInTransactionAsync(
|
||||||
|
TxMode.write, _addEtabsInTx, parseEtabs(_etabs));
|
||||||
|
|
||||||
|
static void _addEtabsInTx(Store store, _Etabs) {
|
||||||
|
// Perform ObjectBox operations that take longer than a few milliseconds
|
||||||
|
// here. To keep it simple, this example just puts multiple object.
|
||||||
|
store.box<Etab>().putMany(_Etabs);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> addEtab(int _id_etab, String _nom, String _mail, String _tel,
|
||||||
|
String _photo_principale, String _longitude, String _latitude) =>
|
||||||
|
store.runInTransactionAsync(
|
||||||
|
TxMode.write,
|
||||||
|
_addEtabInTx,
|
||||||
|
Etab(
|
||||||
|
id_etab: _id_etab,
|
||||||
|
nom: _nom,
|
||||||
|
mail: _mail,
|
||||||
|
tel: _tel,
|
||||||
|
url_photo_principale: _photo_principale,
|
||||||
|
longitude: _longitude,
|
||||||
|
latitude: _latitude));
|
||||||
|
|
||||||
|
static void _addEtabInTx(Store store, _Etab) {
|
||||||
|
// Perform ObjectBox operations that take longer than a few milliseconds
|
||||||
|
// here. To keep it simple, this example just puts a single object.
|
||||||
|
store.box<Etab>().put(_Etab);
|
||||||
|
}
|
||||||
|
|
||||||
|
String getEtabPhotoPrincipale(int _id_etab) {
|
||||||
|
final query = etabBox.query(Etab_.id_etab.equals(_id_etab)).build();
|
||||||
|
var p = query.findFirst();
|
||||||
|
return p!.url_photo_principale;
|
||||||
|
}
|
||||||
|
|
||||||
|
int getEtabCount() {
|
||||||
|
return etabBox.count();
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// /ETAB --------------------------------------------------------------------
|
||||||
|
|
||||||
/// LOG ----------------------------------------------------------------------
|
/// LOG ----------------------------------------------------------------------
|
||||||
///
|
///
|
||||||
Future<void> addLog(String type, String module, String libelle, int duree) =>
|
Future<void> addLog(String type, String module, String libelle, int duree) =>
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ import 'package:objectbox/internal.dart'; // generated code can access "internal
|
||||||
import 'package:objectbox/objectbox.dart';
|
import 'package:objectbox/objectbox.dart';
|
||||||
import 'package:objectbox_flutter_libs/objectbox_flutter_libs.dart';
|
import 'package:objectbox_flutter_libs/objectbox_flutter_libs.dart';
|
||||||
|
|
||||||
|
import 'db/box_etab.dart';
|
||||||
import 'db/box_log.dart';
|
import 'db/box_log.dart';
|
||||||
import 'db/box_user.dart';
|
import 'db/box_user.dart';
|
||||||
import 'model.dart';
|
import 'model.dart';
|
||||||
|
|
@ -132,6 +133,55 @@ final _entities = <ModelEntity>[
|
||||||
flags: 0)
|
flags: 0)
|
||||||
],
|
],
|
||||||
relations: <ModelRelation>[],
|
relations: <ModelRelation>[],
|
||||||
|
backlinks: <ModelBacklink>[]),
|
||||||
|
ModelEntity(
|
||||||
|
id: const IdUid(5, 6220645616537106928),
|
||||||
|
name: 'Etab',
|
||||||
|
lastPropertyId: const IdUid(9, 4862523104151141465),
|
||||||
|
flags: 0,
|
||||||
|
properties: <ModelProperty>[
|
||||||
|
ModelProperty(
|
||||||
|
id: const IdUid(1, 2951125380051176697),
|
||||||
|
name: 'id',
|
||||||
|
type: 6,
|
||||||
|
flags: 1),
|
||||||
|
ModelProperty(
|
||||||
|
id: const IdUid(2, 986806885009634082),
|
||||||
|
name: 'id_etab',
|
||||||
|
type: 6,
|
||||||
|
flags: 0),
|
||||||
|
ModelProperty(
|
||||||
|
id: const IdUid(3, 2138930560668315243),
|
||||||
|
name: 'nom',
|
||||||
|
type: 9,
|
||||||
|
flags: 0),
|
||||||
|
ModelProperty(
|
||||||
|
id: const IdUid(4, 6458474884283325627),
|
||||||
|
name: 'mail',
|
||||||
|
type: 9,
|
||||||
|
flags: 0),
|
||||||
|
ModelProperty(
|
||||||
|
id: const IdUid(5, 8380062137599693463),
|
||||||
|
name: 'tel',
|
||||||
|
type: 9,
|
||||||
|
flags: 0),
|
||||||
|
ModelProperty(
|
||||||
|
id: const IdUid(7, 5547045221255607235),
|
||||||
|
name: 'longitude',
|
||||||
|
type: 9,
|
||||||
|
flags: 0),
|
||||||
|
ModelProperty(
|
||||||
|
id: const IdUid(8, 5768827910047585940),
|
||||||
|
name: 'latitude',
|
||||||
|
type: 9,
|
||||||
|
flags: 0),
|
||||||
|
ModelProperty(
|
||||||
|
id: const IdUid(9, 4862523104151141465),
|
||||||
|
name: 'url_photo_principale',
|
||||||
|
type: 9,
|
||||||
|
flags: 0)
|
||||||
|
],
|
||||||
|
relations: <ModelRelation>[],
|
||||||
backlinks: <ModelBacklink>[])
|
backlinks: <ModelBacklink>[])
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
@ -155,13 +205,17 @@ Future<Store> openStore(
|
||||||
ModelDefinition getObjectBoxModel() {
|
ModelDefinition getObjectBoxModel() {
|
||||||
final model = ModelInfo(
|
final model = ModelInfo(
|
||||||
entities: _entities,
|
entities: _entities,
|
||||||
lastEntityId: const IdUid(4, 4389962693874538546),
|
lastEntityId: const IdUid(5, 6220645616537106928),
|
||||||
lastIndexId: const IdUid(0, 0),
|
lastIndexId: const IdUid(0, 0),
|
||||||
lastRelationId: const IdUid(0, 0),
|
lastRelationId: const IdUid(0, 0),
|
||||||
lastSequenceId: const IdUid(0, 0),
|
lastSequenceId: const IdUid(0, 0),
|
||||||
retiredEntityUids: const [7401686910042688313],
|
retiredEntityUids: const [7401686910042688313],
|
||||||
retiredIndexUids: const [],
|
retiredIndexUids: const [],
|
||||||
retiredPropertyUids: const [402019719780433349, 2876428622751679696],
|
retiredPropertyUids: const [
|
||||||
|
402019719780433349,
|
||||||
|
2876428622751679696,
|
||||||
|
6435857490868115471
|
||||||
|
],
|
||||||
retiredRelationUids: const [],
|
retiredRelationUids: const [],
|
||||||
modelVersion: 5,
|
modelVersion: 5,
|
||||||
modelVersionParserMinimum: 5,
|
modelVersionParserMinimum: 5,
|
||||||
|
|
@ -286,6 +340,58 @@ ModelDefinition getObjectBoxModel() {
|
||||||
uploaded:
|
uploaded:
|
||||||
const fb.Int64Reader().vTableGet(buffer, rootOffset, 16, 0));
|
const fb.Int64Reader().vTableGet(buffer, rootOffset, 16, 0));
|
||||||
|
|
||||||
|
return object;
|
||||||
|
}),
|
||||||
|
Etab: EntityDefinition<Etab>(
|
||||||
|
model: _entities[3],
|
||||||
|
toOneRelations: (Etab object) => [],
|
||||||
|
toManyRelations: (Etab object) => {},
|
||||||
|
getId: (Etab object) => object.id,
|
||||||
|
setId: (Etab object, int id) {
|
||||||
|
object.id = id;
|
||||||
|
},
|
||||||
|
objectToFB: (Etab object, fb.Builder fbb) {
|
||||||
|
final nomOffset = fbb.writeString(object.nom);
|
||||||
|
final mailOffset = fbb.writeString(object.mail);
|
||||||
|
final telOffset = fbb.writeString(object.tel);
|
||||||
|
final longitudeOffset = fbb.writeString(object.longitude);
|
||||||
|
final latitudeOffset = fbb.writeString(object.latitude);
|
||||||
|
final url_photo_principaleOffset =
|
||||||
|
fbb.writeString(object.url_photo_principale);
|
||||||
|
fbb.startTable(10);
|
||||||
|
fbb.addInt64(0, object.id);
|
||||||
|
fbb.addInt64(1, object.id_etab);
|
||||||
|
fbb.addOffset(2, nomOffset);
|
||||||
|
fbb.addOffset(3, mailOffset);
|
||||||
|
fbb.addOffset(4, telOffset);
|
||||||
|
fbb.addOffset(6, longitudeOffset);
|
||||||
|
fbb.addOffset(7, latitudeOffset);
|
||||||
|
fbb.addOffset(8, url_photo_principaleOffset);
|
||||||
|
fbb.finish(fbb.endTable());
|
||||||
|
return object.id;
|
||||||
|
},
|
||||||
|
objectFromFB: (Store store, ByteData fbData) {
|
||||||
|
final buffer = fb.BufferContext(fbData);
|
||||||
|
final rootOffset = buffer.derefObject(0);
|
||||||
|
|
||||||
|
final object = Etab(
|
||||||
|
id: const fb.Int64Reader().vTableGet(buffer, rootOffset, 4, 0),
|
||||||
|
id_etab:
|
||||||
|
const fb.Int64Reader().vTableGet(buffer, rootOffset, 6, 0),
|
||||||
|
nom: const fb.StringReader(asciiOptimization: true)
|
||||||
|
.vTableGet(buffer, rootOffset, 8, ''),
|
||||||
|
mail: const fb.StringReader(asciiOptimization: true)
|
||||||
|
.vTableGet(buffer, rootOffset, 10, ''),
|
||||||
|
tel: const fb.StringReader(asciiOptimization: true)
|
||||||
|
.vTableGet(buffer, rootOffset, 12, ''),
|
||||||
|
url_photo_principale:
|
||||||
|
const fb.StringReader(asciiOptimization: true)
|
||||||
|
.vTableGet(buffer, rootOffset, 20, ''),
|
||||||
|
longitude: const fb.StringReader(asciiOptimization: true)
|
||||||
|
.vTableGet(buffer, rootOffset, 16, ''),
|
||||||
|
latitude: const fb.StringReader(asciiOptimization: true)
|
||||||
|
.vTableGet(buffer, rootOffset, 18, ''));
|
||||||
|
|
||||||
return object;
|
return object;
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
|
|
@ -353,3 +459,32 @@ class Log_ {
|
||||||
/// see [Log.uploaded]
|
/// see [Log.uploaded]
|
||||||
static final uploaded = QueryIntegerProperty<Log>(_entities[2].properties[6]);
|
static final uploaded = QueryIntegerProperty<Log>(_entities[2].properties[6]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// [Etab] entity fields to define ObjectBox queries.
|
||||||
|
class Etab_ {
|
||||||
|
/// see [Etab.id]
|
||||||
|
static final id = QueryIntegerProperty<Etab>(_entities[3].properties[0]);
|
||||||
|
|
||||||
|
/// see [Etab.id_etab]
|
||||||
|
static final id_etab = QueryIntegerProperty<Etab>(_entities[3].properties[1]);
|
||||||
|
|
||||||
|
/// see [Etab.nom]
|
||||||
|
static final nom = QueryStringProperty<Etab>(_entities[3].properties[2]);
|
||||||
|
|
||||||
|
/// see [Etab.mail]
|
||||||
|
static final mail = QueryStringProperty<Etab>(_entities[3].properties[3]);
|
||||||
|
|
||||||
|
/// see [Etab.tel]
|
||||||
|
static final tel = QueryStringProperty<Etab>(_entities[3].properties[4]);
|
||||||
|
|
||||||
|
/// see [Etab.longitude]
|
||||||
|
static final longitude =
|
||||||
|
QueryStringProperty<Etab>(_entities[3].properties[5]);
|
||||||
|
|
||||||
|
/// see [Etab.latitude]
|
||||||
|
static final latitude = QueryStringProperty<Etab>(_entities[3].properties[6]);
|
||||||
|
|
||||||
|
/// see [Etab.url_photo_principale]
|
||||||
|
static final url_photo_principale =
|
||||||
|
QueryStringProperty<Etab>(_entities[3].properties[7]);
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import 'package:mobdr/ui/account/tab_account.dart';
|
import 'package:mobdr/ui/account/tab_account.dart';
|
||||||
import 'package:mobdr/ui/home/tab_home.dart';
|
import 'package:mobdr/ui/home/tab_home.dart';
|
||||||
import 'package:mobdr/ui/shopping_cart/tab_shopping_cart.dart';
|
import 'package:mobdr/ui/shopping_cart/tab_shopping_cart.dart';
|
||||||
import 'package:mobdr/ui/wishlist/tab_wishlist.dart';
|
import 'package:mobdr/ui/sync/tab_sync.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:mobdr/config/constant.dart';
|
import 'package:mobdr/config/constant.dart';
|
||||||
|
|
||||||
|
|
@ -18,7 +18,7 @@ class _HomePageState extends State<HomePage>
|
||||||
// Pages if you click bottom navigation
|
// Pages if you click bottom navigation
|
||||||
final List<Widget> _contentPages = <Widget>[
|
final List<Widget> _contentPages = <Widget>[
|
||||||
TabHomePage(),
|
TabHomePage(),
|
||||||
TabWishlistPage(),
|
TabSyncPage(),
|
||||||
TabShoppingCartPage(),
|
TabShoppingCartPage(),
|
||||||
TabAccountPage(),
|
TabAccountPage(),
|
||||||
];
|
];
|
||||||
|
|
@ -76,8 +76,8 @@ class _HomePageState extends State<HomePage>
|
||||||
icon: Icon(Icons.home,
|
icon: Icon(Icons.home,
|
||||||
color: _currentIndex == 0 ? PRIMARY_COLOR : CHARCOAL)),
|
color: _currentIndex == 0 ? PRIMARY_COLOR : CHARCOAL)),
|
||||||
BottomNavigationBarItem(
|
BottomNavigationBarItem(
|
||||||
label: 'Wishlist',
|
label: 'Sync',
|
||||||
icon: Icon(Icons.favorite,
|
icon: Icon(Icons.sync,
|
||||||
color: _currentIndex == 1 ? ASSENT_COLOR : CHARCOAL)),
|
color: _currentIndex == 1 ? ASSENT_COLOR : CHARCOAL)),
|
||||||
BottomNavigationBarItem(
|
BottomNavigationBarItem(
|
||||||
label: 'Cart',
|
label: 'Cart',
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,300 @@
|
||||||
|
/*
|
||||||
|
This is wishlist page
|
||||||
|
we used AutomaticKeepAliveClientMixin to keep the state when moving from 1 navbar to another navbar, so the page is not refresh overtime
|
||||||
|
*/
|
||||||
|
|
||||||
|
import 'package:mobdr/config/global_style.dart';
|
||||||
|
import 'package:mobdr/main.dart';
|
||||||
|
import 'package:mobdr/ui/reusable/reusable_widget.dart';
|
||||||
|
import 'package:mobdr/network/api_provider.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:timelines/timelines.dart';
|
||||||
|
import 'dart:math';
|
||||||
|
|
||||||
|
const completeColor = Color(0xff5e6172);
|
||||||
|
const inProgressColor = Color(0xff5ec792);
|
||||||
|
const todoColor = Color(0xffd1d2d7);
|
||||||
|
const failedColor = Colors.red;
|
||||||
|
|
||||||
|
class TabSyncPage extends StatefulWidget {
|
||||||
|
@override
|
||||||
|
_TabSyncPageState createState() => _TabSyncPageState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _TabSyncPageState extends State<TabSyncPage>
|
||||||
|
with AutomaticKeepAliveClientMixin {
|
||||||
|
// initialize global function and reusable widget
|
||||||
|
//final _globalFunction = GlobalFunction();
|
||||||
|
final _reusableWidget = ReusableWidget();
|
||||||
|
|
||||||
|
final _processes = ['Btqs', 'Params', 'Visites', 'Photos', 'Logs'];
|
||||||
|
|
||||||
|
final ApiProvider _apiProvider =
|
||||||
|
ApiProvider(); // TODO: A voir si bien positionné
|
||||||
|
|
||||||
|
// _listKey is used for AnimatedList
|
||||||
|
//final GlobalKey<AnimatedListState> _listKey = GlobalKey();
|
||||||
|
|
||||||
|
int _processIndex = 1;
|
||||||
|
|
||||||
|
Color getColor(int index) {
|
||||||
|
if (index == _processIndex) {
|
||||||
|
return inProgressColor;
|
||||||
|
} else if (index < _processIndex) {
|
||||||
|
return completeColor;
|
||||||
|
} else {
|
||||||
|
return todoColor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// keep the state to do not refresh when switch navbar
|
||||||
|
@override
|
||||||
|
bool get wantKeepAlive => true;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
// if we used AutomaticKeepAliveClientMixin, we must call super.build(context);
|
||||||
|
super.build(context);
|
||||||
|
return Scaffold(
|
||||||
|
backgroundColor: Colors.white,
|
||||||
|
appBar: AppBar(
|
||||||
|
iconTheme: IconThemeData(
|
||||||
|
color: GlobalStyle.appBarIconThemeColor,
|
||||||
|
),
|
||||||
|
elevation: GlobalStyle.appBarElevation,
|
||||||
|
title: Text(
|
||||||
|
'Synchronisation',
|
||||||
|
style: GlobalStyle.appBarTitle,
|
||||||
|
),
|
||||||
|
backgroundColor: GlobalStyle.appBarBackgroundColor,
|
||||||
|
systemOverlayStyle: GlobalStyle.appBarSystemOverlayStyle,
|
||||||
|
bottom: _reusableWidget.bottomAppBar(),
|
||||||
|
),
|
||||||
|
body: Timeline.tileBuilder(
|
||||||
|
theme: TimelineThemeData(
|
||||||
|
direction: Axis.horizontal,
|
||||||
|
connectorTheme: ConnectorThemeData(
|
||||||
|
space: 30.0,
|
||||||
|
thickness: 5.0,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
builder: TimelineTileBuilder.connected(
|
||||||
|
connectionDirection: ConnectionDirection.before,
|
||||||
|
itemExtentBuilder: (_, __) =>
|
||||||
|
MediaQuery.of(context).size.width / _processes.length,
|
||||||
|
oppositeContentsBuilder: (context, index) {
|
||||||
|
return Padding(
|
||||||
|
padding: const EdgeInsets.only(bottom: 15.0),
|
||||||
|
child: Image.asset(
|
||||||
|
'assets/images/process_timeline/status${index + 1}.png',
|
||||||
|
width: 50.0,
|
||||||
|
color: getColor(index),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
contentsBuilder: (context, index) {
|
||||||
|
return Padding(
|
||||||
|
padding: const EdgeInsets.only(top: 15.0),
|
||||||
|
child: Text(
|
||||||
|
_processes[index],
|
||||||
|
style: TextStyle(
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
color: getColor(index),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
indicatorBuilder: (_, index) {
|
||||||
|
var color;
|
||||||
|
var child;
|
||||||
|
if (index == _processIndex) {
|
||||||
|
color = inProgressColor;
|
||||||
|
child = Padding(
|
||||||
|
padding: const EdgeInsets.all(8.0),
|
||||||
|
child: CircularProgressIndicator(
|
||||||
|
strokeWidth: 3.0,
|
||||||
|
valueColor: AlwaysStoppedAnimation(Colors.white),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
} else if (index < _processIndex) {
|
||||||
|
color = failedColor;
|
||||||
|
child = Icon(
|
||||||
|
Icons.cancel,
|
||||||
|
color: Colors.white,
|
||||||
|
size: 20.0,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
color = todoColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (index <= _processIndex) {
|
||||||
|
return Stack(
|
||||||
|
children: [
|
||||||
|
CustomPaint(
|
||||||
|
size: Size(30.0, 30.0),
|
||||||
|
painter: _BezierPainter(
|
||||||
|
color: color,
|
||||||
|
drawStart: index > 0,
|
||||||
|
drawEnd: index < _processIndex,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
DotIndicator(
|
||||||
|
size: 30.0,
|
||||||
|
color: color,
|
||||||
|
child: child,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return Stack(
|
||||||
|
children: [
|
||||||
|
CustomPaint(
|
||||||
|
size: Size(15.0, 15.0),
|
||||||
|
painter: _BezierPainter(
|
||||||
|
color: color,
|
||||||
|
drawEnd: index < _processes.length - 1,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
OutlinedDotIndicator(
|
||||||
|
borderWidth: 4.0,
|
||||||
|
color: color,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
connectorBuilder: (_, index, type) {
|
||||||
|
if (index > 0) {
|
||||||
|
if (index == _processIndex) {
|
||||||
|
final prevColor = getColor(index - 1);
|
||||||
|
final color = getColor(index);
|
||||||
|
List<Color> gradientColors;
|
||||||
|
if (type == ConnectorType.start) {
|
||||||
|
gradientColors = [Color.lerp(prevColor, color, 0.5)!, color];
|
||||||
|
} else {
|
||||||
|
gradientColors = [
|
||||||
|
prevColor,
|
||||||
|
Color.lerp(prevColor, color, 0.5)!
|
||||||
|
];
|
||||||
|
}
|
||||||
|
return DecoratedLineConnector(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
gradient: LinearGradient(
|
||||||
|
colors: gradientColors,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return SolidLineConnector(
|
||||||
|
color: getColor(index),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
itemCount: _processes.length,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
floatingActionButton: FloatingActionButton(
|
||||||
|
child: Icon(Icons.chevron_right),
|
||||||
|
onPressed: () async {
|
||||||
|
///FRED
|
||||||
|
print("Nombre étab avant:" + objectbox.getEtabCount().toString());
|
||||||
|
var apiResponse = await _apiProvider.SyncEtablissements();
|
||||||
|
if (apiResponse == 'OK') {
|
||||||
|
print("getEtablissement:" + apiResponse);
|
||||||
|
print("Nombre étab apres" + objectbox.getEtabCount().toString());
|
||||||
|
} else {
|
||||||
|
print("getEtablissement Error:" + apiResponse);
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
setState(() {
|
||||||
|
_processIndex = (_processIndex + 1) % _processes.length;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
backgroundColor: inProgressColor,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// hardcoded bezier painter
|
||||||
|
class _BezierPainter extends CustomPainter {
|
||||||
|
const _BezierPainter({
|
||||||
|
required this.color,
|
||||||
|
this.drawStart = true,
|
||||||
|
this.drawEnd = true,
|
||||||
|
});
|
||||||
|
|
||||||
|
final Color color;
|
||||||
|
final bool drawStart;
|
||||||
|
final bool drawEnd;
|
||||||
|
|
||||||
|
Offset _offset(double radius, double angle) {
|
||||||
|
return Offset(
|
||||||
|
radius * cos(angle) + radius,
|
||||||
|
radius * sin(angle) + radius,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void paint(Canvas canvas, Size size) {
|
||||||
|
final paint = Paint()
|
||||||
|
..style = PaintingStyle.fill
|
||||||
|
..color = color;
|
||||||
|
|
||||||
|
final radius = size.width / 2;
|
||||||
|
|
||||||
|
var angle;
|
||||||
|
var offset1;
|
||||||
|
var offset2;
|
||||||
|
|
||||||
|
var path;
|
||||||
|
|
||||||
|
if (drawStart) {
|
||||||
|
angle = 3 * pi / 4;
|
||||||
|
offset1 = _offset(radius, angle);
|
||||||
|
offset2 = _offset(radius, -angle);
|
||||||
|
path = Path()
|
||||||
|
..moveTo(offset1.dx, offset1.dy)
|
||||||
|
..quadraticBezierTo(0.0, size.height / 2, -radius, radius)
|
||||||
|
..quadraticBezierTo(0.0, size.height / 2, offset2.dx, offset2.dy)
|
||||||
|
..close();
|
||||||
|
|
||||||
|
canvas.drawPath(path, paint);
|
||||||
|
}
|
||||||
|
if (drawEnd) {
|
||||||
|
angle = -pi / 4;
|
||||||
|
offset1 = _offset(radius, angle);
|
||||||
|
offset2 = _offset(radius, -angle);
|
||||||
|
|
||||||
|
path = Path()
|
||||||
|
..moveTo(offset1.dx, offset1.dy)
|
||||||
|
..quadraticBezierTo(
|
||||||
|
size.width, size.height / 2, size.width + radius, radius)
|
||||||
|
..quadraticBezierTo(size.width, size.height / 2, offset2.dx, offset2.dy)
|
||||||
|
..close();
|
||||||
|
|
||||||
|
canvas.drawPath(path, paint);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool shouldRepaint(_BezierPainter oldDelegate) {
|
||||||
|
return oldDelegate.color != color ||
|
||||||
|
oldDelegate.drawStart != drawStart ||
|
||||||
|
oldDelegate.drawEnd != drawEnd;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,378 +0,0 @@
|
||||||
/*
|
|
||||||
This is wishlist page
|
|
||||||
we used AutomaticKeepAliveClientMixin to keep the state when moving from 1 navbar to another navbar, so the page is not refresh overtime
|
|
||||||
*/
|
|
||||||
|
|
||||||
import 'package:mobdr/config/constant.dart';
|
|
||||||
import 'package:mobdr/config/global_style.dart';
|
|
||||||
import 'package:mobdr/model/wishlist_model.dart';
|
|
||||||
import 'package:mobdr/ui/general/chat_us.dart';
|
|
||||||
import 'package:mobdr/ui/general/notification.dart';
|
|
||||||
import 'package:mobdr/ui/general/product_detail/product_detail.dart';
|
|
||||||
import 'package:mobdr/ui/reusable/reusable_widget.dart';
|
|
||||||
import 'package:mobdr/ui/reusable/cache_image_network.dart';
|
|
||||||
import 'package:mobdr/ui/reusable/global_function.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:fluttertoast/fluttertoast.dart';
|
|
||||||
|
|
||||||
class TabWishlistPage extends StatefulWidget {
|
|
||||||
@override
|
|
||||||
_TabWishlistPageState createState() => _TabWishlistPageState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _TabWishlistPageState extends State<TabWishlistPage>
|
|
||||||
with AutomaticKeepAliveClientMixin {
|
|
||||||
// initialize global function and reusable widget
|
|
||||||
final _globalFunction = GlobalFunction();
|
|
||||||
final _reusableWidget = ReusableWidget();
|
|
||||||
|
|
||||||
// _listKey is used for AnimatedList
|
|
||||||
final GlobalKey<AnimatedListState> _listKey = GlobalKey();
|
|
||||||
|
|
||||||
TextEditingController _etSearch = TextEditingController();
|
|
||||||
|
|
||||||
// keep the state to do not refresh when switch navbar
|
|
||||||
@override
|
|
||||||
bool get wantKeepAlive => true;
|
|
||||||
|
|
||||||
@override
|
|
||||||
void initState() {
|
|
||||||
super.initState();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void dispose() {
|
|
||||||
_etSearch.dispose();
|
|
||||||
super.dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
// if we used AutomaticKeepAliveClientMixin, we must call super.build(context);
|
|
||||||
super.build(context);
|
|
||||||
final double boxImageSize = (MediaQuery.of(context).size.width / 4);
|
|
||||||
return Scaffold(
|
|
||||||
appBar: AppBar(
|
|
||||||
automaticallyImplyLeading: false,
|
|
||||||
elevation: GlobalStyle.appBarElevation,
|
|
||||||
title: Text(
|
|
||||||
'Wishlist',
|
|
||||||
style: GlobalStyle.appBarTitle,
|
|
||||||
),
|
|
||||||
backgroundColor: GlobalStyle.appBarBackgroundColor,
|
|
||||||
systemOverlayStyle: GlobalStyle.appBarSystemOverlayStyle,
|
|
||||||
actions: [
|
|
||||||
GestureDetector(
|
|
||||||
onTap: () {
|
|
||||||
Navigator.push(context,
|
|
||||||
MaterialPageRoute(builder: (context) => ChatUsPage()));
|
|
||||||
},
|
|
||||||
child: Icon(Icons.email, color: BLACK_GREY)),
|
|
||||||
IconButton(
|
|
||||||
icon: _reusableWidget.customNotifIcon(
|
|
||||||
count: 8, notifColor: BLACK_GREY),
|
|
||||||
onPressed: () {
|
|
||||||
Navigator.push(
|
|
||||||
context,
|
|
||||||
MaterialPageRoute(
|
|
||||||
builder: (context) => NotificationPage()));
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
// create search text field in the app bar
|
|
||||||
bottom: PreferredSize(
|
|
||||||
child: Container(
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
border: Border(
|
|
||||||
bottom: BorderSide(
|
|
||||||
color: Colors.grey[100]!,
|
|
||||||
width: 1.0,
|
|
||||||
)),
|
|
||||||
),
|
|
||||||
padding: EdgeInsets.fromLTRB(16, 0, 16, 12),
|
|
||||||
height: kToolbarHeight,
|
|
||||||
child: TextFormField(
|
|
||||||
controller: _etSearch,
|
|
||||||
textAlignVertical: TextAlignVertical.bottom,
|
|
||||||
maxLines: 1,
|
|
||||||
style: TextStyle(fontSize: 16, color: Colors.grey[600]),
|
|
||||||
onChanged: (textValue) {
|
|
||||||
setState(() {});
|
|
||||||
},
|
|
||||||
decoration: InputDecoration(
|
|
||||||
fillColor: Colors.grey[100],
|
|
||||||
filled: true,
|
|
||||||
hintText: 'Search Wishlist',
|
|
||||||
prefixIcon: Icon(Icons.search, color: Colors.grey[500]),
|
|
||||||
suffixIcon: (_etSearch.text == '')
|
|
||||||
? null
|
|
||||||
: GestureDetector(
|
|
||||||
onTap: () {
|
|
||||||
setState(() {
|
|
||||||
_etSearch = TextEditingController(text: '');
|
|
||||||
});
|
|
||||||
},
|
|
||||||
child: Icon(Icons.close, color: Colors.grey[500])),
|
|
||||||
focusedBorder: UnderlineInputBorder(
|
|
||||||
borderRadius: BorderRadius.all(Radius.circular(5.0)),
|
|
||||||
borderSide: BorderSide(color: Colors.grey[200]!)),
|
|
||||||
enabledBorder: UnderlineInputBorder(
|
|
||||||
borderRadius: BorderRadius.all(Radius.circular(5.0)),
|
|
||||||
borderSide: BorderSide(color: Colors.grey[200]!),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
preferredSize: Size.fromHeight(kToolbarHeight),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
body: AnimatedList(
|
|
||||||
key: _listKey,
|
|
||||||
initialItemCount: wishlistData.length,
|
|
||||||
physics: AlwaysScrollableScrollPhysics(),
|
|
||||||
itemBuilder: (context, index, animation) {
|
|
||||||
return _buildWishlistCard(
|
|
||||||
wishlistData[index], boxImageSize, animation, index);
|
|
||||||
},
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget _buildWishlistCard(
|
|
||||||
WishlistModel wishlistData, boxImageSize, animation, index) {
|
|
||||||
return SizeTransition(
|
|
||||||
sizeFactor: animation,
|
|
||||||
child: Container(
|
|
||||||
margin: EdgeInsets.fromLTRB(12, 6, 12, 0),
|
|
||||||
child: Card(
|
|
||||||
shape: RoundedRectangleBorder(
|
|
||||||
borderRadius: BorderRadius.circular(10),
|
|
||||||
),
|
|
||||||
elevation: 2,
|
|
||||||
color: Colors.white,
|
|
||||||
child: Container(
|
|
||||||
margin: EdgeInsets.all(8),
|
|
||||||
child: Column(
|
|
||||||
children: [
|
|
||||||
GestureDetector(
|
|
||||||
onTap: () {
|
|
||||||
Navigator.push(
|
|
||||||
context,
|
|
||||||
MaterialPageRoute(
|
|
||||||
builder: (context) => ProductDetailPage(
|
|
||||||
name: wishlistData.name,
|
|
||||||
image: wishlistData.image,
|
|
||||||
price: wishlistData.price,
|
|
||||||
rating: wishlistData.rating,
|
|
||||||
review: wishlistData.review,
|
|
||||||
sale: wishlistData.sale)));
|
|
||||||
},
|
|
||||||
child: Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.start,
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: <Widget>[
|
|
||||||
ClipRRect(
|
|
||||||
borderRadius: BorderRadius.all(Radius.circular(10)),
|
|
||||||
child: buildCacheNetworkImage(
|
|
||||||
width: boxImageSize,
|
|
||||||
height: boxImageSize,
|
|
||||||
url: wishlistData.image)),
|
|
||||||
SizedBox(
|
|
||||||
width: 10,
|
|
||||||
),
|
|
||||||
Expanded(
|
|
||||||
child: Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
Text(
|
|
||||||
wishlistData.name,
|
|
||||||
style: GlobalStyle.productName
|
|
||||||
.copyWith(fontSize: 13),
|
|
||||||
maxLines: 3,
|
|
||||||
overflow: TextOverflow.ellipsis,
|
|
||||||
),
|
|
||||||
Container(
|
|
||||||
margin: EdgeInsets.only(top: 5),
|
|
||||||
child: Text(
|
|
||||||
'\$ ' +
|
|
||||||
_globalFunction.removeDecimalZeroFormat(
|
|
||||||
wishlistData.price),
|
|
||||||
style: GlobalStyle.productPrice),
|
|
||||||
),
|
|
||||||
Container(
|
|
||||||
margin: EdgeInsets.only(top: 5),
|
|
||||||
child: Row(
|
|
||||||
children: [
|
|
||||||
Icon(Icons.location_on,
|
|
||||||
color: SOFT_GREY, size: 12),
|
|
||||||
Text(' ' + wishlistData.location,
|
|
||||||
style: GlobalStyle.productLocation)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Container(
|
|
||||||
margin: EdgeInsets.only(top: 5),
|
|
||||||
child: Row(
|
|
||||||
children: [
|
|
||||||
_reusableWidget.createRatingBar(
|
|
||||||
rating: wishlistData.rating, size: 12),
|
|
||||||
Text(
|
|
||||||
'(' +
|
|
||||||
wishlistData.review.toString() +
|
|
||||||
')',
|
|
||||||
style: GlobalStyle.productTotalReview)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Container(
|
|
||||||
margin: EdgeInsets.only(top: 5),
|
|
||||||
child: Text(
|
|
||||||
wishlistData.sale.toString() + ' Sale',
|
|
||||||
style: GlobalStyle.productSale),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Container(
|
|
||||||
margin: EdgeInsets.only(top: 12),
|
|
||||||
child: Row(
|
|
||||||
children: [
|
|
||||||
GestureDetector(
|
|
||||||
behavior: HitTestBehavior.translucent,
|
|
||||||
onTap: () {
|
|
||||||
showPopupDeleteTabWishlist(index, boxImageSize);
|
|
||||||
},
|
|
||||||
child: Container(
|
|
||||||
padding: EdgeInsets.fromLTRB(5, 0, 5, 0),
|
|
||||||
height: 30,
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
borderRadius: BorderRadius.circular(8),
|
|
||||||
border: Border.all(
|
|
||||||
width: 1, color: Colors.grey[300]!)),
|
|
||||||
child:
|
|
||||||
Icon(Icons.delete, color: BLACK_GREY, size: 20),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
SizedBox(
|
|
||||||
width: 8,
|
|
||||||
),
|
|
||||||
Expanded(
|
|
||||||
child: (wishlistData.stock == 0)
|
|
||||||
? TextButton(
|
|
||||||
style: ButtonStyle(
|
|
||||||
minimumSize:
|
|
||||||
MaterialStateProperty.all(Size(0, 30)),
|
|
||||||
backgroundColor:
|
|
||||||
MaterialStateProperty.resolveWith<Color>(
|
|
||||||
(Set<MaterialState> states) =>
|
|
||||||
Colors.grey[300]!,
|
|
||||||
),
|
|
||||||
overlayColor: MaterialStateProperty.all(
|
|
||||||
Colors.transparent),
|
|
||||||
shape: MaterialStateProperty.all(
|
|
||||||
RoundedRectangleBorder(
|
|
||||||
borderRadius: BorderRadius.circular(5.0),
|
|
||||||
)),
|
|
||||||
),
|
|
||||||
onPressed: null,
|
|
||||||
child: Text(
|
|
||||||
'Out of Stock',
|
|
||||||
style: TextStyle(
|
|
||||||
color: Colors.grey[600],
|
|
||||||
fontWeight: FontWeight.bold,
|
|
||||||
fontSize: 13),
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
))
|
|
||||||
: OutlinedButton(
|
|
||||||
onPressed: () {
|
|
||||||
Fluttertoast.showToast(
|
|
||||||
msg:
|
|
||||||
'Item has been added to Shopping Cart');
|
|
||||||
},
|
|
||||||
style: ButtonStyle(
|
|
||||||
minimumSize:
|
|
||||||
MaterialStateProperty.all(Size(0, 30)),
|
|
||||||
overlayColor: MaterialStateProperty.all(
|
|
||||||
Colors.transparent),
|
|
||||||
shape: MaterialStateProperty.all(
|
|
||||||
RoundedRectangleBorder(
|
|
||||||
borderRadius: BorderRadius.circular(5.0),
|
|
||||||
)),
|
|
||||||
side: MaterialStateProperty.all(
|
|
||||||
BorderSide(color: SOFT_BLUE, width: 1.0),
|
|
||||||
)),
|
|
||||||
child: Text(
|
|
||||||
'Add to Shopping Cart',
|
|
||||||
style: TextStyle(
|
|
||||||
color: SOFT_BLUE,
|
|
||||||
fontWeight: FontWeight.bold,
|
|
||||||
fontSize: 13),
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
)),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
void showPopupDeleteTabWishlist(index, boxImageSize) {
|
|
||||||
// set up the buttons
|
|
||||||
Widget cancelButton = TextButton(
|
|
||||||
onPressed: () {
|
|
||||||
Navigator.pop(context);
|
|
||||||
},
|
|
||||||
child: Text('No', style: TextStyle(color: SOFT_BLUE)));
|
|
||||||
Widget continueButton = TextButton(
|
|
||||||
onPressed: () {
|
|
||||||
int removeIndex = index;
|
|
||||||
var removedItem = wishlistData.removeAt(removeIndex);
|
|
||||||
// This builder is just so that the animation has something
|
|
||||||
// to work with before it disappears from view since the original
|
|
||||||
// has already been deleted.
|
|
||||||
AnimatedRemovedItemBuilder builder = (context, animation) {
|
|
||||||
// A method to build the Card widget.
|
|
||||||
return _buildWishlistCard(
|
|
||||||
removedItem, boxImageSize, animation, removeIndex);
|
|
||||||
};
|
|
||||||
_listKey.currentState!.removeItem(removeIndex, builder);
|
|
||||||
|
|
||||||
Navigator.pop(context);
|
|
||||||
Fluttertoast.showToast(
|
|
||||||
msg: 'Item has been deleted from your wishlist',
|
|
||||||
toastLength: Toast.LENGTH_LONG);
|
|
||||||
},
|
|
||||||
child: Text('Yes', style: TextStyle(color: SOFT_BLUE)));
|
|
||||||
|
|
||||||
// set up the AlertDialog
|
|
||||||
AlertDialog alert = AlertDialog(
|
|
||||||
shape: RoundedRectangleBorder(
|
|
||||||
borderRadius: BorderRadius.circular(10),
|
|
||||||
),
|
|
||||||
title: Text(
|
|
||||||
'Delete Wishlist',
|
|
||||||
style: TextStyle(fontSize: 18),
|
|
||||||
),
|
|
||||||
content: Text('Are you sure to delete this item from your Wishlist ?',
|
|
||||||
style: TextStyle(fontSize: 13, color: BLACK_GREY)),
|
|
||||||
actions: [
|
|
||||||
cancelButton,
|
|
||||||
continueButton,
|
|
||||||
],
|
|
||||||
);
|
|
||||||
|
|
||||||
// show the dialog
|
|
||||||
showDialog(
|
|
||||||
context: context,
|
|
||||||
builder: (BuildContext context) {
|
|
||||||
return alert;
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -850,6 +850,14 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.4.16"
|
version: "0.4.16"
|
||||||
|
timelines:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: timelines
|
||||||
|
sha256: "40214f5ab772ff45459cb8c15e5f60505a6828af0c0eb1eec6f29ed911a4c1c5"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.1.0"
|
||||||
timing:
|
timing:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
|
||||||
|
|
@ -54,7 +54,7 @@ dependencies:
|
||||||
cached_network_image: 3.2.3
|
cached_network_image: 3.2.3
|
||||||
get_it: ^7.2.0
|
get_it: ^7.2.0
|
||||||
shared_preferences: 2.0.18
|
shared_preferences: 2.0.18
|
||||||
|
timelines: ^0.1.0
|
||||||
universal_io: 2.2.0
|
universal_io: 2.2.0
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
|
|
@ -125,6 +125,11 @@ flutter:
|
||||||
- assets/images/logo_dark.png
|
- assets/images/logo_dark.png
|
||||||
- assets/images/logo_horizontal.png
|
- assets/images/logo_horizontal.png
|
||||||
- assets/images/onboarding/search_product.gif
|
- assets/images/onboarding/search_product.gif
|
||||||
|
- assets/images/process_timeline/status1.png
|
||||||
|
- assets/images/process_timeline/status2.png
|
||||||
|
- assets/images/process_timeline/status3.png
|
||||||
|
- assets/images/process_timeline/status4.png
|
||||||
|
- assets/images/process_timeline/status5.png
|
||||||
|
|
||||||
- assets/lang/fr.json
|
- assets/lang/fr.json
|
||||||
- assets/lang/en.json
|
- assets/lang/en.json
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue