class MenuProduct extends StatelessWidget {
FirebaseOneMenuProduct p;
BuildContext context;
var placeId;
var inWishList;
var showWishAddButton;
MenuProduct(this.p, this.placeId, this.context,
{this.inWishList = false, this.showWishAddButton = true});
FirebaseManager _firebaseManager = new FirebaseManager();
static final LIST_VIEW_ITEM_HEIGHT = 160.0;
@override
Widget build(BuildContext c) {
// MARK: implement build
return _oneProductView(p);
}
Widget _oneProductView(FirebaseOneMenuProduct p) => Padding(
padding: EdgeInsets.only(top: 12.0),
child: new Container(
color: Colors.white,
child: GestureDetector(
onTap: () {
debugPrint("main: " + p.id + " " + placeId);
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ProductDetail(p.id, placeId)),
);
},
child: Padding(
padding: EdgeInsets.only(
left: Constants.PADDING_SMALL_12,
right: Constants.PADDING_SMALL_12,
top: Constants.PADDING_MEDIUM_16,
bottom: Constants.PADDING_MEDIUM_16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Stack(
children: <Widget>[
Container(
color: Colors.grey[200],
width: double.infinity,
height: LIST_VIEW_ITEM_HEIGHT,
child: Image.asset(
Images.PRODUCT_PLACEHOLDER,
fit: BoxFit.fitWidth,
width: double.infinity,
)),
Container(
width: double.infinity,
height: LIST_VIEW_ITEM_HEIGHT,
child: Image.network(
p.downloadUrl,
fit: BoxFit.fitWidth,
width: double.infinity,
)),
Positioned(
child: _addIcon(inWishList),
right: 0.0,
top: 0.0,
),
],
),
Padding(
padding: EdgeInsets.only(
top: Constants.PADDING_SMALL_8,
bottom: Constants.PADDING_SMALL_4),
child: Row(
children: <Widget>[
Expanded(
flex: 10,
child: Text(p.item_name,
maxLines: 1,
style: TextStyle(
color: Colors.black,
fontSize: 16.0,
fontWeight: FontWeight.bold))),
Expanded(
flex: 1,
child: Icon(
Icons.star,
color: Colors.green,
size: 16.0,
),
),
Expanded(
flex: 1,
child: Text(
double.parse(p.rating.toString())
.toStringAsFixed(1),
style: TextStyle(
fontSize: 12.0,
fontWeight: FontWeight.bold),
),
)
],
)),
Padding(
padding: EdgeInsets.only(
bottom: Constants.PADDING_SMALL_4),
child: Text(
(double.parse(p.calories.toString()) != null
? "${double.parse(p.calories.toString()).round().toString()} calories"
: "n/a calories"),
maxLines: 1,
style: TextStyle(
color: Colors.black,
fontSize: 13.0,
))),
],
)))));
Widget _addIcon(bool inWishList) {
//MARK: Animated icon
var addedToWishListIcon =
(showWishAddButton ? Icons.check_circle : Icons.delete_forever);
return IconButton(
icon: HighLightedIcon(
(!inWishList ? Icons.add_circle : addedToWishListIcon),
color: (!inWishList ? Colors.white : Colors.orange),
size: 30.0,
),
onPressed: () {
_firebaseManager.changeDishList(placeId, p, null);
});
}
}
Last active
July 8, 2019 16:05
-
-
Save followthemoney1/27d764a24f8513001c37731ca346e115 to your computer and use it in GitHub Desktop.
flutter example
class Review extends StatelessWidget {
FirebaseReviewUser _review;
DateFormat _dateFormat = new DateFormat("dd-MMMM-yyy");
Review(this._review);
@override
Widget build(BuildContext context) {
return review();
}
Widget review() => Column(
children: <Widget>[
///top review
Padding(
padding: EdgeInsets.only(
left: Constants.PADDING_SMALL_12,
right: Constants.PADDING_SMALL_4,
bottom: Constants.PADDING_SMALL_4,
top: Constants.PADDING_SMALL_8),
child: Row(
verticalDirection: VerticalDirection.up,
children: <Widget>[
CircleAvatar(
backgroundImage:
NetworkImage((_review.userAvatarDownloadUrl!=null ? _review.userAvatarDownloadUrl:"")),
backgroundColor: Colors.grey,
),
Expanded(
flex: 3,
child: Padding(
padding: EdgeInsets.only(
left: Constants.PADDING_MEDIUM_16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
_review.authorName,
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 17.0,
color: Colors.black),
),
Text(_dateFormat.format(_review.createdAt),
style: TextStyle(
fontSize: 12.0, color: Colors.grey[800])),
],
))),
Flexible(
flex: 2,
child: new StarRating(
allowHalfRating: true,
size: 20.0,
rating: _review.rating,
color: Colors.orange,
borderColor: Colors.orange,
starCount: 5,
),
),
],
)),
///bottom review
Padding(
padding: EdgeInsets.only(
left: Constants.PADDING_MEDIUM_16,
right: Constants.PADDING_MEDIUM_16,
top: Constants.PADDING_SMALL_8,
bottom: Constants.PADDING_MEDIUM_18),
child: Container(
width: double.infinity,
child: Text(
_review.text,
style: TextStyle(fontSize: 16.0, color: Colors.black),
)),
),
Container(
height: 1.0,
width: double.infinity,
color: Colors.grey[300],
)
],
);
}
class FirebaseManager {
static FirebaseDatabase _firebaseDatabase = FirebaseDatabase.instance;
DatabaseReference _databaseReference = _firebaseDatabase.reference();
FirebaseAuth _firebaseUser = FirebaseAuth.instance;
Firestore _firebaseFirestore = Firestore.instance;
FirebaseStorage _storage = FirebaseStorage.instance;
NetworkSharedPreferences _networkSharedPreferences =
NetworkSharedPreferences();
String _imagePublicUrlPrefix;
final String ERROR_FIND_MACHES_COLLECTION =
"Cannot find matches in collection: ";
final String ERROR_FIND_PLACE_FROM_FIRESTORE =
"Cannot find place in firestore";
final String ERROR_FIND_PLACE_MENU_FROM_FIRESTORE =
"Cannot find place menu in firestore";
static final FirebaseManager _singleton = new FirebaseManager._internal();
factory FirebaseManager() {
return _singleton;
}
FirebaseManager._internal() {
_init();
}
void _init() async {
await _firebaseUser.signInAnonymously();
_getRemoteConfig();
_checkUserIsLogin();
}
void _getRemoteConfig() async {
RemoteConfig _remoteConfig = await RemoteConfig.instance;
try {
await _remoteConfig.fetch(
expiration: const Duration(hours: 12)); //default fetch 12 hours
await _remoteConfig.activateFetched();
} on FetchThrottledException catch (exception) {
debugPrint(exception.toString());
} catch (exception) {
debugPrint("Unable to fetch remote config.");
}
_imagePublicUrlPrefix = _remoteConfig
?.getString(Constants.FIREBASE_REMOTE_CONF_IMAGE_PUBLIC_URL);
}
void _checkUserIsLogin() async {
if (_firebaseUser.currentUser() == null) {
_firebaseUser.signInAnonymously().catchError((e) {
debugPrint(e);
});
}
}
Future<String> getCurrentUserId() async {
FirebaseUser user = await _firebaseUser.currentUser();
return user.uid;
}
Future<String> getCurrentUserName() async {
FirebaseUser user = await _firebaseUser.currentUser();
return user.displayName;
}
Future<String> getDownloadUrlFromGS(String path) async {
String ref = "";
if (path.isNotEmpty)
ref = await _storage.ref().child(path).getDownloadURL();
return ref;
}
/**
* Find PlaceObject for place witch
* we selected from place picker
*/
void getFirestoreReferenceForPlace(
final String placeId, FindPlaceCallback callback) async {
CollectionReference collection =
_firebaseFirestore.collection(Constants.FIREBASE_PLACE);
QuerySnapshot documents = await collection.getDocuments();
if (documents.documents.length == 0)
callback.onError(ERROR_FIND_MACHES_COLLECTION + Constants.FIREBASE_PLACE);
bool resultsFound = false;
for (DocumentSnapshot doc in documents.documents) {
String docId = doc.documentID;
FirebasePlaceObject placeObject = FirebasePlaceObject.fromSnapshot(doc);
if (placeObject.google_id.isNotEmpty &&
placeObject.google_id == (placeId)) {
placeObject.docId = docId;
//MARK:SET CALLBACK TO VIEW
callback.onFirebasePlaceFind(placeObject);
//MARK:SAVE DATA
_networkSharedPreferences
.saveAcceptComments(placeObject.accept_comments);
_networkSharedPreferences
.saveAcceptPhotoReview(placeObject.accept_photo_review);
//MARK:GET MENU BY PLACE
_getPlaceMenuFromFirebase(docId, placeObject, callback);
//MARK:PRINTING debugPrint('place doc id: $docId');
resultsFound = true;
break;
}
}
if (!resultsFound) callback.onNothingFind(ERROR_FIND_PLACE_FROM_FIRESTORE);
}
void getFirestoreReferenceForPlaceByDocId(
final String documentID, FindPlaceCallback callback) async {
CollectionReference collection =
_firebaseFirestore.collection(Constants.FIREBASE_PLACE);
QuerySnapshot documents = await collection.getDocuments();
if (documents.documents.length == 0)
callback.onError(ERROR_FIND_MACHES_COLLECTION + Constants.FIREBASE_PLACE);
bool resultsFound = false;
for (DocumentSnapshot doc in documents.documents) {
String thisDocId = doc.documentID;
if (documentID == thisDocId) {
FirebasePlaceObject placeObject = FirebasePlaceObject.fromSnapshot(doc);
placeObject.docId = thisDocId;
//MARK:SET CALLBACK TO VIEW
callback.onFirebasePlaceFind(placeObject);
//MARK:SAVE DATA
_networkSharedPreferences
.saveAcceptComments(placeObject.accept_comments);
_networkSharedPreferences
.saveAcceptPhotoReview(placeObject.accept_photo_review);
//MARK:GET MENU BY PLACE
_getPlaceMenuFromFirebase(documentID, placeObject, callback);
//MARK:PRINTING debugPrint('place doc id: $docId');
resultsFound = true;
break;
}
}
if (!resultsFound) callback.onNothingFind(ERROR_FIND_PLACE_FROM_FIRESTORE);
}
/**
* Find Menu for place witch we selected before
*/
void _getPlaceMenuFromFirebase(String placeId,
FirebasePlaceObject placeObject, FindPlaceCallback callback) async {
CollectionReference collection =
_firebaseFirestore.collection(Constants.FIREBASE_MENU);
QuerySnapshot documents = await collection.getDocuments();
if (documents.documents.length == 0)
callback.onError(ERROR_FIND_MACHES_COLLECTION + Constants.FIREBASE_MENU);
bool resultsFound = false;
for (DocumentSnapshot doc in documents.documents) {
FirebaseMenuObject menuObject = FirebaseMenuObject.fromSnapshot(doc);
if (placeObject.docId.isNotEmpty &&
placeObject.docId == menuObject.place_id) {
menuObject.objectId = doc.documentID;
_getMenuProductsByMenuId(placeId, menuObject, callback);
resultsFound = true;
break;
}
}
if (!resultsFound)
callback.onNothingFind(ERROR_FIND_PLACE_MENU_FROM_FIRESTORE);
}
/**
* Find product for place witch we selected before
*/
void _getMenuProductsByMenuId(String placeId, FirebaseMenuObject menuObject,
FindPlaceCallback callback) async {
CollectionReference collectionReference =
_firebaseFirestore.collection(Constants.FIREBASE_ITEMS);
QuerySnapshot documents = await collectionReference
.where(Constants.FIREBASE_MENU_OBJECT_ID,
isEqualTo: menuObject.objectId)
.getDocuments();
if (documents.documents.length == 0)
callback.onError(ERROR_FIND_MACHES_COLLECTION + Constants.FIREBASE_ITEMS);
List<FirebaseOneMenuProduct> products = List();
for (DocumentSnapshot doc in documents.documents) {
FirebaseOneMenuProduct product = FirebaseOneMenuProduct.fromSnapshot(doc);
product.id = doc.documentID;
product.downloadUrl = _imagePublicUrlPrefix +
product.image; //await getDownloadUrlFromGS(product.image);
//MARK: debugPrint(product.downloadUrl);
products.add(product);
}
products.sort((b, a) => a.rating.compareTo(b.rating));
callback.onFind(products);
}
Future<FirebaseOneMenuProduct> getMenuProductByMenuId(var id) async {
DocumentReference documentReference =
_firebaseFirestore.collection(Constants.FIREBASE_ITEMS).document(id);
DocumentSnapshot doc = await documentReference.get();
FirebaseOneMenuProduct product = FirebaseOneMenuProduct.fromSnapshot(doc);
product.id = doc.documentID;
try {
product.downloadUrl = _imagePublicUrlPrefix +
product.image; // await getDownloadUrlFromGS(product.image);
} catch (e) {}
return product;
}
void getMealList(String placeId, Function onChange) async {
FirebaseUser user = await _firebaseUser.currentUser();
if (user.uid != null)
_databaseReference
.child(Constants.FIREBASE_USERS)
.child(user.uid)
.child(Constants.FIREBASE_LISTS)
.child(placeId)
.child(Constants.FIREBASE_SHORT)
.onValue
.listen((data) {
List<String> wishList = (data.snapshot.value != null
? new List.from(data.snapshot.value.cast<String>())
: new List());
if (wishList != null && wishList.length > 0) {
onChange(wishList); //exists = true;
} else {
onChange(null); //exists = false;
}
});
else
onChange(null);
}
void changeDishList(
String placeId, FirebaseOneMenuProduct product, Function onChange) async {
FirebaseUser user = await _firebaseUser.currentUser();
if (user.uid != null) {
var ref = _databaseReference
.child(Constants.FIREBASE_USERS)
.child(user.uid)
.child(Constants.FIREBASE_LISTS)
.child(placeId)
.child(Constants.FIREBASE_SHORT);
ref.once().then((data) {
List<String> wishList = (data.value != null
? new List.from(data.value.cast<String>())
: new List());
if (wishList != null &&
wishList.length > 0 &&
wishList.contains(product.id)) {
wishList.remove(product.id); //exists = true;
} else {
if (wishList == null) wishList = new List<String>();
wishList.add(product.id); //exists = false;
}
ref.set(wishList);
onChange("Success");
});
} else
onChange("User is undefined");
}
void getProductsFromWishList(
List<String> wishList, FindPlaceCallback callback) async {
CollectionReference collectionReference =
_firebaseFirestore.collection(Constants.FIREBASE_ITEMS);
List<FirebaseOneMenuProduct> products = List();
if (wishList == null) callback.onNothingFind(null);
for (int i = 0; i < wishList.length; i++) {
DocumentSnapshot documents =
await collectionReference.document(wishList.elementAt(i)).get();
FirebaseOneMenuProduct product =
FirebaseOneMenuProduct.fromSnapshot(documents);
product.id = documents.documentID;
product.downloadUrl = _imagePublicUrlPrefix +
product.image; //await getDownloadUrlFromGS(product.image);
debugPrint(product.downloadUrl);
products.add(product);
}
products.sort((b, a) => a.rating.compareTo(b.rating));
callback.onFind(products);
}
void getProductPhotos(
String placeId, String productId, MainCallback callback) async {
_databaseReference
.child(Constants.FIREBASE_PLACES)
.child(placeId)
.child(Constants.FIREBASE_ITEMS)
.child(productId)
.child(Constants.FIREBASE_IMAGES)
.orderByKey()
.onValue
.listen((event) {
var ev = event.snapshot;
List<FirebaseReviewImage> firebaseImages = List();
for (var value in ev.value.values) {
FirebaseReviewImage firebaseReviewImage =
FirebaseReviewImage.fromMap(value);
firebaseImages.add(firebaseReviewImage);
}
callback.onSuccess(firebaseImages);
}).onError((er) {
debugPrint(er);
callback.onError(er);
});
}
void getProductReviews(
String placeId, String productId, MainCallback callback) async {
_databaseReference
.child(Constants.FIREBASE_PLACES)
.child(placeId)
.child(Constants.FIREBASE_ITEMS)
.child(productId)
.child(Constants.FIREBASE_REVIEWS)
.orderByChild(Constants.FIREBASE_CREATED_AT)
.onValue
.listen((event) async {
var ev = event.snapshot;
List<FirebaseReviewUser> firebaseReviews = List();
for (var value in ev?.value?.values) {
FirebaseReviewUser firebaseReviewUser =
FirebaseReviewUser.fromMap(value);
try {
firebaseReviewUser.userAvatarDownloadUrl =
await _getFirebaseUserPhotoUrlById(firebaseReviewUser.authorId);
} catch (e) {}
firebaseReviews.add(firebaseReviewUser);
}
callback.onSuccess(firebaseReviews);
}).onError((er) {
debugPrint(er);
callback.onError(er);
});
}
Future<String> _getFirebaseUserPhotoUrlById(String id) async {
return await _storage
.ref()
.child(Constants.FIREBASE_IMAGES)
.child(Constants.FIREBASE_USERS)
.child("${id}.jpg")
.getDownloadURL();
}
void uploadProductPhoto(File image, String productId, String placeId) async {
final photoUrl =
await uploadPhotoReturnDownloadUrl(image, productId, placeId);
FirebaseReviewImage reviewImage = new FirebaseReviewImage();
reviewImage.authorId = (await _firebaseUser.currentUser()).uid;
reviewImage.createdAt = new DateTime.now();
reviewImage.imagePath = photoUrl;
applyImageToProduct(reviewImage, productId, placeId);
}
Future<String> uploadPhotoReturnDownloadUrl(
File image, String productId, String placeId) async {
FirebaseUser user = await _firebaseUser.currentUser();
var uuid = new Uuid();
StorageReference imageRef = _storage
.ref()
.child(Constants.FIREBASE_PLACE)
.child(placeId)
.child(Constants.FIREBASE_ITEMS)
.child(productId)
.child(Constants.FIREBASE_IMAGES)
.child(user.uid + "_" + uuid.v1().toString() + ".jpg");
StorageUploadTask uploadTask = imageRef.putFile(image);
String url = await (await uploadTask.onComplete).ref.getDownloadURL();
return url;
}
}
abstract class ProductDetailInterface{
void onProductFind(var product);
void onError(String error);
void updateProductImages(List<FirebaseReviewImage> firebaseImages);
void updateProductReviews(List<FirebaseReviewUser> firebaseReviews);
void productInWishList(bool t);
void setCommentsAndPhotosPermission(bool acceptComments, bool acceptPhotoReview);
}
abstract class MealPageInterface {
void updatePlaceResultsViews(List<FirebaseOneMenuProduct> products );
void showProgressBar(bool visability);
void onError(String error);
void updateWishList(List<String> wishList);
}
abstract class HomePageInterface {
void showProgressBar(bool visability);
void changeClearIconVisibility(bool visible, FirebasePlaceObject place);
void updatePlaceResultsViews(List<FirebaseOneMenuProduct> products );
void onErrorPlacePicker(PlacesAutocompleteResponse response);
void onError(String error);
void updateWishList(List<String> wishList);
}
abstract class FindPlaceCallback{
onFind(List<FirebaseOneMenuProduct> products);
onError(var error);
onNothingFind(String response);
onFirebasePlaceFind(FirebasePlaceObject firebasePlace);
}
class MealPage extends StatefulWidget {
static String tag = 'meal_page';
var placeId;
var _mainScreenProducts;
MealPage(this.placeId,this._mainScreenProducts);
@override
_MealPageState createState() => _MealPageState(placeId,_mainScreenProducts);
}
class _MealPageState extends State<MealPage> implements MealPageInterface {
var placeId;
var _mainScreenProducts;
_MealPageState(this.placeId, this._mainScreenProducts);
static const platform = const MethodChannel('show_home_screen');
var homeScaffoldKey = new GlobalKey<ScaffoldState>();
var presenter;
List<FirebaseOneMenuProduct> _products;
List<String> _wishList;
@override
void initState() {
presenter = MealPresenter(placeId,this);
platform.setMethodCallHandler(_handleMethod);
}
@override
Widget build(BuildContext context) {
// MARK: implement build
return Scaffold(
key: homeScaffoldKey,
appBar: PreferredSize(
preferredSize: Size.fromHeight(CustomAppBar.APP_BAR_SIZE),
// here the desired height
child: _appBar()),
body: Center(
child: Column(
children: <Widget>[
Expanded(flex: 24, child: _productsListView()),
_bottomView(),
],
),
),
);
}
Widget _appBar() => CustomAppBar(
backIconPress:(){ Navigator.pop(context);},
settingsIconVisibility: false,
);
Widget _productsListView() => ListView.builder(
itemCount: (_products != null ? _products.length : 0),
itemBuilder: (context, i) {
return MenuProduct(_products.elementAt(i),placeId,context, inWishList: true, showWishAddButton: false,);
},
);
Widget _bottomView() => Container(
height: Constants.PADDING_BOTTOM_SHEET,
width: double.infinity,
child: Row(
crossAxisAlignment: CrossAxisAlignment.end,
children: <Widget>[
Expanded(
child: Container(
height: double.infinity,
color: Colors.green,
child: FlatButton.icon(
icon: Icon(
Icons.restaurant_menu,
color: Colors.white,
),
onPressed: _goToScanMenu,
padding: EdgeInsets.all(0),
label: Text("SCAN MENU",
style: TextStyle(color: Colors.white, fontSize: 16.0))),
)),
],
));
@override
void onError(String error) {
if (error != null && homeScaffoldKey.currentState != null)
homeScaffoldKey.currentState.showSnackBar(
SnackBar(content: Text(error)),
); }
@override
void showProgressBar(bool visability) {
// MARK: implement showProgressBar
}
@override
void updatePlaceResultsViews(List<FirebaseOneMenuProduct> products) {
setState(() {
_products = products;
}); }
@override
void updateWishList(List<String> w) {
setState(() {
_wishList = w;
debugPrint('wish list = ${w}');
}); }
void _goToScanMenu() async {
if (_mainScreenProducts == null) {
onError("Place not selected");
return;
}
try {
var data = json.encode(
{'placeId': placeId, "products": _mainScreenProducts});
debugPrint(data);
final int result = await platform.invokeMethod('showHomeScreen', data);
} on PlatformException catch (e) {
debugPrint(e.toString());
}
}
Future<dynamic> _handleMethod(MethodCall call) async {
switch (call.method) {
case "showDetailScreen":
debugPrint(call.arguments);
Map<dynamic, dynamic> ar = json.decode(call.arguments);
debugPrint(" scan: " +
ar["productId"].toString() +
" " +
ar["placeId"].toString());
await Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ProductDetail(
ar["productId"].toString(), ar["placeId"].toString())),
);
_goToScanMenu();
return new Future.value("");
}
}
}
class MealPresenter implements FindPlaceCallback{
MealPageInterface _view;
FirebaseManager _firebaseManager = new FirebaseManager();
MealPresenter(var placeId,this._view){
_init(placeId);
}
void _init(var placeId){
_firebaseManager.getMealList(placeId, (List<String> wishList){
_firebaseManager.getProductsFromWishList(wishList, this);
});
}
@override
onError(var error) {
// MARK: implement onError
return null;
}
@override
onFind(List<FirebaseOneMenuProduct> products) {
_view.updatePlaceResultsViews(products);
}
@override
onFirebasePlaceFind(FirebasePlaceObject firebasePlace) {
// MARK: implement onFirebasePlaceFind
return null;
}
@override
onNothingFind(String response) {
return _view.updatePlaceResultsViews(null);
}
}
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment