feat: opravit a rozdelit iOS
parent
dfb5a091aa
commit
365976a853
@ -1,10 +1,45 @@
|
||||
# This file tracks properties of this Flutter project.
|
||||
# Used by Flutter tool to assess capabilities and perform upgrades etc.
|
||||
#
|
||||
# This file should be version controlled and should not be manually edited.
|
||||
# This file should be version controlled.
|
||||
|
||||
version:
|
||||
revision: 097d3313d8e2c7f901932d63e537c1acefb87800
|
||||
revision: 52b3dc25f6471c27b2144594abb11c741cb88f57
|
||||
channel: stable
|
||||
|
||||
project_type: app
|
||||
|
||||
# Tracks metadata for the flutter migrate command
|
||||
migration:
|
||||
platforms:
|
||||
- platform: root
|
||||
create_revision: 52b3dc25f6471c27b2144594abb11c741cb88f57
|
||||
base_revision: 52b3dc25f6471c27b2144594abb11c741cb88f57
|
||||
- platform: android
|
||||
create_revision: 52b3dc25f6471c27b2144594abb11c741cb88f57
|
||||
base_revision: 52b3dc25f6471c27b2144594abb11c741cb88f57
|
||||
- platform: ios
|
||||
create_revision: 52b3dc25f6471c27b2144594abb11c741cb88f57
|
||||
base_revision: 52b3dc25f6471c27b2144594abb11c741cb88f57
|
||||
- platform: linux
|
||||
create_revision: 52b3dc25f6471c27b2144594abb11c741cb88f57
|
||||
base_revision: 52b3dc25f6471c27b2144594abb11c741cb88f57
|
||||
- platform: macos
|
||||
create_revision: 52b3dc25f6471c27b2144594abb11c741cb88f57
|
||||
base_revision: 52b3dc25f6471c27b2144594abb11c741cb88f57
|
||||
- platform: web
|
||||
create_revision: 52b3dc25f6471c27b2144594abb11c741cb88f57
|
||||
base_revision: 52b3dc25f6471c27b2144594abb11c741cb88f57
|
||||
- platform: windows
|
||||
create_revision: 52b3dc25f6471c27b2144594abb11c741cb88f57
|
||||
base_revision: 52b3dc25f6471c27b2144594abb11c741cb88f57
|
||||
|
||||
# User provided section
|
||||
|
||||
# List of Local paths (relative to this file) that should be
|
||||
# ignored by the migrate tool.
|
||||
#
|
||||
# Files that are not part of the templates will be ignored by default.
|
||||
unmanaged_files:
|
||||
- 'lib/main.dart'
|
||||
- 'ios/Runner.xcodeproj/project.pbxproj'
|
||||
|
@ -0,0 +1,283 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:canteenlib/canteenlib.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
|
||||
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
||||
import 'package:opencanteen/okna/android/welcome.dart';
|
||||
|
||||
import '../../lang/lang.dart';
|
||||
import '../../loginmanager.dart';
|
||||
import '../../main.dart';
|
||||
import '../../util.dart';
|
||||
import 'jidelnicek.dart';
|
||||
import 'offline_jidelnicek.dart';
|
||||
|
||||
class AndroidLogin extends StatefulWidget {
|
||||
const AndroidLogin({Key? key}) : super(key: key);
|
||||
@override
|
||||
State<AndroidLogin> createState() => _AndroidLoginState();
|
||||
}
|
||||
|
||||
class _AndroidLoginState extends State<AndroidLogin> {
|
||||
TextEditingController userControl = TextEditingController();
|
||||
TextEditingController passControl = TextEditingController();
|
||||
TextEditingController canteenControl = TextEditingController();
|
||||
bool rememberMe = false;
|
||||
bool _showUrl = false;
|
||||
String dropdownUrl = instance.first["url"] ?? "";
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
LoginManager.getDetails().then((r) async {
|
||||
// žádat o oprávnění na android
|
||||
flutterLocalNotificationsPlugin
|
||||
.resolvePlatformSpecificImplementation<
|
||||
AndroidFlutterLocalNotificationsPlugin>()
|
||||
?.requestPermission();
|
||||
|
||||
if (r != null) {
|
||||
// Automaticky přihlásit
|
||||
showDialog(
|
||||
context: context,
|
||||
barrierDismissible: false,
|
||||
builder: (_) => Dialog(
|
||||
child: SizedBox(
|
||||
height: 100,
|
||||
child: Row(children: [
|
||||
const Padding(
|
||||
padding: EdgeInsets.all(10),
|
||||
child: CircularProgressIndicator(),
|
||||
),
|
||||
Text(Languages.of(context)!.loggingIn)
|
||||
]),
|
||||
),
|
||||
));
|
||||
var canteen = Canteen(r["url"]!);
|
||||
try {
|
||||
var l = await canteen.login(r["user"]!, r["pass"]!);
|
||||
if (!l) {
|
||||
if (!mounted) return;
|
||||
ScaffoldMessenger.of(context).hideCurrentSnackBar();
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text(Languages.of(context)!.loginFailed),
|
||||
),
|
||||
);
|
||||
return;
|
||||
}
|
||||
const storage = FlutterSecureStorage();
|
||||
var odsouhlasil = await storage.read(key: "oc_souhlas");
|
||||
if (!mounted) return;
|
||||
if (odsouhlasil == null || odsouhlasil != "ano") {
|
||||
Navigator.pushAndRemoveUntil(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (c) => AndroidWelcome(canteen: canteen),
|
||||
),
|
||||
(route) => false);
|
||||
} else {
|
||||
Navigator.pushAndRemoveUntil(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) => AndroidJidelnicek(canteen: canteen),
|
||||
),
|
||||
(route) => false);
|
||||
}
|
||||
} on PlatformException {
|
||||
if (!mounted) return;
|
||||
Navigator.of(context).pop();
|
||||
ScaffoldMessenger.of(context).hideCurrentSnackBar();
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text(Languages.of(context)!.corrupted),
|
||||
),
|
||||
);
|
||||
} catch (_) {
|
||||
if (!mounted) return;
|
||||
Navigator.of(context).pop();
|
||||
ScaffoldMessenger.of(context).hideCurrentSnackBar();
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text(Languages.of(context)!.errorContacting),
|
||||
),
|
||||
);
|
||||
goOffline();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text(Languages.of(context)!.logIn),
|
||||
automaticallyImplyLeading: false,
|
||||
),
|
||||
body: Center(
|
||||
child: SingleChildScrollView(
|
||||
child: SizedBox(
|
||||
width: MediaQuery.of(context).size.width - 50,
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
Text(
|
||||
Languages.of(context)!.appName,
|
||||
textAlign: TextAlign.center,
|
||||
style: const TextStyle(
|
||||
fontWeight: FontWeight.bold, fontSize: 40),
|
||||
),
|
||||
Text(
|
||||
Languages.of(context)!.logIn,
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
TextField(
|
||||
controller: userControl,
|
||||
autofillHints: const [AutofillHints.username],
|
||||
decoration: InputDecoration(
|
||||
labelText: Languages.of(context)!.username),
|
||||
),
|
||||
TextField(
|
||||
autofillHints: const [AutofillHints.password],
|
||||
decoration: InputDecoration(
|
||||
labelText: Languages.of(context)!.password),
|
||||
controller: passControl,
|
||||
obscureText: true,
|
||||
),
|
||||
const SizedBox(
|
||||
height: 10,
|
||||
),
|
||||
DropdownButton(
|
||||
isExpanded: true,
|
||||
value: dropdownUrl,
|
||||
items: instance.map<DropdownMenuItem<String>>((e) {
|
||||
return DropdownMenuItem<String>(
|
||||
value: e["url"],
|
||||
child: Text(e["name"]!),
|
||||
);
|
||||
}).toList(),
|
||||
onChanged: (String? value) {
|
||||
setState(() {
|
||||
if (value == "") {
|
||||
_showUrl = true;
|
||||
} else {
|
||||
_showUrl = false;
|
||||
}
|
||||
dropdownUrl = value!;
|
||||
});
|
||||
},
|
||||
),
|
||||
AnimatedOpacity(
|
||||
opacity: _showUrl ? 1.0 : 0.0,
|
||||
duration: const Duration(milliseconds: 300),
|
||||
child: TextField(
|
||||
autofillHints: const [AutofillHints.url],
|
||||
decoration: InputDecoration(
|
||||
labelText: Languages.of(context)!.iCanteenUrl),
|
||||
keyboardType: TextInputType.url,
|
||||
controller: canteenControl,
|
||||
),
|
||||
),
|
||||
Row(mainAxisAlignment: MainAxisAlignment.center, children: [
|
||||
Switch(
|
||||
value: rememberMe,
|
||||
onChanged: (value) {
|
||||
setState(() {
|
||||
rememberMe = value;
|
||||
});
|
||||
}),
|
||||
Text(Languages.of(context)!.rememberMe)
|
||||
]),
|
||||
TextButton(
|
||||
onPressed: () async {
|
||||
var canteenUrl = (dropdownUrl == "")
|
||||
? canteenControl.text
|
||||
: dropdownUrl;
|
||||
if (!canteenUrl.startsWith("https://") &&
|
||||
!canteenUrl.startsWith("http://")) {
|
||||
canteenUrl = "https://$canteenUrl";
|
||||
}
|
||||
var canteen = Canteen(canteenUrl);
|
||||
try {
|
||||
var l = await canteen.login(
|
||||
userControl.text, passControl.text);
|
||||
if (!l) {
|
||||
if (!mounted) return;
|
||||
ScaffoldMessenger.of(context).hideCurrentSnackBar();
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content:
|
||||
Text(Languages.of(context)!.loginFailed),
|
||||
),
|
||||
);
|
||||
return;
|
||||
}
|
||||
if (rememberMe) {
|
||||
LoginManager.setDetails(
|
||||
userControl.text, passControl.text, canteenUrl);
|
||||
}
|
||||
// souhlas
|
||||
const storage = FlutterSecureStorage();
|
||||
var odsouhlasil =
|
||||
await storage.read(key: "oc_souhlas");
|
||||
if (!mounted) return;
|
||||
if (odsouhlasil == null || odsouhlasil != "ano") {
|
||||
Navigator.pushAndRemoveUntil(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (c) => AndroidWelcome(
|
||||
canteen: canteen,
|
||||
)),
|
||||
(route) => false);
|
||||
} else {
|
||||
Navigator.pushAndRemoveUntil(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) => AndroidJidelnicek(
|
||||
canteen: canteen,
|
||||
)),
|
||||
(route) => false);
|
||||
}
|
||||
} on PlatformException {
|
||||
if (!mounted) return;
|
||||
ScaffoldMessenger.of(context).hideCurrentSnackBar();
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text(Languages.of(context)!.corrupted),
|
||||
),
|
||||
);
|
||||
} on Exception catch (_) {
|
||||
if (!mounted) return;
|
||||
ScaffoldMessenger.of(context).hideCurrentSnackBar();
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content:
|
||||
Text(Languages.of(context)!.errorContacting),
|
||||
),
|
||||
);
|
||||
goOffline();
|
||||
}
|
||||
},
|
||||
child: Text(Languages.of(context)!.logIn)),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
));
|
||||
}
|
||||
|
||||
/// Získá offline soubor a zobrazí údaje
|
||||
void goOffline() async {
|
||||
if (!mounted) return;
|
||||
if (Platform.isAndroid) {
|
||||
Navigator.pushAndRemoveUntil(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: ((context) => const AndroidOfflineJidelnicek())),
|
||||
(route) => false);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,143 @@
|
||||
import 'package:canteenlib/canteenlib.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:opencanteen/okna/ios/login.dart';
|
||||
import 'package:opencanteen/util.dart';
|
||||
|
||||
import '../../lang/lang.dart';
|
||||
|
||||
class IOSBurza extends StatefulWidget {
|
||||
const IOSBurza({Key? key, required this.canteen}) : super(key: key);
|
||||
final Canteen canteen;
|
||||
@override
|
||||
State<IOSBurza> createState() => _IOSBurzaState();
|
||||
}
|
||||
|
||||
class _IOSBurzaState extends State<IOSBurza> {
|
||||
List<Widget> obsah = [];
|
||||
double kredit = 0.0;
|
||||
Future<void> nactiBurzu(BuildContext context) async {
|
||||
obsah = [const CircularProgressIndicator()];
|
||||
widget.canteen.ziskejUzivatele().then((kr) {
|
||||
kredit = kr.kredit;
|
||||
widget.canteen.ziskatBurzu().then((burza) {
|
||||
setState(() {
|
||||
obsah = [];
|
||||
if (burza.isEmpty) {
|
||||
obsah = [
|
||||
Text(
|
||||
Languages.of(context)!.noExchange,
|
||||
style: const TextStyle(fontSize: 20),
|
||||
),
|
||||
Text(Languages.of(context)!.pullToReload)
|
||||
];
|
||||
} else {
|
||||
for (var b in burza) {
|
||||
obsah.add(
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 15),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text("${b.den.day}. ${b.den.month}."),
|
||||
const SizedBox(width: 10),
|
||||
Flexible(
|
||||
child: Text(
|
||||
b.nazev,
|
||||
),
|
||||
),
|
||||
Text("${b.pocet}x"),
|
||||
CupertinoButton(
|
||||
onPressed: () {
|
||||
widget.canteen.objednatZBurzy(b).then((a) {
|
||||
if (a) {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) => CupertinoAlertDialog(
|
||||
title: Text(Languages.of(context)!.ordered),
|
||||
content: Text(
|
||||
Languages.of(context)!.orderSuccess),
|
||||
actions: [
|
||||
CupertinoButton(
|
||||
child: Text(Languages.of(context)!.ok),
|
||||
onPressed: () =>
|
||||
Navigator.of(context).pop(),
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
} else {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) => CupertinoAlertDialog(
|
||||
title: Text(
|
||||
Languages.of(context)!.cannotOrder),
|
||||
content: Text(
|
||||
Languages.of(context)!.errorOrdering),
|
||||
actions: [
|
||||
CupertinoButton(
|
||||
child: Text(Languages.of(context)!.ok),
|
||||
onPressed: () =>
|
||||
Navigator.of(context).pop(),
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
nactiBurzu(context);
|
||||
});
|
||||
},
|
||||
child: Text(Languages.of(context)!.order)),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}).catchError((o) {
|
||||
if (!widget.canteen.prihlasen) {
|
||||
Navigator.pushReplacement(
|
||||
context, MaterialPageRoute(builder: (c) => const IOSLogin()));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
nactiBurzu(context);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
drawer: drawerGenerator(context, widget.canteen, 3),
|
||||
appBar: AppBar(
|
||||
title: Text(Languages.of(context)!.exchange),
|
||||
),
|
||||
body: RefreshIndicator(
|
||||
child: Center(
|
||||
child: SizedBox(
|
||||
width: MediaQuery.of(context).size.width - 50,
|
||||
child: Column(
|
||||
children: [
|
||||
const SizedBox(height: 10),
|
||||
Text("${Languages.of(context)!.balance}$kredit Kč"),
|
||||
const SizedBox(height: 10),
|
||||
SingleChildScrollView(
|
||||
physics: const AlwaysScrollableScrollPhysics(),
|
||||
child: SizedBox(
|
||||
height: MediaQuery.of(context).size.height / 1.3,
|
||||
child: Column(children: obsah),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
onRefresh: () => nactiBurzu(context)),
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,568 @@
|
||||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:canteenlib/canteenlib.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
||||
import 'package:opencanteen/okna/ios/login.dart';
|
||||
import 'package:opencanteen/okna/ios/nastaveni.dart';
|
||||
import 'package:opencanteen/util.dart';
|
||||
import 'package:package_info_plus/package_info_plus.dart';
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
|
||||
import '../../lang/lang.dart';
|
||||
|
||||
class IOSJidelnicek extends StatefulWidget {
|
||||
const IOSJidelnicek({Key? key, required this.canteen}) : super(key: key);
|
||||
final Canteen canteen;
|
||||
@override
|
||||
State<IOSJidelnicek> createState() => _IOSJidelnicekState();
|
||||
}
|
||||
|
||||
class _IOSJidelnicekState extends State<IOSJidelnicek> {
|
||||
List<Widget> obsah = [const CircularProgressIndicator()];
|
||||
DateTime den = DateTime.now();
|
||||
String denTydne = "";
|
||||
double kredit = 0.0;
|
||||
bool _skipWeekend = false;
|
||||
|
||||
void kontrolaTyden(BuildContext context) async {
|
||||
var prefs = await SharedPreferences.getInstance();
|
||||
if (prefs.getBool("tyden") ?? false) {
|
||||
// Zjistit jestli je objednáno na přístí týden
|
||||
var pristi = den.add(const Duration(days: 6));
|
||||
for (var i = 0; i < 5; i++) {
|
||||
var jidelnicek = await widget.canteen
|
||||
.jidelnicekDen(den: pristi.add(Duration(days: i + 1)));
|
||||
if (jidelnicek.jidla.isNotEmpty &&
|
||||
!jidelnicek.jidla.any((element) => element.objednano == true)) {
|
||||
if (!mounted) break;
|
||||
ScaffoldMessenger.of(context).hideCurrentSnackBar();
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text(Languages.of(context)!.noOrder),
|
||||
duration: const Duration(seconds: 5),
|
||||
action: SnackBarAction(
|
||||
onPressed: () => setState(
|
||||
() {
|
||||
den = pristi.add(Duration(days: i + 1));
|
||||
nactiJidlo();
|
||||
},
|
||||
),
|
||||
label: Languages.of(context)!.jump,
|
||||
),
|
||||
),
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> nactiJidlo() async {
|
||||
obsah = [const CircularProgressIndicator()];
|
||||
switch (den.weekday) {
|
||||
case 2:
|
||||
denTydne = Languages.of(context)!.tuesday;
|
||||
break;
|
||||
case 3:
|
||||
denTydne = Languages.of(context)!.wednesday;
|
||||
break;
|
||||
case 4:
|
||||
denTydne = Languages.of(context)!.thursday;
|
||||
break;
|
||||
case 5:
|
||||
denTydne = Languages.of(context)!.friday;
|
||||
break;
|
||||
case 6:
|
||||
denTydne = Languages.of(context)!.saturday;
|
||||
break;
|
||||
case 7:
|
||||
denTydne = Languages.of(context)!.sunday;
|
||||
break;
|
||||
default:
|
||||
denTydne = Languages.of(context)!.monday;
|
||||
}
|
||||
widget.canteen.ziskejUzivatele().then((kr) {
|
||||
kredit = kr.kredit;
|
||||
widget.canteen.jidelnicekDen(den: den).then((jd) async {
|
||||
setState(() {
|
||||
obsah = [];
|
||||
if (jd.jidla.isEmpty) {
|
||||
obsah.add(Text(
|
||||
Languages.of(context)!.noFood,
|
||||
style: const TextStyle(fontSize: 15),
|
||||
));
|
||||
} else {
|
||||
for (var j in jd.jidla) {
|
||||
obsah.add(
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 15),
|
||||
child: InkWell(
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(j.varianta),
|
||||
const SizedBox(width: 10),
|
||||
Flexible(
|
||||
child: Text(
|
||||
j.nazev,
|
||||
),
|
||||
),
|
||||
Text((j.naBurze)
|
||||
? Languages.of(context)!.inExchange
|
||||
: "${j.cena} Kč"),
|
||||
Checkbox(
|
||||
value: j.objednano,
|
||||
fillColor: (j.lzeObjednat)
|
||||
? MaterialStateProperty.all(Colors.purple)
|
||||
: MaterialStateProperty.all(Colors.grey),
|
||||
onChanged: (v) async {
|
||||
if (!j.lzeObjednat) {
|
||||
showDialog(
|
||||
context: context,
|
||||