diff --git a/.metadata b/.metadata index 1634cfb..bf1f529 100644 --- a/.metadata +++ b/.metadata @@ -4,5 +4,27 @@ # This file should be version controlled and should not be manually edited. version: - revision: 3b309bda072a6b326e8aa4591a5836af600923ce - channel: beta + revision: "300451adae589accbece3490f4396f10bdf15e6e" + channel: "stable" + +project_type: app + +# Tracks metadata for the flutter migrate command +migration: + platforms: + - platform: root + create_revision: 300451adae589accbece3490f4396f10bdf15e6e + base_revision: 300451adae589accbece3490f4396f10bdf15e6e + - platform: web + create_revision: 300451adae589accbece3490f4396f10bdf15e6e + base_revision: 300451adae589accbece3490f4396f10bdf15e6e + + # 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' diff --git a/.vscode/launch.json b/.vscode/launch.json index dc01eb3..a5afaf6 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -1,14 +1,19 @@ { - "configurations": [ - { - "name": "Flutter", - "request": "launch", - "type": "dart", - "flutterMode": "debug", - "args": [ - "--flavor", - "main" - ], - } - ] + "configurations": [ + { + "name": "Flutter (Chromium)", + "type": "dart", + "request": "launch", + "program": "lib/main.dart", + "args": ["-d", "chrome", "--flavor", "main"], + "deviceId": "chrome", + }, + { + "name": "Flutter", + "request": "launch", + "type": "dart", + "flutterMode": "debug", + "args": ["--flavor", "main"] + } + ] } diff --git a/lib/components/KanbanWidget.dart b/lib/components/KanbanWidget.dart index c36e98a..680ad1e 100644 --- a/lib/components/KanbanWidget.dart +++ b/lib/components/KanbanWidget.dart @@ -7,7 +7,6 @@ import 'package:provider/provider.dart'; import '../global.dart'; import '../models/bucket.dart'; -import '../models/list.dart'; import '../models/project.dart'; import '../pages/list/list.dart'; import '../stores/project_store.dart'; diff --git a/lib/global.dart b/lib/global.dart index 006b4fc..4bcc7eb 100644 --- a/lib/global.dart +++ b/lib/global.dart @@ -1,5 +1,6 @@ import 'dart:developer' as dev; +import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_secure_storage/flutter_secure_storage.dart'; import 'package:vikunja_app/api/bucket_implementation.dart'; @@ -89,6 +90,9 @@ class VikunjaGlobalState extends State { late String currentTimeZone; void updateWorkmanagerDuration() { + if (kIsWeb) { + return; + } Workmanager().cancelAll().then((value) { settingsManager.getWorkmanagerDuration().then((duration) { if (duration.inMinutes > 0) { diff --git a/lib/main.dart b/lib/main.dart index efece9a..0073576 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,6 +1,7 @@ import 'dart:io'; import 'package:dynamic_color/dynamic_color.dart'; +import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_secure_storage/flutter_secure_storage.dart'; import 'package:permission_handler/permission_handler.dart'; @@ -34,6 +35,9 @@ class IgnoreCertHttpOverrides extends HttpOverrides { @pragma('vm:entry-point') void callbackDispatcher() { + if (kIsWeb) { + return; + } Workmanager().executeTask((task, inputData) async { print( "Native called background task: $task"); //simpleTask will be emitted here. @@ -95,18 +99,31 @@ void main() async { Permission.notification.request(); } }); - await FlutterDownloader.initialize(); - Workmanager().initialize(callbackDispatcher, isInDebugMode: false); + try { + if (!kIsWeb) { + await FlutterDownloader.initialize(); + } + } catch (e) { + print("Failed to initialize downloader: $e"); + } + try { + if (!kIsWeb) { + Workmanager().initialize(callbackDispatcher, isInDebugMode: false); + } + } catch (e) { + print("Failed to initialize workmanager: $e"); + } runApp(VikunjaGlobal( - child: new VikunjaApp( - home: HomePage(), - key: UniqueKey(), - navkey: globalNavigatorKey, - ), - login: new VikunjaApp( - home: LoginPage(), - key: UniqueKey(), - ))); + child: new VikunjaApp( + home: HomePage(), + key: UniqueKey(), + navkey: globalNavigatorKey, + ), + login: new VikunjaApp( + home: LoginPage(), + key: UniqueKey(), + ), + )); } final ValueNotifier updateTheme = ValueNotifier(false); @@ -118,38 +135,41 @@ class VikunjaApp extends StatelessWidget { const VikunjaApp({Key? key, required this.home, this.navkey}) : super(key: key); + Future getThemedata() async { + FlutterThemeMode themeMode = FlutterThemeMode.light; + try { + SettingsManager manager = SettingsManager(new FlutterSecureStorage()); + themeMode = await manager.getThemeMode(); + } catch (e) { + print("Failed to get theme mode: $e"); + } + switch (themeMode) { + case FlutterThemeMode.dark: + return buildVikunjaDarkTheme(); + case FlutterThemeMode.materialYouLight: + return buildVikunjaMaterialLightTheme(); + case FlutterThemeMode.materialYouDark: + return buildVikunjaMaterialDarkTheme(); + default: + return buildVikunjaTheme(); + } + } + @override Widget build(BuildContext context) { - SettingsManager manager = SettingsManager(new FlutterSecureStorage()); - return new ValueListenableBuilder( valueListenable: updateTheme, builder: (_, mode, __) { - updateTheme.value = false; - FlutterThemeMode themeMode = FlutterThemeMode.system; - Future theme = manager.getThemeMode().then((value) { - themeMode = value; - switch (value) { - case FlutterThemeMode.dark: - return buildVikunjaDarkTheme(); - case FlutterThemeMode.materialYouLight: - return buildVikunjaMaterialLightTheme(); - case FlutterThemeMode.materialYouDark: - return buildVikunjaMaterialDarkTheme(); - default: - return buildVikunjaTheme(); - } - }); return FutureBuilder( - future: theme, + future: getThemedata(), builder: (BuildContext context, AsyncSnapshot data) { if (data.hasData) { return new DynamicColorBuilder( builder: (lightTheme, darkTheme) { ThemeData? themeData = data.data; - if (themeMode == FlutterThemeMode.materialYouLight) + if (data.data == FlutterThemeMode.materialYouLight) themeData = themeData?.copyWith(colorScheme: lightTheme); - else if (themeMode == FlutterThemeMode.materialYouDark) + else if (data.data == FlutterThemeMode.materialYouDark) themeData = themeData?.copyWith(colorScheme: darkTheme); return MaterialApp( title: 'Vikunja', diff --git a/lib/pages/list/list_edit.dart b/lib/pages/list/list_edit.dart index 9d49eb1..0b75823 100644 --- a/lib/pages/list/list_edit.dart +++ b/lib/pages/list/list_edit.dart @@ -1,7 +1,5 @@ -import 'dart:ffi'; import 'dart:developer'; import 'package:flutter/material.dart'; -import 'package:flutter_typeahead/flutter_typeahead.dart'; import 'package:vikunja_app/global.dart'; import 'package:vikunja_app/models/list.dart'; import 'package:vikunja_app/theme/button.dart'; diff --git a/lib/pages/project/project_edit.dart b/lib/pages/project/project_edit.dart index 9341475..f2ecd12 100644 --- a/lib/pages/project/project_edit.dart +++ b/lib/pages/project/project_edit.dart @@ -1,4 +1,3 @@ -import 'dart:ffi'; import 'dart:developer'; import 'package:flutter/material.dart'; import 'package:vikunja_app/global.dart'; diff --git a/lib/pages/project/project_task_list.dart b/lib/pages/project/project_task_list.dart index ce27ebd..391f213 100644 --- a/lib/pages/project/project_task_list.dart +++ b/lib/pages/project/project_task_list.dart @@ -8,10 +8,8 @@ import 'package:vikunja_app/components/AddDialog.dart'; import 'package:vikunja_app/components/KanbanWidget.dart'; import 'package:vikunja_app/components/TaskTile.dart'; import 'package:vikunja_app/global.dart'; -import 'package:vikunja_app/models/list.dart'; import 'package:vikunja_app/models/task.dart'; import 'package:vikunja_app/models/bucket.dart'; -import 'package:vikunja_app/pages/list/list_edit.dart'; import 'package:vikunja_app/pages/list/task_edit.dart'; import 'package:vikunja_app/pages/project/project_edit.dart'; diff --git a/lib/service/services.dart b/lib/service/services.dart index 79e961e..53cb4c3 100644 --- a/lib/service/services.dart +++ b/lib/service/services.dart @@ -324,10 +324,10 @@ class SettingsManager { key: "workmanager-duration", value: duration.inMinutes.toString()); } - Future?> getPastServers() { - return _storage - .read(key: "recent-servers") - .then((value) => (jsonDecode(value!) as List).cast()); + Future?> getPastServers() async { + String jsonString = await _storage.read(key: "recent-servers") ?? "[]"; + List server = jsonDecode(jsonString); + return server.map((e) => e as String).toList(); } Future setPastServers(List? server) { diff --git a/web/favicon.png b/web/favicon.png new file mode 100644 index 0000000..8aaa46a Binary files /dev/null and b/web/favicon.png differ diff --git a/web/icons/Icon-192.png b/web/icons/Icon-192.png new file mode 100644 index 0000000..b749bfe Binary files /dev/null and b/web/icons/Icon-192.png differ diff --git a/web/icons/Icon-512.png b/web/icons/Icon-512.png new file mode 100644 index 0000000..88cfd48 Binary files /dev/null and b/web/icons/Icon-512.png differ diff --git a/web/icons/Icon-maskable-192.png b/web/icons/Icon-maskable-192.png new file mode 100644 index 0000000..eb9b4d7 Binary files /dev/null and b/web/icons/Icon-maskable-192.png differ diff --git a/web/icons/Icon-maskable-512.png b/web/icons/Icon-maskable-512.png new file mode 100644 index 0000000..d69c566 Binary files /dev/null and b/web/icons/Icon-maskable-512.png differ diff --git a/web/index.html b/web/index.html new file mode 100644 index 0000000..9a14f3d --- /dev/null +++ b/web/index.html @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + vikunja_app + + + + + + + + + + diff --git a/web/manifest.json b/web/manifest.json new file mode 100644 index 0000000..172e6eb --- /dev/null +++ b/web/manifest.json @@ -0,0 +1,35 @@ +{ + "name": "vikunja_app", + "short_name": "vikunja_app", + "start_url": ".", + "display": "standalone", + "background_color": "#0175C2", + "theme_color": "#0175C2", + "description": "A new Flutter project.", + "orientation": "portrait-primary", + "prefer_related_applications": false, + "icons": [ + { + "src": "icons/Icon-192.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "icons/Icon-512.png", + "sizes": "512x512", + "type": "image/png" + }, + { + "src": "icons/Icon-maskable-192.png", + "sizes": "192x192", + "type": "image/png", + "purpose": "maskable" + }, + { + "src": "icons/Icon-maskable-512.png", + "sizes": "512x512", + "type": "image/png", + "purpose": "maskable" + } + ] +}