diff --git a/assets/values-en/strings.xml b/assets/values-en/strings.xml
index 0015bb0..b2b3ee7 100644
--- a/assets/values-en/strings.xml
+++ b/assets/values-en/strings.xml
@@ -154,4 +154,12 @@ Set on switch on Camera
Go back to %s.
Open settings
+ Return
+ Are you sure you want to return purchase, which cost %s on %s?
+
+You cannot undo this.
+You bonus balance will be changed and you will have %s bonus points.
+ Return confirmed
+ Purchase, which cost %s on %s is returned.
+ Points
diff --git a/assets/values-ru/strings.xml b/assets/values-ru/strings.xml
index d51ed37..b84f307 100644
--- a/assets/values-ru/strings.xml
+++ b/assets/values-ru/strings.xml
@@ -153,4 +153,12 @@
Вернитесь к приложению %s.
Открыть настройки
+ Возврвт
+ Вы подтверждаете возврат покупки на сумму %s от %s?
+
+Отменить возврат нельзя.
+Бонусный баланс будет изменен и составит %s баллов.
+ Возврат подтверждет
+ Покупка на сумму %s от %s возвращена.
+ Баллы
diff --git a/lib/base/base_state.dart b/lib/base/base_state.dart
index be78f8a..64a0e24 100644
--- a/lib/base/base_state.dart
+++ b/lib/base/base_state.dart
@@ -1,4 +1,5 @@
import 'dart:async';
+import 'dart:io';
import 'package:checker/resources.dart';
import 'package:flutter/material.dart';
@@ -10,7 +11,6 @@ import 'package:checker/screens/faq.dart';
import 'package:checker/strings.dart';
import 'package:checker/db.dart';
import 'package:flutter/rendering.dart';
-import 'package:meta/meta.dart';
abstract class BaseState extends State {
@@ -78,7 +78,14 @@ abstract class BaseState extends State {
child: getMenuItem(help_png, StringsLocalization.help())
));
- if (Theme.of(context).platform != TargetPlatform.iOS) {
+ if(showReturnScreen()) {
+ menuItemList.add(new PopupMenuItem(
+ value: 3,
+ child: getMenuItem(exit_png, StringsLocalization.returnLabel())
+ ));
+ }
+
+ if (Platform.isAndroid) {
menuItemList.add(new PopupMenuItem(
value: 2,
child: getMenuItem(exit_png, StringsLocalization.exit())
@@ -95,6 +102,8 @@ abstract class BaseState extends State {
];
}
+ bool showReturnScreen() => false;
+
void onOptionsItemClick(int index) {
switch (index) {
case 0: {
@@ -119,9 +128,14 @@ abstract class BaseState extends State {
platform.invokeMethod('finish');
break;
}
+ case 3:
+ openReturnScreen();
+ break;
}
}
+ void openReturnScreen() {}
+
/// Возвращает пункт меню (Картинка с текстом)
Widget getMenuItem(String image, String text) {
return new Row(children: [
diff --git a/lib/network.dart b/lib/network.dart
index fd85033..7f64166 100644
--- a/lib/network.dart
+++ b/lib/network.dart
@@ -106,3 +106,33 @@ getEndpoint() async {
getToken() async {
return await platform.invokeMethod('getAppToken');
}
+
+Future getUserPurchases(String token, int userId, int page) async {
+
+ var headers = {
+ 'DM-Authorization': 'dmapptoken ${await getToken()}',
+ 'Authorization': 'dmtoken $token',
+ 'Accept-Language': StringsLocalization.localeCode
+ };
+
+
+ var finalEndpoint = "${await getEndpoint()}users/$userId/purchases/?returned=false&page=$page";
+ print(finalEndpoint);
+
+ return httpClient.get(finalEndpoint, headers: headers);
+}
+
+Future returnPurchase(String token, int userId, int purchaseId) async {
+
+ var headers = {
+ 'DM-Authorization': 'dmapptoken ${await getToken()}',
+ 'Authorization': 'dmtoken $token',
+ 'Accept-Language': StringsLocalization.localeCode
+ };
+
+
+ var finalEndpoint = "${await getEndpoint()}users/$userId/purchases/$purchaseId";
+ print(finalEndpoint);
+
+ return httpClient.delete(finalEndpoint, headers: headers);
+}
diff --git a/lib/screens/purchase.dart b/lib/screens/purchase.dart
index c7309b5..5f1c51d 100644
--- a/lib/screens/purchase.dart
+++ b/lib/screens/purchase.dart
@@ -1,5 +1,6 @@
import 'package:checker/base/base_screen.dart';
import 'package:checker/db.dart';
+import 'package:checker/screens/return.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'dart:convert';
@@ -127,6 +128,16 @@ class PurchaseScreenState extends BaseState {
return listView;
}
+ bool showReturnScreen() => true;
+
+ void openReturnScreen() {
+ Future.delayed(const Duration(milliseconds: 200), () {
+ Route route = MaterialPageRoute(builder: (BuildContext context) =>
+ ReturnScreen(helper, app, user['id'], user['bonus']), fullscreenDialog: true);
+ Navigator.push(context, route);
+ });
+ }
+
getBonusInputField() {
var bonusTextField = new TextField(
keyboardType: TextInputType.number,
diff --git a/lib/screens/return.dart b/lib/screens/return.dart
new file mode 100644
index 0000000..5264612
--- /dev/null
+++ b/lib/screens/return.dart
@@ -0,0 +1,186 @@
+import 'dart:convert';
+
+import 'package:checker/base/base_screen.dart';
+import 'package:checker/base/base_state.dart';
+import 'package:checker/db.dart';
+import 'package:checker/strings.dart';
+import 'package:flutter/material.dart';
+import 'package:checker/network.dart';
+import 'package:http/http.dart';
+import 'package:intl/intl.dart';
+
+class ReturnScreen extends BaseScreen {
+ final int userId;
+ final int bonus;
+
+ ReturnScreen(SqliteHelper helper, String app, this.userId, this.bonus) : super(helper, app);
+
+ @override
+ _ReturnScreenState createState() => _ReturnScreenState(helper, app);
+}
+
+class _ReturnScreenState extends BaseState {
+ static DateFormat dateFormat = DateFormat('d MMM yy');
+
+ ScrollController _controller;
+ List _purchases = [];
+ int _bonus;
+ int _page = 1;
+ bool _fullLoaded = false;
+ bool _loading = false;
+
+
+ _ReturnScreenState(SqliteHelper helper, String app) : super(helper, app);
+
+ bool isAutomaticallyImplyLeading() => true;
+
+ @override
+ Widget getScreenContent() => ListView.separated(
+ itemBuilder: (context, index) {
+ final TextStyle style = Theme.of(context).textTheme.subhead;
+ if(index > 0) {
+ final item = _purchases[index - 1];
+ final DateTime date = DateTime.parse(item['date']);
+ final String formattedDate = dateFormat.format(date);
+ return GestureDetector(
+ child: Padding(
+ padding: const EdgeInsets.all(16),
+ child: Row(
+ children: [
+ Expanded(
+ child: Text(formattedDate, style: style),
+ ),
+ Expanded(
+ child: Text(item['sum_total'], style: style),
+ ),
+ Expanded(
+ child: Text(item['sum_bonus'].toString(), style: style),
+ )
+ ],
+ ),
+ ),
+ onTap: () => _confirmReturnPurchase(item, formattedDate),
+ );
+ } else {
+ final TextStyle headerStyle = style.copyWith(color: Colors.grey);
+ return Padding(
+ padding: const EdgeInsets.all(16),
+ child: Row(
+ children: [
+ Expanded(
+ child: Container(),
+ ),
+ Expanded(
+ child: Text(StringsLocalization.sum(), style: headerStyle),
+ ),
+ Expanded(
+ child: Text(StringsLocalization.points(), style: headerStyle),
+ )
+ ],
+ ),
+ );
+ }
+ },
+ separatorBuilder: (_, index) => index == 0
+ ? Container()
+ : Padding(
+ padding: const EdgeInsets.symmetric(horizontal: 16),
+ child: Divider(height: 1,),
+ ),
+ itemCount: _purchases.length > 0 ? _purchases.length + 1 : _purchases.length,
+ controller: _controller);
+
+ @override
+ Widget build(BuildContext context) => getMainWidget();
+
+ @override
+ String getTitle() => StringsLocalization.returnLabel();
+
+ @override
+ void initState() {
+ super.initState();
+ setState(() {
+ loading = true;
+ });
+ _loadUserPurchases();
+ _bonus = widget.bonus;
+ _controller = ScrollController();
+ _controller.addListener(_scrollListener);
+ }
+
+ void _scrollListener() {
+ if (_controller.offset >= _controller.position.maxScrollExtent &&
+ !_controller.position.outOfRange) {
+ _loadUserPurchases();
+ }
+ }
+
+ void _loadUserPurchases() async {
+ if(!_fullLoaded && !_loading) {
+ _loading = true;
+ setState(() => loading = true);
+ String token = await helper.getToken();
+ Response response = await getUserPurchases(token, widget.userId, _page);
+ final responseJson = json.decode(response.body);
+ List purchases = responseJson['results'];
+ _fullLoaded = _page == responseJson['pages'];
+ setState(() {
+ loading = false;
+ _purchases.addAll(purchases);
+ });
+ _page++;
+ _loading = false;
+ setState(() => loading = false);
+ }
+ }
+
+ void _confirmReturnPurchase(Map purchase, String formattedDate) {
+ showDialog(
+ context: context,
+ builder: (context) =>
+ AlertDialog(
+ title: Text(StringsLocalization.confirmation()),
+ content: Text(StringsLocalization.returnConfirmation(
+ purchase['sum_total'], formattedDate, _bonus + purchase['sum_bonus'])),
+ actions: [
+ FlatButton(
+ child: Text(StringsLocalization.no()),
+ onPressed: () => Navigator.pop(context),
+ ),
+ FlatButton(
+ child: Text(StringsLocalization.yes()),
+ onPressed: () {
+ Navigator.pop(context);
+ _returnPurchase(purchase, formattedDate);
+ }
+ )
+ ],
+ )
+ );
+ }
+
+ void _returnPurchase(Map purchase, String formattedDate) async {
+ String token = await helper.getToken();
+ final Response response = await returnPurchase(token, widget.userId, purchase['id']);
+ if(response.statusCode == 204) {
+ _bonus += purchase['sum_bonus'];
+ setState(() {
+ _purchases.removeWhere((p) => p['id'] == purchase['id']);
+ });
+ showDialog(
+ context: context,
+ builder: (context) =>
+ AlertDialog(
+ title: Text(StringsLocalization.returnConfirmed()),
+ content: Text(StringsLocalization.returnConfirmedContent(purchase['sum_total'], formattedDate)),
+ actions: [
+ FlatButton(
+ child: Text(StringsLocalization.yes()),
+ onPressed: () => Navigator.pop(context)
+ )
+ ],
+ )
+ );
+ }
+ }
+}
diff --git a/lib/strings.dart b/lib/strings.dart
index 8061b96..08ce633 100644
--- a/lib/strings.dart
+++ b/lib/strings.dart
@@ -125,6 +125,11 @@ class StringsLocalization {
String trimmedVal = val.substring(0, val.length - 3);
return sprintf(strings['payment_complite'], [val, declineCurrency(int.parse(trimmedVal), code)]);
}
+ static String returnConfirmation(String sum, String date, int points) =>
+ sprintf(strings['return_purchase_content'], [sum, date, points.toString()]);
+
+ static String returnConfirmedContent(String sum, String date) =>
+ sprintf(strings['return_confirmation_content'], [sum, date]);
static String registration() => strings['registration'];
static String usage() => strings['usage'];
@@ -218,4 +223,7 @@ class StringsLocalization {
static String joysMinus() => strings['joys_minus'];
static String joysHint() => strings['joys_hint'];
static String phone() => strings['phone'];
+ static String returnLabel() => strings['returnLabel'];
+ static String returnConfirmed() => strings['return_confirmation'];
+ static String points() => strings['points'];
}
diff --git a/pubspec.lock b/pubspec.lock
index 9f407d6..f06d8c4 100644
--- a/pubspec.lock
+++ b/pubspec.lock
@@ -48,6 +48,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "0.4.10"
+ intl:
+ dependency: "direct main"
+ description:
+ name: intl
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "0.15.7"
meta:
dependency: transitive
description:
diff --git a/pubspec.yaml b/pubspec.yaml
index ae07c59..2a8b048 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -9,6 +9,7 @@ dependencies:
image_picker: '^0.4.1' # use for ask permissions @ iOS
xml: "^3.0.0"
sentry: 2.2.0
+ intl: 0.15.7
flutter:
sdk: flutter