Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: 5326 - users can now select proof from gallery in "add price" page #5679

Merged
merged 2 commits into from
Oct 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 17 additions & 5 deletions packages/smooth_app/lib/pages/image_crop_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,23 @@ import 'package:smooth_app/pages/crop_parameters.dart';
import 'package:smooth_app/pages/product_crop_helper.dart';

/// Safely picks an image file from gallery or camera, regarding access denied.
Future<XFile?> pickImageFile(final BuildContext context) async {
Future<XFile?> pickImageFile(
final BuildContext context, {
final UserPictureSource? forcedSource,
}) async {
/// Picks an image file from gallery or camera.
Future<XFile?> innerPickImageFile(
final BuildContext context, {
bool ignorePlatformException = false,
}) async {
final UserPictureSource? source = await _getUserPictureSource(context);
if (source == null) {
return null;
final UserPictureSource? source;
if (forcedSource != null) {
source = forcedSource;
} else {
source = await _getUserPictureSource(context);
if (source == null) {
return null;
}
}
final ImagePicker picker = ImagePicker();
if (source == UserPictureSource.GALLERY) {
Expand Down Expand Up @@ -277,8 +285,12 @@ Future<CropParameters?> confirmAndUploadNewImage(
final BuildContext context, {
required final CropHelper cropHelper,
required final bool isLoggedInMandatory,
final UserPictureSource? forcedSource,
}) async {
final XFile? fullPhoto = await pickImageFile(context);
final XFile? fullPhoto = await pickImageFile(
context,
forcedSource: forcedSource,
);
if (fullPhoto == null) {
return null;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,9 @@ class UserPreferencesAccount extends AbstractUserPreferences {
appLocalizations.user_search_proofs_title,
() async => Navigator.of(context).push(
MaterialPageRoute<void>(
builder: (BuildContext context) => const PricesProofsPage(),
builder: (BuildContext context) => const PricesProofsPage(
selectProof: false,
),
),
),
Icons.receipt,
Expand Down
36 changes: 24 additions & 12 deletions packages/smooth_app/lib/pages/prices/price_model.dart
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ class PriceModel with ChangeNotifier {
required final List<OsmLocation>? locations,
required final Currency currency,
final PriceMetaProduct? initialProduct,
}) : proof = null,
}) : _proof = null,
_proofType = proofType,
_date = DateTime.now(),
_currency = currency,
Expand All @@ -29,12 +29,19 @@ class PriceModel with ChangeNotifier {
];

PriceModel.proof({
required Proof this.proof,
}) : _proofType = proof.type!,
_date = proof.date!,
_locations = null,
_currency = proof.currency!,
priceAmountModels = <PriceAmountModel>[];
required Proof proof,
}) : priceAmountModels = <PriceAmountModel>[] {
setProof(proof);
}

void setProof(final Proof proof) {
_proof = proof;
_cropParameters = null;
_proofType = proof.type!;
_date = proof.date!;
_locations = null;
_currency = proof.currency!;
}

/// Checks if a proof cannot be reused for prices adding.
///
Expand All @@ -49,6 +56,8 @@ class PriceModel with ChangeNotifier {
proof.imageThumbPath == null ||
proof.filePath == null;

bool get hasImage => _proof != null || _cropParameters != null;

final List<PriceAmountModel> priceAmountModels;

CropParameters? _cropParameters;
Expand All @@ -57,21 +66,24 @@ class PriceModel with ChangeNotifier {

set cropParameters(final CropParameters? value) {
_cropParameters = value;
_proof = null;
notifyListeners();
}

final Proof? proof;
Proof? _proof;

Proof? get proof => _proof;

ProofType _proofType;
late ProofType _proofType;

ProofType get proofType => proof != null ? proof!.type! : _proofType;
ProofType get proofType => _proof != null ? _proof!.type! : _proofType;

set proofType(final ProofType proofType) {
_proofType = proofType;
notifyListeners();
}

DateTime _date;
late DateTime _date;

DateTime get date => _date;

Expand All @@ -96,7 +108,7 @@ class PriceModel with ChangeNotifier {
? OsmLocation.fromPrice(proof!.location!)
: _locations!.firstOrNull;

Currency _currency;
late Currency _currency;

Currency get currency => _currency;

Expand Down
141 changes: 110 additions & 31 deletions packages/smooth_app/lib/pages/prices/price_proof_card.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,14 @@ import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:openfoodfacts/openfoodfacts.dart';
import 'package:provider/provider.dart';
import 'package:smooth_app/data_models/preferences/user_preferences.dart';
import 'package:smooth_app/generic_lib/buttons/smooth_large_button_with_icon.dart';
import 'package:smooth_app/generic_lib/widgets/smooth_card.dart';
import 'package:smooth_app/helpers/camera_helper.dart';
import 'package:smooth_app/pages/crop_parameters.dart';
import 'package:smooth_app/pages/image_crop_page.dart';
import 'package:smooth_app/pages/prices/price_model.dart';
import 'package:smooth_app/pages/prices/prices_proofs_page.dart';
import 'package:smooth_app/pages/proof_crop_helper.dart';
import 'package:smooth_app/query/product_query.dart';

Expand All @@ -29,20 +32,17 @@ class PriceProofCard extends StatelessWidget {
children: <Widget>[
Text(appLocalizations.prices_proof_subtitle),
if (model.proof != null)
LayoutBuilder(
builder: (BuildContext context, BoxConstraints constraints) =>
Image(
image: NetworkImage(
model.proof!
.getFileUrl(
uriProductHelper: ProductQuery.uriPricesHelper,
isThumbnail: true,
)!
.toString(),
),
Image(
image: NetworkImage(
model.proof!
.getFileUrl(
uriProductHelper: ProductQuery.uriPricesHelper,
isThumbnail: true,
)!
.toString(),
),
),
if (model.cropParameters != null)
)
else if (model.cropParameters != null)
LayoutBuilder(
builder: (BuildContext context, BoxConstraints constraints) =>
Image(
Expand All @@ -53,29 +53,24 @@ class PriceProofCard extends StatelessWidget {
height: constraints.maxWidth,
),
),
//Text(model.cropParameters!.smallCroppedFile.path),
SmoothLargeButtonWithIcon(
text: model.proof == null && model.cropParameters == null
text: !model.hasImage
? appLocalizations.prices_proof_find
: model.proofType == ProofType.receipt
? appLocalizations.prices_proof_receipt
: appLocalizations.prices_proof_price_tag,
icon: model.proof == null && model.cropParameters == null
? _iconTodo
: _iconDone,
onPressed: model.proof != null
? null
: () async {
final CropParameters? cropParameters =
await confirmAndUploadNewImage(
context,
cropHelper: ProofCropHelper(model: model),
isLoggedInMandatory: true,
);
if (cropParameters != null) {
model.cropParameters = cropParameters;
}
},
icon: !model.hasImage ? _iconTodo : _iconDone,
onPressed: () async {
final _ProofSource? proofSource =
await _ProofSource.select(context);
if (proofSource == null) {
return;
}
if (!context.mounted) {
return;
}
return proofSource.process(context, model);
},
),
LayoutBuilder(
builder: (BuildContext context, BoxConstraints constraints) => Row(
Expand Down Expand Up @@ -112,3 +107,87 @@ class PriceProofCard extends StatelessWidget {
);
}
}

enum _ProofSource {
camera,
gallery,
history;

Future<void> process(
final BuildContext context,
final PriceModel model,
) async {
switch (this) {
case _ProofSource.history:
final Proof? proof = await Navigator.of(context).push<Proof>(
MaterialPageRoute<Proof>(
builder: (BuildContext context) => const PricesProofsPage(
selectProof: true,
),
),
);
if (proof != null) {
model.setProof(proof);
model.notifyListeners();
}
return;
case _ProofSource.camera:
case _ProofSource.gallery:
final UserPictureSource source = this == _ProofSource.gallery
? UserPictureSource.GALLERY
: UserPictureSource.CAMERA;
final CropParameters? cropParameters = await confirmAndUploadNewImage(
context,
cropHelper: ProofCropHelper(model: model),
isLoggedInMandatory: true,
forcedSource: source,
);
if (cropParameters != null) {
model.cropParameters = cropParameters;
}
}
}

static Future<_ProofSource?> select(final BuildContext context) async {
final AppLocalizations appLocalizations = AppLocalizations.of(context);
return showCupertinoModalPopup<_ProofSource>(
context: context,
builder: (final BuildContext context) => CupertinoActionSheet(
title: Text(appLocalizations.prices_proof_find),
cancelButton: CupertinoActionSheetAction(
onPressed: () => Navigator.of(context).pop(),
child: Text(
appLocalizations.cancel,
),
),
actions: <Widget>[
if (CameraHelper.hasACamera)
CupertinoActionSheetAction(
onPressed: () => Navigator.of(context).pop(
_ProofSource.camera,
),
child: Text(
appLocalizations.settings_app_camera,
),
),
CupertinoActionSheetAction(
onPressed: () => Navigator.of(context).pop(
_ProofSource.gallery,
),
child: Text(
appLocalizations.gallery_source_label,
),
),
CupertinoActionSheetAction(
onPressed: () => Navigator.of(context).pop(
_ProofSource.history,
),
child: Text(
appLocalizations.user_search_proofs_title,
),
),
],
),
);
}
}
29 changes: 20 additions & 9 deletions packages/smooth_app/lib/pages/prices/prices_proofs_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,12 @@ import 'package:smooth_app/widgets/smooth_scaffold.dart';

/// Page that displays the latest proofs of the current user.
class PricesProofsPage extends StatefulWidget {
const PricesProofsPage();
const PricesProofsPage({
required this.selectProof,
});

/// Do we want to select a proof (true), or just to see its details (false)?
final bool selectProof;

@override
State<PricesProofsPage> createState() => _PricesProofsPageState();
Expand Down Expand Up @@ -119,15 +124,21 @@ class _PricesProofsPageState extends State<PricesProofsPage>
);
}
return InkWell(
onTap: () async => Navigator.push<void>(
context,
MaterialPageRoute<void>(
builder: (BuildContext context) =>
PriceProofPage(
proof,
onTap: () async {
if (widget.selectProof) {
Navigator.of(context).pop(proof);
return;
}
return Navigator.push<void>(
context,
MaterialPageRoute<void>(
builder: (BuildContext context) =>
PriceProofPage(
proof,
),
),
),
), // PriceProofPage
);
}, // PriceProofPage
child: _PriceProofImage(proof,
squareSize: squareSize),
);
Expand Down
Loading