feat: pracovat na oznámení před obědem
This commit is contained in:
parent
7ec2ded7ec
commit
93ec1e852f
9 changed files with 191 additions and 63 deletions
5
.devcontainer/devcontainer.json
Normal file
5
.devcontainer/devcontainer.json
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
{
|
||||||
|
"name": "Flutter",
|
||||||
|
"image": "matspfeiffer/flutter:beta",
|
||||||
|
"extensions": ["dart-code.dart-code", "dart-code.flutter"]
|
||||||
|
}
|
|
@ -1,3 +1,6 @@
|
||||||
|
# 1.3.0
|
||||||
|
- Odstranit connectivity_plus
|
||||||
|
- Přidat možnost oznámení s info o obědu v daný čas
|
||||||
# 1.2.0
|
# 1.2.0
|
||||||
- Přidat možnost zobrazení oznámení v případě neobjednaného jídla na příští týden
|
- Přidat možnost zobrazení oznámení v případě neobjednaného jídla na příští týden
|
||||||
- Přidat oznámení o rozbitých uložených údajích
|
- Přidat oznámení o rozbitých uložených údajích
|
||||||
|
|
|
@ -145,6 +145,10 @@ abstract class Languages {
|
||||||
|
|
||||||
String get checkOrdered;
|
String get checkOrdered;
|
||||||
|
|
||||||
|
String get notifyLunch;
|
||||||
|
|
||||||
|
String get notifyAt;
|
||||||
|
|
||||||
// Offline
|
// Offline
|
||||||
String get offline;
|
String get offline;
|
||||||
|
|
||||||
|
|
|
@ -207,4 +207,11 @@ class LanguageCz extends Languages {
|
||||||
@override
|
@override
|
||||||
String get corrupted =>
|
String get corrupted =>
|
||||||
"Nastal problém s dešifrováním uložených údajů, prosím zkuste vyčistit veškerá data této aplikace.";
|
"Nastal problém s dešifrováním uložených údajů, prosím zkuste vyčistit veškerá data této aplikace.";
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get notifyAt => "Odeslat v";
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get notifyLunch =>
|
||||||
|
"V určený čas odeslat notifikaci s informacemi o obědě";
|
||||||
}
|
}
|
||||||
|
|
|
@ -206,4 +206,10 @@ class LanguageEn extends Languages {
|
||||||
@override
|
@override
|
||||||
String get corrupted =>
|
String get corrupted =>
|
||||||
"The saved credentials seem to be corrupted, please try clearing the application's data.";
|
"The saved credentials seem to be corrupted, please try clearing the application's data.";
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get notifyAt => "Send notification at";
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get notifyLunch => "Send a notification with meal info";
|
||||||
}
|
}
|
||||||
|
|
118
lib/main.dart
118
lib/main.dart
|
@ -1,18 +1,20 @@
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'package:background_fetch/background_fetch.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
|
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
|
||||||
import 'package:flutter_localizations/flutter_localizations.dart';
|
import 'package:flutter_localizations/flutter_localizations.dart';
|
||||||
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
||||||
import 'package:opencanteen/lang/lang_cz.dart';
|
import 'package:opencanteen/lang/lang_cz.dart';
|
||||||
import 'package:opencanteen/loginmanager.dart';
|
import 'package:opencanteen/loginmanager.dart';
|
||||||
import 'package:connectivity_plus/connectivity_plus.dart';
|
|
||||||
import 'package:canteenlib/canteenlib.dart';
|
import 'package:canteenlib/canteenlib.dart';
|
||||||
import 'package:opencanteen/okna/offline_jidelnicek.dart';
|
import 'package:opencanteen/okna/offline_jidelnicek.dart';
|
||||||
import 'package:opencanteen/okna/welcome.dart';
|
import 'package:opencanteen/okna/welcome.dart';
|
||||||
import 'package:opencanteen/util.dart';
|
import 'package:opencanteen/util.dart';
|
||||||
import 'package:path_provider/path_provider.dart';
|
import 'package:path_provider/path_provider.dart';
|
||||||
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
|
|
||||||
import 'lang/lang.dart';
|
import 'lang/lang.dart';
|
||||||
import 'lang/lang_en.dart';
|
import 'lang/lang_en.dart';
|
||||||
|
@ -35,14 +37,75 @@ Copyright (C) 2022 Matyáš Caras a přispěvatelé
|
||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void main() {
|
final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin =
|
||||||
|
FlutterLocalNotificationsPlugin();
|
||||||
|
|
||||||
|
// Pouze pro Android
|
||||||
|
void backgroundFetchHeadlessTask(HeadlessTask task) async {
|
||||||
|
String taskId = task.taskId;
|
||||||
|
bool isTimeout = task.timeout;
|
||||||
|
if (isTimeout) {
|
||||||
|
// Timeout
|
||||||
|
debugPrint("[BackgroundFetch] Headless task má time-out: $taskId");
|
||||||
|
BackgroundFetch.finish(taskId);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var prefs = await SharedPreferences.getInstance();
|
||||||
|
debugPrint('[BackgroundFetch] Přišel headless event.');
|
||||||
|
|
||||||
|
if (prefs.getBool("oznamit") ?? false) {
|
||||||
|
// Oznámení před obědem
|
||||||
|
if (prefs.getBool("offline") ?? false) {
|
||||||
|
// TODO možnost brát z offline dat
|
||||||
|
} else {
|
||||||
|
// bere online
|
||||||
|
var d = await LoginManager.getDetails(); // získat údaje
|
||||||
|
if (d != null) {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
BackgroundFetch.finish(taskId);
|
||||||
|
}
|
||||||
|
|
||||||
|
void main() async {
|
||||||
|
WidgetsFlutterBinding.ensureInitialized();
|
||||||
|
const AndroidInitializationSettings initializationSettingsAndroid =
|
||||||
|
AndroidInitializationSettings('notif_icon');
|
||||||
|
|
||||||
|
/// Note: permissions aren't requested here just to demonstrate that can be
|
||||||
|
/// done later
|
||||||
|
final IOSInitializationSettings initializationSettingsIOS =
|
||||||
|
IOSInitializationSettings(
|
||||||
|
requestAlertPermission: false,
|
||||||
|
requestBadgePermission: false,
|
||||||
|
requestSoundPermission: false,
|
||||||
|
onDidReceiveLocalNotification: (
|
||||||
|
int id,
|
||||||
|
String? title,
|
||||||
|
String? body,
|
||||||
|
String? payload,
|
||||||
|
) async {
|
||||||
|
debugPrint(body);
|
||||||
|
});
|
||||||
|
|
||||||
|
final InitializationSettings initializationSettings = InitializationSettings(
|
||||||
|
android: initializationSettingsAndroid,
|
||||||
|
iOS: initializationSettingsIOS,
|
||||||
|
);
|
||||||
|
await flutterLocalNotificationsPlugin.initialize(initializationSettings,
|
||||||
|
onSelectNotification: (String? payload) async {
|
||||||
|
if (payload != null) {
|
||||||
|
debugPrint('notification payload: $payload');
|
||||||
|
}
|
||||||
|
});
|
||||||
runApp(const MyApp());
|
runApp(const MyApp());
|
||||||
|
BackgroundFetch.registerHeadlessTask(backgroundFetchHeadlessTask);
|
||||||
}
|
}
|
||||||
|
|
||||||
class MyApp extends StatelessWidget {
|
class MyApp extends StatelessWidget {
|
||||||
const MyApp({Key? key}) : super(key: key);
|
const MyApp({Key? key}) : super(key: key);
|
||||||
|
|
||||||
// This widget is the root of your application.
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return MaterialApp(
|
return MaterialApp(
|
||||||
|
@ -78,22 +141,49 @@ class _LoginPageState extends State<LoginPage> {
|
||||||
TextEditingController canteenControl = TextEditingController();
|
TextEditingController canteenControl = TextEditingController();
|
||||||
bool rememberMe = false;
|
bool rememberMe = false;
|
||||||
|
|
||||||
|
void nastavitPozadi() async {
|
||||||
|
// Configure BackgroundFetch.
|
||||||
|
int status = await BackgroundFetch.configure(
|
||||||
|
BackgroundFetchConfig(
|
||||||
|
minimumFetchInterval: 15,
|
||||||
|
stopOnTerminate: false,
|
||||||
|
enableHeadless: true,
|
||||||
|
requiresBatteryNotLow: false,
|
||||||
|
requiresCharging: false,
|
||||||
|
requiresStorageNotLow: false,
|
||||||
|
requiresDeviceIdle: false,
|
||||||
|
requiredNetworkType: NetworkType.ANY), (String taskId) async {
|
||||||
|
// Callback
|
||||||
|
debugPrint("[BackgroundFetch] Event získán $taskId");
|
||||||
|
var d = await LoginManager.getDetails();
|
||||||
|
if (d != null) {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
BackgroundFetch.finish(taskId);
|
||||||
|
}, (String taskId) async {
|
||||||
|
debugPrint("[BackgroundFetch] TASK TIMEOUT taskId: $taskId");
|
||||||
|
BackgroundFetch.finish(taskId);
|
||||||
|
});
|
||||||
|
debugPrint('[BackgroundFetch] úspěšně nakonfigurováno: $status');
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
LoginManager.getDetails().then((r) async {
|
LoginManager.getDetails().then((r) async {
|
||||||
var connectivityResult = await (Connectivity().checkConnectivity());
|
if (Platform.isIOS) {
|
||||||
if (connectivityResult == ConnectivityResult.none) {
|
// žádat o oprávnění na iOS
|
||||||
ScaffoldMessenger.of(context).hideCurrentSnackBar();
|
await flutterLocalNotificationsPlugin
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
.resolvePlatformSpecificImplementation<
|
||||||
SnackBar(
|
IOSFlutterLocalNotificationsPlugin>()
|
||||||
content: Text(Languages.of(context)!.errorContacting),
|
?.requestPermissions(
|
||||||
),
|
alert: true,
|
||||||
);
|
badge: true,
|
||||||
goOffline();
|
sound: true,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (r != null) {
|
if (r != null) {
|
||||||
|
// Automaticky přihlásit
|
||||||
showDialog(
|
showDialog(
|
||||||
context: context,
|
context: context,
|
||||||
barrierDismissible: false,
|
barrierDismissible: false,
|
||||||
|
@ -123,6 +213,7 @@ class _LoginPageState extends State<LoginPage> {
|
||||||
}
|
}
|
||||||
const storage = FlutterSecureStorage();
|
const storage = FlutterSecureStorage();
|
||||||
var odsouhlasil = await storage.read(key: "oc_souhlas");
|
var odsouhlasil = await storage.read(key: "oc_souhlas");
|
||||||
|
nastavitPozadi();
|
||||||
if (odsouhlasil == null || odsouhlasil != "ano") {
|
if (odsouhlasil == null || odsouhlasil != "ano") {
|
||||||
Navigator.pushReplacement(
|
Navigator.pushReplacement(
|
||||||
context,
|
context,
|
||||||
|
@ -260,6 +351,7 @@ class _LoginPageState extends State<LoginPage> {
|
||||||
LoginManager.setDetails(userControl.text,
|
LoginManager.setDetails(userControl.text,
|
||||||
passControl.text, canteenControl.text);
|
passControl.text, canteenControl.text);
|
||||||
}
|
}
|
||||||
|
nastavitPozadi();
|
||||||
// souhlas
|
// souhlas
|
||||||
const storage = FlutterSecureStorage();
|
const storage = FlutterSecureStorage();
|
||||||
var odsouhlasil =
|
var odsouhlasil =
|
||||||
|
|
|
@ -17,6 +17,8 @@ class _NastaveniState extends State<Nastaveni> {
|
||||||
bool _ukladatOffline = false;
|
bool _ukladatOffline = false;
|
||||||
bool _preskakovatVikend = false;
|
bool _preskakovatVikend = false;
|
||||||
bool _kontrolovatTyden = false;
|
bool _kontrolovatTyden = false;
|
||||||
|
bool _oznameniObed = false;
|
||||||
|
String? _oznameniCas;
|
||||||
|
|
||||||
void najitNastaveni() async {
|
void najitNastaveni() async {
|
||||||
var preferences = await SharedPreferences.getInstance();
|
var preferences = await SharedPreferences.getInstance();
|
||||||
|
@ -24,6 +26,8 @@ class _NastaveniState extends State<Nastaveni> {
|
||||||
_ukladatOffline = preferences.getBool("offline") ?? false;
|
_ukladatOffline = preferences.getBool("offline") ?? false;
|
||||||
_preskakovatVikend = preferences.getBool("skip") ?? false;
|
_preskakovatVikend = preferences.getBool("skip") ?? false;
|
||||||
_kontrolovatTyden = preferences.getBool("tyden") ?? false;
|
_kontrolovatTyden = preferences.getBool("tyden") ?? false;
|
||||||
|
_oznameniObed = preferences.getBool("oznamit") ?? false;
|
||||||
|
_oznameniCas = preferences.getString("oznameni_cas");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,6 +95,26 @@ class _NastaveniState extends State<Nastaveni> {
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
],
|
],
|
||||||
|
),
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
Text(Languages.of(context)!.skipWeekend),
|
||||||
|
Switch(
|
||||||
|
value: _oznameniObed,
|
||||||
|
onChanged: (value) {
|
||||||
|
setState(() {
|
||||||
|
_oznameniObed = value;
|
||||||
|
zmenitNastaveni("oznamit", value);
|
||||||
|
});
|
||||||
|
})
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Text(Languages.of(context)!.notifyAt),
|
||||||
|
TimePickerDialog(
|
||||||
|
initialTime: (_oznameniCas == null)
|
||||||
|
? TimeOfDay.now()
|
||||||
|
: TimeOfDay.fromDateTime(DateTime.parse(_oznameniCas!)),
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|
84
pubspec.lock
84
pubspec.lock
|
@ -22,6 +22,13 @@ packages:
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.8.2"
|
version: "2.8.2"
|
||||||
|
background_fetch:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: background_fetch
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "1.1.0"
|
||||||
canteenlib:
|
canteenlib:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
@ -57,48 +64,6 @@ packages:
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.16.0"
|
version: "1.16.0"
|
||||||
connectivity_plus:
|
|
||||||
dependency: "direct main"
|
|
||||||
description:
|
|
||||||
name: connectivity_plus
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "2.2.1"
|
|
||||||
connectivity_plus_linux:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: connectivity_plus_linux
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "1.3.0"
|
|
||||||
connectivity_plus_macos:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: connectivity_plus_macos
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "1.2.1"
|
|
||||||
connectivity_plus_platform_interface:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: connectivity_plus_platform_interface
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "1.2.0"
|
|
||||||
connectivity_plus_web:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: connectivity_plus_web
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "1.2.0"
|
|
||||||
connectivity_plus_windows:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: connectivity_plus_windows
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "1.2.0"
|
|
||||||
crypto:
|
crypto:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -153,6 +118,27 @@ packages:
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.4"
|
version: "1.0.4"
|
||||||
|
flutter_local_notifications:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: flutter_local_notifications
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "9.5.3+1"
|
||||||
|
flutter_local_notifications_linux:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: flutter_local_notifications_linux
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "0.4.2"
|
||||||
|
flutter_local_notifications_platform_interface:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: flutter_local_notifications_platform_interface
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "5.0.0"
|
||||||
flutter_localizations:
|
flutter_localizations:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description: flutter
|
description: flutter
|
||||||
|
@ -268,13 +254,6 @@ packages:
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.7.0"
|
version: "1.7.0"
|
||||||
nm:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: nm
|
|
||||||
url: "https://pub.dartlang.org"
|
|
||||||
source: hosted
|
|
||||||
version: "0.5.0"
|
|
||||||
path:
|
path:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -441,6 +420,13 @@ packages:
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.2.0"
|
version: "1.2.0"
|
||||||
|
timezone:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: timezone
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "0.8.0"
|
||||||
typed_data:
|
typed_data:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
|
@ -17,12 +17,13 @@ dependencies:
|
||||||
flutter_localizations:
|
flutter_localizations:
|
||||||
sdk: flutter
|
sdk: flutter
|
||||||
canteenlib: ^0.1.0-alpha.16
|
canteenlib: ^0.1.0-alpha.16
|
||||||
connectivity_plus: ^2.2.1
|
|
||||||
flutter_secure_storage: ^5.0.2
|
flutter_secure_storage: ^5.0.2
|
||||||
url_launcher: ^6.0.20
|
url_launcher: ^6.0.20
|
||||||
path_provider: ^2.0.9
|
path_provider: ^2.0.9
|
||||||
shared_preferences: ^2.0.13
|
shared_preferences: ^2.0.13
|
||||||
introduction_screen: ^3.0.1
|
introduction_screen: ^3.0.1
|
||||||
|
flutter_local_notifications: ^9.5.3+1
|
||||||
|
background_fetch: ^1.1.0
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_lints: ^1.0.0
|
flutter_lints: ^1.0.0
|
||||||
|
|
Reference in a new issue