diff --git a/.vscode/launch.json b/.vscode/launch.json
index dc01eb3..f923891 100644
--- a/.vscode/launch.json
+++ b/.vscode/launch.json
@@ -7,7 +7,7 @@
"flutterMode": "debug",
"args": [
"--flavor",
- "main"
+ "core"
],
}
]
diff --git a/android/app/build.gradle b/android/app/build.gradle
index 75f0c58..9cdf098 100644
--- a/android/app/build.gradle
+++ b/android/app/build.gradle
@@ -32,7 +32,7 @@ if (keystorePropertiesFile.exists()) {
}
android {
- compileSdkVersion 33
+ compileSdkVersion 34
sourceSets {
main.java.srcDirs += 'src/main/kotlin'
@@ -41,8 +41,8 @@ android {
defaultConfig {
applicationId "io.vikunja.app"
- minSdkVersion 21
- targetSdkVersion 33
+ minSdkVersion 33
+ targetSdkVersion 34
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName
diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml
index 7744c5e..fd4ace3 100644
--- a/android/app/src/main/AndroidManifest.xml
+++ b/android/app/src/main/AndroidManifest.xml
@@ -23,6 +23,7 @@
android:icon="@mipmap/ic_launcher"
android:networkSecurityConfig="@xml/network_security_config"
>
+
-
+
diff --git a/android/build.gradle b/android/build.gradle
index fbe7210..09dcd8d 100644
--- a/android/build.gradle
+++ b/android/build.gradle
@@ -1,5 +1,5 @@
buildscript {
- ext.kotlin_version = '1.7.20'
+ ext.kotlin_version = '1.9.23'
repositories {
google()
mavenCentral()
diff --git a/lib/api/client.dart b/lib/api/client.dart
index 2658470..1ec07c6 100644
--- a/lib/api/client.dart
+++ b/lib/api/client.dart
@@ -9,7 +9,6 @@ import 'package:vikunja_app/global.dart';
import '../main.dart';
-
class Client {
GlobalKey? global_scaffold_key;
final JsonDecoder _decoder = new JsonDecoder();
@@ -25,8 +24,6 @@ class Client {
String? post_body;
-
-
bool operator ==(dynamic otherClient) {
return otherClient._token == _token;
}
@@ -36,18 +33,17 @@ class Client {
configure(token: token, base: base, authenticated: authenticated);
}
- void reload_ignore_certs(bool? val) {
+ void reloadIgnoreCerts(bool? val) {
ignoreCertificates = val ?? false;
HttpOverrides.global = new IgnoreCertHttpOverrides(ignoreCertificates);
- if(global_scaffold_key == null || global_scaffold_key!.currentContext == null) return;
- VikunjaGlobal
- .of(global_scaffold_key!.currentContext!)
+ if (global_scaffold_key == null ||
+ global_scaffold_key!.currentContext == null) return;
+ VikunjaGlobal.of(global_scaffold_key!.currentContext!)
.settingsManager
.setIgnoreCertificates(ignoreCertificates);
}
- get _headers =>
- {
+ get _headers => {
'Authorization': _token != '' ? 'Bearer $_token' : '',
'Content-Type': 'application/json',
'User-Agent': 'Vikunja Mobile App'
@@ -59,20 +55,15 @@ class Client {
int get hashCode => _token.hashCode;
void configure({String? token, String? base, bool? authenticated}) {
- if (token != null)
- _token = token;
+ if (token != null) _token = token;
if (base != null) {
base = base.replaceAll(" ", "");
- if(base.endsWith("/"))
- base = base.substring(0,base.length-1);
+ if (base.endsWith("/")) base = base.substring(0, base.length - 1);
_base = base.endsWith('/api/v1') ? base : '$base/api/v1';
}
- if (authenticated != null)
- this.authenticated = authenticated;
-
+ if (authenticated != null) this.authenticated = authenticated;
}
-
void reset() {
_token = _base = '';
authenticated = false;
@@ -84,54 +75,61 @@ class Client {
// why are we doing it like this? because Uri doesnt have setters. wtf.
uri = Uri(
- scheme: uri.scheme,
+ scheme: uri.scheme,
userInfo: uri.userInfo,
host: uri.host,
port: uri.port,
path: uri.path,
//queryParameters: {...uri.queryParameters, ...?queryParameters},
queryParameters: queryParameters,
- fragment: uri.fragment
- );
+ fragment: uri.fragment);
- return http.get(uri, headers: _headers)
- .then(_handleResponse).onError((error, stackTrace) =>
- _handleError(error, stackTrace));
+ return http
+ .get(uri, headers: _headers)
+ .then(_handleResponse)
+ .onError((error, stackTrace) => _handleError(error, stackTrace));
}
Future delete(String url) {
- return http.delete(
- '${this.base}$url'.toUri()!,
- headers: _headers,
- ).then(_handleResponse).onError((error, stackTrace) =>
- _handleError(error, stackTrace));
+ return http
+ .delete(
+ '${this.base}$url'.toUri()!,
+ headers: _headers,
+ )
+ .then(_handleResponse)
+ .onError((error, stackTrace) => _handleError(error, stackTrace));
}
Future post(String url, {dynamic body}) {
- return http.post(
- '${this.base}$url'.toUri()!,
- headers: _headers,
- body: _encoder.convert(body),
- )
- .then(_handleResponse).onError((error, stackTrace) =>
- _handleError(error, stackTrace));
+ return http
+ .post(
+ '${this.base}$url'.toUri()!,
+ headers: _headers,
+ body: _encoder.convert(body),
+ )
+ .then(_handleResponse)
+ .onError((error, stackTrace) => _handleError(error, stackTrace));
}
Future put(String url, {dynamic body}) {
- return http.put(
- '${this.base}$url'.toUri()!,
- headers: _headers,
- body: _encoder.convert(body),
- )
- .then(_handleResponse).onError((error, stackTrace) =>
- _handleError(error, stackTrace));
+ return http
+ .put(
+ '${this.base}$url'.toUri()!,
+ headers: _headers,
+ body: _encoder.convert(body),
+ )
+ .then(_handleResponse)
+ .onError((error, stackTrace) => _handleError(error, stackTrace));
}
Response? _handleError(Object? e, StackTrace? st) {
- if(global_scaffold_key == null) return null;
+ if (global_scaffold_key == null) return null;
SnackBar snackBar = SnackBar(
content: Text("Error on request: " + e.toString()),
- action: SnackBarAction(label: "Clear", onPressed: () => global_scaffold_key!.currentState?.clearSnackBars()),);
+ action: SnackBarAction(
+ label: "Clear",
+ onPressed: () => global_scaffold_key!.currentState?.clearSnackBars()),
+ );
global_scaffold_key!.currentState?.showSnackBar(snackBar);
return null;
}
@@ -144,39 +142,38 @@ class Client {
return map;
}
-
Error? _handleResponseErrors(http.Response response) {
- if (response.statusCode < 200 ||
- response.statusCode >= 400) {
+ if (response.statusCode < 200 || response.statusCode >= 400) {
Map error;
error = _decoder.convert(response.body);
-
final SnackBar snackBar = SnackBar(
- content: Text(
- "Error code " + response.statusCode.toString() + " received."),
- action: globalNavigatorKey.currentContext == null ? null : SnackBarAction(
- label: ("Details"),
- onPressed: () {
- showDialog(
- context: globalNavigatorKey.currentContext!,
- builder: (BuildContext context) =>
- AlertDialog(
- title: Text("Error ${response.statusCode}"),
- content: Column(
- crossAxisAlignment: CrossAxisAlignment.start,
- mainAxisSize: MainAxisSize.min,
- children: [
- Text("Message: ${error["message"]}", textAlign: TextAlign.start,),
- Text("Url: ${response.request!.url.toString()}"),
- ],
- )
- )
- );
- },
- ),
+ content:
+ Text("Error code " + response.statusCode.toString() + " received."),
+ action: globalNavigatorKey.currentContext == null
+ ? null
+ : SnackBarAction(
+ label: ("Details"),
+ onPressed: () {
+ showDialog(
+ context: globalNavigatorKey.currentContext!,
+ builder: (BuildContext context) => AlertDialog(
+ title: Text("Error ${response.statusCode}"),
+ content: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ Text(
+ "Message: ${error["message"]}",
+ textAlign: TextAlign.start,
+ ),
+ Text("Url: ${response.request!.url.toString()}"),
+ ],
+ )));
+ },
+ ),
);
- if(global_scaffold_key != null && showSnackBar)
+ if (global_scaffold_key != null && showSnackBar)
global_scaffold_key!.currentState?.showSnackBar(snackBar);
else
print("error on request: ${error["message"]}");
diff --git a/lib/api/list_implementation.dart b/lib/api/list_implementation.dart
index 1debbbf..e55513b 100644
--- a/lib/api/list_implementation.dart
+++ b/lib/api/list_implementation.dart
@@ -8,7 +8,9 @@ import 'package:vikunja_app/service/services.dart';
class ListAPIService extends APIService implements ListService {
FlutterSecureStorage _storage;
- ListAPIService(Client client, FlutterSecureStorage storage) : _storage = storage, super(client);
+ ListAPIService(Client client, FlutterSecureStorage storage)
+ : _storage = storage,
+ super(client);
@override
Future create(namespaceId, TaskList tl) {
@@ -16,9 +18,9 @@ class ListAPIService extends APIService implements ListService {
return client
.put('/namespaces/$namespaceId/lists', body: tl.toJSON())
.then((response) {
- if (response == null) return null;
- return TaskList.fromJson(response.body);
- });
+ if (response == null) return null;
+ return TaskList.fromJson(response.body);
+ });
}
@override
@@ -32,12 +34,10 @@ class ListAPIService extends APIService implements ListService {
if (response == null) return null;
final map = response.body;
if (map.containsKey('id')) {
- return client
- .get("/lists/$listId/tasks")
- .then((tasks) {
- map['tasks'] = tasks?.body;
- return TaskList.fromJson(map);
- });
+ return client.get("/lists/$listId/tasks").then((tasks) {
+ map['tasks'] = tasks?.body;
+ return TaskList.fromJson(map);
+ });
}
return TaskList.fromJson(map);
});
@@ -45,47 +45,44 @@ class ListAPIService extends APIService implements ListService {
@override
Future?> getAll() {
- return client.get('/lists').then(
- (list) {
- if (list == null || list.statusCode != 200) return null;
- if (list.body.toString().isEmpty)
- return Future.value([]);
- print(list.statusCode);
- return convertList(list.body, (result) => TaskList.fromJson(result));});
+ return client.get('/lists').then((list) {
+ if (list == null || list.statusCode != 200) return null;
+ if (list.body.toString().isEmpty) return Future.value([]);
+ print(list.statusCode);
+ return convertList(list.body, (result) => TaskList.fromJson(result));
+ });
}
@override
Future?> getByNamespace(int namespaceId) {
// TODO there needs to be a better way for this. /namespaces/-2/lists should
// return favorite lists
- if(namespaceId == -2) {
+ if (namespaceId == -2) {
// Favourites.
return getAll().then((value) {
if (value == null) return null;
- value.removeWhere((element) => !element.isFavorite); return value;});
+ value.removeWhere((element) => !element.isFavorite);
+ return value;
+ });
}
- return client.get('/namespaces/$namespaceId/lists').then(
- (list) {
- if (list == null || list.statusCode != 200) return null;
- return convertList(list.body, (result) => TaskList.fromJson(result));
- });
+ return client.get('/namespaces/$namespaceId/lists').then((list) {
+ if (list == null || list.statusCode != 200) return null;
+ return convertList(list.body, (result) => TaskList.fromJson(result));
+ });
}
@override
Future update(TaskList tl) {
- return client
- .post('/lists/${tl.id}', body: tl.toJSON())
- .then((response) {
- if (response == null) return null;
- return TaskList.fromJson(response.body);
- });
+ return client.post('/lists/${tl.id}', body: tl.toJSON()).then((response) {
+ if (response == null) return null;
+ return TaskList.fromJson(response.body);
+ });
}
@override
Future getDisplayDoneTasks(int listId) {
- return _storage.read(key: "display_done_tasks_list_$listId").then((value)
- {
- if(value == null) {
+ return _storage.read(key: "display_done_tasks_list_$listId").then((value) {
+ if (value == null) {
// TODO: implement default value
setDisplayDoneTasks(listId, "1");
return Future.value("1");
@@ -104,7 +101,6 @@ class ListAPIService extends APIService implements ListService {
return _storage.read(key: "default_list_id");
}
- @override
void setDefaultList(int? listId) {
_storage.write(key: "default_list_id", value: listId.toString());
}
diff --git a/lib/api/project.dart b/lib/api/project.dart
index 9f2f6b4..f094965 100644
--- a/lib/api/project.dart
+++ b/lib/api/project.dart
@@ -6,7 +6,9 @@ import 'package:vikunja_app/service/services.dart';
class ProjectAPIService extends APIService implements ProjectService {
FlutterSecureStorage _storage;
- ProjectAPIService(client, storage) : _storage = storage, super(client);
+ ProjectAPIService(client, storage)
+ : _storage = storage,
+ super(client);
@override
Future create(Project p) {
@@ -47,9 +49,7 @@ class ProjectAPIService extends APIService implements ProjectService {
@override
Future update(Project p) {
- return client
- .post('/projects/${p.id}', body: p.toJSON())
- .then((response) {
+ return client.post('/projects/${p.id}', body: p.toJSON()).then((response) {
if (response == null) return null;
return Project.fromJson(response.body);
});
@@ -57,9 +57,8 @@ class ProjectAPIService extends APIService implements ProjectService {
@override
Future getDisplayDoneTasks(int listId) {
- return _storage.read(key: "display_done_tasks_list_$listId").then((value)
- {
- if(value == null) {
+ return _storage.read(key: "display_done_tasks_list_$listId").then((value) {
+ if (value == null) {
// TODO: implement default value
setDisplayDoneTasks(listId, "1");
return Future.value("1");
@@ -68,19 +67,15 @@ class ProjectAPIService extends APIService implements ProjectService {
});
}
- @override
void setDisplayDoneTasks(int listId, String value) {
_storage.write(key: "display_done_tasks_list_$listId", value: value);
}
- @override
Future getDefaultList() {
return _storage.read(key: "default_list_id");
}
- @override
void setDefaultList(int? listId) {
_storage.write(key: "default_list_id", value: listId.toString());
}
-
-}
\ No newline at end of file
+}
diff --git a/lib/components/BucketTaskCard.dart b/lib/components/BucketTaskCard.dart
index 73a371c..dfdfbd9 100644
--- a/lib/components/BucketTaskCard.dart
+++ b/lib/components/BucketTaskCard.dart
@@ -11,7 +11,7 @@ import 'package:vikunja_app/theme/constants.dart';
import '../stores/project_store.dart';
-enum DropLocation {above, below, none}
+enum DropLocation { above, below, none }
class TaskData {
final Task task;
@@ -37,7 +37,8 @@ class BucketTaskCard extends StatefulWidget {
State createState() => _BucketTaskCardState();
}
-class _BucketTaskCardState extends State with AutomaticKeepAliveClientMixin {
+class _BucketTaskCardState extends State
+ with AutomaticKeepAliveClientMixin {
Size? _cardSize;
bool _dragging = false;
DropLocation _dropLocation = DropLocation.none;
@@ -49,7 +50,8 @@ class _BucketTaskCardState extends State with AutomaticKeepAlive
if (_cardSize == null) _updateCardSize(context);
final taskState = Provider.of(context);
- final bucket = taskState.buckets[taskState.buckets.indexWhere((b) => b.id == widget.task.bucketId)];
+ final bucket = taskState.buckets[
+ taskState.buckets.indexWhere((b) => b.id == widget.task.bucketId)];
// default chip height: 32
const double chipHeight = 28;
const chipConstraints = BoxConstraints(maxHeight: chipHeight);
@@ -59,7 +61,8 @@ class _BucketTaskCardState extends State with AutomaticKeepAlive
children: [
Text(
widget.task.identifier.isNotEmpty
- ? '#${widget.task.identifier}' : '${widget.task.id}',
+ ? '#${widget.task.identifier}'
+ : '${widget.task.id}',
style: (theme.textTheme.titleSmall ?? TextStyle()).copyWith(
color: Colors.grey,
),
@@ -67,21 +70,25 @@ class _BucketTaskCardState extends State with AutomaticKeepAlive
],
);
if (widget.task.done) {
- identifierRow.children.insert(0, Container(
- constraints: chipConstraints,
- padding: EdgeInsets.only(right: 4),
- child: FittedBox(
- child: Chip(
- label: Text('Done'),
- labelStyle: (theme.textTheme.labelLarge ?? TextStyle()).copyWith(
- fontWeight: FontWeight.bold,
- color: theme.brightness == Brightness.dark
- ? Colors.black : Colors.white,
+ identifierRow.children.insert(
+ 0,
+ Container(
+ constraints: chipConstraints,
+ padding: EdgeInsets.only(right: 4),
+ child: FittedBox(
+ child: Chip(
+ label: Text('Done'),
+ labelStyle:
+ (theme.textTheme.labelLarge ?? TextStyle()).copyWith(
+ fontWeight: FontWeight.bold,
+ color: theme.brightness == Brightness.dark
+ ? Colors.black
+ : Colors.white,
+ ),
+ backgroundColor: vGreen,
+ ),
),
- backgroundColor: vGreen,
- ),
- ),
- ));
+ ));
}
final titleRow = Row(
@@ -89,9 +96,11 @@ class _BucketTaskCardState extends State with AutomaticKeepAlive
Expanded(
child: Text(
widget.task.title,
- style: (theme.textTheme.titleMedium ?? TextStyle(fontSize: 16)).copyWith(
+ style: (theme.textTheme.titleMedium ?? TextStyle(fontSize: 16))
+ .copyWith(
color: theme.brightness == Brightness.dark
- ? Colors.white : Colors.black,
+ ? Colors.white
+ : Colors.black,
),
),
),
@@ -145,10 +154,10 @@ class _BucketTaskCardState extends State with AutomaticKeepAlive
backgroundColor: Colors.grey,
),
),
- label: Text(
- (checkboxStatistics.checked == checkboxStatistics.total ? '' : '${checkboxStatistics.checked} of ')
- + '${checkboxStatistics.total} tasks'
- ),
+ label: Text((checkboxStatistics.checked == checkboxStatistics.total
+ ? ''
+ : '${checkboxStatistics.checked} of ') +
+ '${checkboxStatistics.total} tasks'),
));
}
if (widget.task.attachments.isNotEmpty) {
@@ -185,7 +194,8 @@ class _BucketTaskCardState extends State with AutomaticKeepAlive
child: identifierRow,
),
Padding(
- padding: EdgeInsets.only(top: 4, bottom: labelRow.children.isNotEmpty ? 8 : 0),
+ padding: EdgeInsets.only(
+ top: 4, bottom: labelRow.children.isNotEmpty ? 8 : 0),
child: Container(
constraints: rowConstraints,
child: titleRow,
@@ -213,7 +223,9 @@ class _BucketTaskCardState extends State with AutomaticKeepAlive
return LongPressDraggable(
data: TaskData(widget.task, _cardSize),
- maxSimultaneousDrags: taskState.taskDragging ? 0 : 1, // only one task can be dragged at a time
+ maxSimultaneousDrags: taskState.taskDragging
+ ? 0
+ : 1, // only one task can be dragged at a time
onDragStarted: () {
taskState.taskDragging = true;
setState(() => _dragging = true);
@@ -223,14 +235,16 @@ class _BucketTaskCardState extends State with AutomaticKeepAlive
taskState.taskDragging = false;
setState(() => _dragging = false);
},
- feedback: (_cardSize == null) ? SizedBox.shrink() : SizedBox.fromSize(
- size: _cardSize,
- child: Card(
- color: card.color,
- child: (card.child as InkWell).child,
- elevation: (card.elevation ?? 0) + 5,
- ),
- ),
+ feedback: (_cardSize == null)
+ ? SizedBox.shrink()
+ : SizedBox.fromSize(
+ size: _cardSize,
+ child: Card(
+ color: card.color,
+ child: (card.child as InkWell).child,
+ elevation: (card.elevation ?? 0) + 5,
+ ),
+ ),
childWhenDragging: SizedBox.shrink(),
child: () {
if (_dragging || _cardSize == null) return card;
@@ -241,25 +255,30 @@ class _BucketTaskCardState extends State with AutomaticKeepAlive
color: Colors.grey,
child: SizedBox.fromSize(size: dropBoxSize),
);
- final dropAbove = taskState.taskDragging && _dropLocation == DropLocation.above;
- final dropBelow = taskState.taskDragging && _dropLocation == DropLocation.below;
- final DragTargetLeave dragTargetOnLeave = (data) => setState(() {
- _dropLocation = DropLocation.none;
- _dropData = null;
- });
- final dragTargetOnWillAccept = (TaskData data, DropLocation dropLocation) {
- if (data.task.bucketId != bucket.id)
- if (bucket.limit != 0 && bucket.tasks.length >= bucket.limit)
- return false;
+ final dropAbove =
+ taskState.taskDragging && _dropLocation == DropLocation.above;
+ final dropBelow =
+ taskState.taskDragging && _dropLocation == DropLocation.below;
+ final DragTargetLeave dragTargetOnLeave =
+ (data) => setState(() {
+ _dropLocation = DropLocation.none;
+ _dropData = null;
+ });
+ final dragTargetOnWillAccept =
+ (TaskData data, DropLocation dropLocation) {
+ if (data.task.bucketId != bucket.id) if (bucket.limit != 0 &&
+ bucket.tasks.length >= bucket.limit) return false;
setState(() {
_dropLocation = dropLocation;
_dropData = data;
});
return true;
};
- final DragTargetAccept dragTargetOnAccept = (data) {
+ final DragTargetAccept> dragTargetOnAccept =
+ (data) {
final index = bucket.tasks.indexOf(widget.task);
- widget.onAccept(data.task, _dropLocation == DropLocation.above ? index : index + 1);
+ widget.onAccept(data.data.task,
+ _dropLocation == DropLocation.above ? index : index + 1);
setState(() {
_dropLocation = DropLocation.none;
_dropData = null;
@@ -268,7 +287,8 @@ class _BucketTaskCardState extends State with AutomaticKeepAlive
return SizedBox(
width: cardSize.width,
- height: cardSize.height + (dropAbove || dropBelow ? dropBoxSize.height + 4 : 0),
+ height: cardSize.height +
+ (dropAbove || dropBelow ? dropBoxSize.height + 4 : 0),
child: Stack(
children: [
Column(
@@ -281,18 +301,22 @@ class _BucketTaskCardState extends State with AutomaticKeepAlive
Column(
children: [
SizedBox(
- height: (cardSize.height / 2) + (dropAbove ? dropBoxSize.height : 0),
+ height: (cardSize.height / 2) +
+ (dropAbove ? dropBoxSize.height : 0),
child: DragTarget(
- onWillAcceptWithDetails: (data) => dragTargetOnWillAccept(data, DropLocation.above),
+ onWillAcceptWithDetails: (data) =>
+ dragTargetOnWillAccept(data.data, DropLocation.above),
onAcceptWithDetails: dragTargetOnAccept,
onLeave: dragTargetOnLeave,
builder: (_, __, ___) => SizedBox.expand(),
),
),
SizedBox(
- height: (cardSize.height / 2) + (dropBelow ? dropBoxSize.height : 0),
+ height: (cardSize.height / 2) +
+ (dropBelow ? dropBoxSize.height : 0),
child: DragTarget(
- onWillAcceptWithDetails: (data) => dragTargetOnWillAccept(data, DropLocation.below),
+ onWillAcceptWithDetails: (data) =>
+ dragTargetOnWillAccept(data.data, DropLocation.below),
onAcceptWithDetails: dragTargetOnAccept,
onLeave: dragTargetOnLeave,
builder: (_, __, ___) => SizedBox.expand(),
@@ -309,12 +333,13 @@ class _BucketTaskCardState extends State with AutomaticKeepAlive
void _updateCardSize(BuildContext context) {
SchedulerBinding.instance.addPostFrameCallback((_) {
- if (mounted) setState(() {
- _cardSize = context.size;
- });
+ if (mounted)
+ setState(() {
+ _cardSize = context.size;
+ });
});
}
@override
bool get wantKeepAlive => _dragging;
-}
\ No newline at end of file
+}
diff --git a/lib/components/KanbanWidget.dart b/lib/components/KanbanWidget.dart
index 287031b..fbbff7e 100644
--- a/lib/components/KanbanWidget.dart
+++ b/lib/components/KanbanWidget.dart
@@ -25,23 +25,22 @@ class KanbanClass {
Function _onViewTapped, _addItemDialog, notify;
Duration _lastTaskDragUpdateAction = Duration.zero;
-
Project _list;
Map _bucketProps = {};
-
- KanbanClass(this.context, this.notify, this._onViewTapped, this._addItemDialog, this._list) {
+ KanbanClass(this.context, this.notify, this._onViewTapped,
+ this._addItemDialog, this._list) {
taskState = Provider.of(context);
}
-
Widget kanbanView() {
final deviceData = MediaQuery.of(context);
final portrait = deviceData.orientation == Orientation.portrait;
final bucketFraction = portrait ? 0.8 : 0.4;
final bucketWidth = deviceData.size.width * bucketFraction;
- if (_pageController == null || _pageController!.viewportFraction != bucketFraction)
+ if (_pageController == null ||
+ _pageController!.viewportFraction != bucketFraction)
_pageController = PageController(viewportFraction: bucketFraction);
print(_list.doneBucketId);
@@ -170,14 +169,16 @@ class KanbanClass {
),
));
}
+
Future _setDoneBucket(BuildContext context, int bucketId) async {
//setState(() {});
- _list = (await VikunjaGlobal.of(context).projectService.update(_list.copyWith(doneBucketId: bucketId)))!;
+ _list = (await VikunjaGlobal.of(context)
+ .projectService
+ .update(_list.copyWith(doneBucketId: bucketId)))!;
notify();
}
- Future _addBucket(
- String title, BuildContext context) async {
+ Future _addBucket(String title, BuildContext context) async {
final currentUser = VikunjaGlobal.of(context).currentUser;
if (currentUser == null) {
return;
@@ -256,14 +257,12 @@ class KanbanClass {
SchedulerBinding.instance.addPostFrameCallback((_) {
if (_bucketProps[bucket.id]!.controller.hasClients)
//setState(() {
- _bucketProps[bucket.id]!.bucketLength = bucket.tasks.length;
- _bucketProps[bucket.id]!.scrollable =
- _bucketProps[bucket.id]!.controller.position.maxScrollExtent >
- 0;
- _bucketProps[bucket.id]!.portrait = portrait;
- //});
+ _bucketProps[bucket.id]!.bucketLength = bucket.tasks.length;
+ _bucketProps[bucket.id]!.scrollable =
+ _bucketProps[bucket.id]!.controller.position.maxScrollExtent > 0;
+ _bucketProps[bucket.id]!.portrait = portrait;
+ //});
notify();
-
});
if (_bucketProps[bucket.id]!.titleController.text.isEmpty)
_bucketProps[bucket.id]!.titleController.text = bucket.title;
@@ -427,10 +426,11 @@ class KanbanClass {
final screenSize = MediaQuery.of(context).size;
const scrollDuration = Duration(milliseconds: 250);
const scrollCurve = Curves.easeInOut;
- final updateAction = () { //setState(() =>
+ final updateAction = () {
+ //setState(() =>
_lastTaskDragUpdateAction = details.sourceTimeStamp!;
notify();
- };//);
+ }; //);
if (details.globalPosition.dx < screenSize.width * 0.1) {
// scroll left
@@ -502,8 +502,8 @@ class KanbanClass {
if (bucket.tasks.length == 0)
DragTarget(
onWillAcceptWithDetails: (data) {
- /*setState(() =>*/ _bucketProps[bucket.id]!.taskDropSize =
- data.size;//);
+ /*setState(() =>*/ _bucketProps[bucket.id]!
+ .taskDropSize = data.data.size; //);
notify();
return true;
},
@@ -511,23 +511,23 @@ class KanbanClass {
Provider.of(context, listen: false)
.moveTaskToBucket(
context: context,
- task: data.task,
+ task: data.data.task,
newBucketId: bucket.id,
index: 0,
)
.then((_) => ScaffoldMessenger.of(context)
.showSnackBar(SnackBar(
content: Text(
- '\'${data.task.title}\' was moved to \'${bucket.title}\' successfully!'),
+ '\'${data.data.task.title}\' was moved to \'${bucket.title}\' successfully!'),
)));
//setState(() =>
- _bucketProps[bucket.id]!.taskDropSize = null;//);
+ _bucketProps[bucket.id]!.taskDropSize = null; //);
notify();
},
onLeave: (_) {
//setState(() =>
- _bucketProps[bucket.id]!.taskDropSize = null;//)
+ _bucketProps[bucket.id]!.taskDropSize = null; //)
notify();
},
builder: (_, __, ___) => SizedBox.expand(),
@@ -548,12 +548,7 @@ class KanbanClass {
}
Future loadBucketsForPage(int page) {
- return Provider.of(context, listen: false).loadBuckets(
- context: context,
- listId: _list.id,
- page: page
- );
+ return Provider.of(context, listen: false)
+ .loadBuckets(context: context, listId: _list.id, page: page);
}
-
-
}
diff --git a/lib/global.dart b/lib/global.dart
index 5cf490c..006b4fc 100644
--- a/lib/global.dart
+++ b/lib/global.dart
@@ -23,7 +23,6 @@ import 'package:workmanager/workmanager.dart';
import 'api/project.dart';
import 'main.dart';
-
class VikunjaGlobal extends StatefulWidget {
final Widget child;
final Widget login;
@@ -50,7 +49,6 @@ class VikunjaGlobalState extends State {
UserService? _newUserService;
NotificationClass _notificationClass = NotificationClass();
-
User? get currentUser => _currentUser;
Client get client => _client;
@@ -81,7 +79,6 @@ class VikunjaGlobalState extends State {
NotificationClass get notifications => _notificationClass;
-
LabelService get labelService => new LabelAPIService(client);
LabelTaskService get labelTaskService => new LabelTaskAPIService(client);
@@ -89,21 +86,25 @@ class VikunjaGlobalState extends State {
LabelTaskBulkAPIService get labelTaskBulkService =>
new LabelTaskBulkAPIService(client);
-
late String currentTimeZone;
void updateWorkmanagerDuration() {
Workmanager().cancelAll().then((value) {
- settingsManager.getWorkmanagerDuration().then((duration)
- {
- if(duration.inMinutes > 0) {
- Workmanager().registerPeriodicTask(
- "update-tasks", "update-tasks", frequency: duration, constraints: Constraints(networkType: NetworkType.connected),
- initialDelay: Duration(seconds: 15), inputData: {"client_token": client.token, "client_base": client.base});
+ settingsManager.getWorkmanagerDuration().then((duration) {
+ if (duration.inMinutes > 0) {
+ Workmanager().registerPeriodicTask("update-tasks", "update-tasks",
+ frequency: duration,
+ constraints: Constraints(networkType: NetworkType.connected),
+ initialDelay: Duration(seconds: 15),
+ inputData: {
+ "client_token": client.token,
+ "client_base": client.base
+ });
}
- Workmanager().registerPeriodicTask(
- "refresh-token", "refresh-token", frequency: Duration(hours: 12), constraints: Constraints(networkType: NetworkType.connected),
+ Workmanager().registerPeriodicTask("refresh-token", "refresh-token",
+ frequency: Duration(hours: 12),
+ constraints: Constraints(networkType: NetworkType.connected),
initialDelay: Duration(seconds: 15));
});
});
@@ -113,13 +114,15 @@ class VikunjaGlobalState extends State {
void initState() {
super.initState();
_client = Client(snackbarKey);
- settingsManager.getIgnoreCertificates().then((value) => client.reload_ignore_certs(value == "1"));
+ settingsManager
+ .getIgnoreCertificates()
+ .then((value) => client.reloadIgnoreCerts(value == "1"));
_newUserService = UserAPIService(client);
_loadCurrentUser();
tz.initializeTimeZones();
notifications.notificationInitializer();
settingsManager.getVersionNotifications().then((value) {
- if(value == "1") {
+ if (value == "1") {
versionChecker.postVersionCheckSnackbar();
}
});
@@ -152,17 +155,16 @@ class VikunjaGlobalState extends State {
});
}
-
void logoutUser(BuildContext context) async {
// _storage.deleteAll().then((_) {
- var userId = await _storage.read(key: "currentUser");
- await _storage.delete(key: userId!); //delete token
- await _storage.delete(key: "${userId}_base");
- setState(() {
- client.reset();
- _currentUser = null;
- });
- /* }).catchError((err) {
+ var userId = await _storage.read(key: "currentUser");
+ await _storage.delete(key: userId!); //delete token
+ await _storage.delete(key: "${userId}_base");
+ setState(() {
+ client.reset();
+ _currentUser = null;
+ });
+ /* }).catchError((err) {
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Text('An error occurred while logging out!'),
));
@@ -191,13 +193,12 @@ class VikunjaGlobalState extends State {
loadedCurrentUser = await UserAPIService(client).getCurrentUser();
// load new token from server to avoid expiration
String? newToken = await newUserService?.getToken();
- if(newToken != null) {
+ if (newToken != null) {
_storage.write(key: currentUser, value: newToken);
client.configure(token: newToken);
}
-
} on ApiException catch (e) {
- dev.log("Error code: " + e.errorCode.toString(),level: 1000);
+ dev.log("Error code: " + e.errorCode.toString(), level: 1000);
if (e.errorCode ~/ 100 == 4) {
client.authenticated = false;
if (e.errorCode == 401) {
@@ -227,7 +228,7 @@ class VikunjaGlobalState extends State {
if (_loading) {
return new Center(child: new CircularProgressIndicator());
}
- if(client.authenticated) {
+ if (client.authenticated) {
notifications.scheduleDueNotifications(taskService);
}
return new VikunjaGlobalInherited(
diff --git a/lib/main.dart b/lib/main.dart
index b0ae919..efece9a 100644
--- a/lib/main.dart
+++ b/lib/main.dart
@@ -35,7 +35,8 @@ class IgnoreCertHttpOverrides extends HttpOverrides {
@pragma('vm:entry-point')
void callbackDispatcher() {
Workmanager().executeTask((task, inputData) async {
- print("Native called background task: $task"); //simpleTask will be emitted here.
+ print(
+ "Native called background task: $task"); //simpleTask will be emitted here.
if (task == "update-tasks" && inputData != null) {
Client client = Client(null,
token: inputData["client_token"],
@@ -47,7 +48,7 @@ void callbackDispatcher() {
.getIgnoreCertificates()
.then((value) async {
print("ignoring: $value");
- client.reload_ignore_certs(value == "1");
+ client.reloadIgnoreCerts(value == "1");
TaskAPIService taskService = TaskAPIService(client);
NotificationClass nc = NotificationClass();
@@ -56,7 +57,7 @@ void callbackDispatcher() {
.scheduleDueNotifications(taskService)
.then((value) => Future.value(true));
});
- } else if( task == "refresh-token") {
+ } else if (task == "refresh-token") {
print("running refresh from workmanager");
final FlutterSecureStorage _storage = new FlutterSecureStorage();
@@ -66,25 +67,24 @@ void callbackDispatcher() {
}
var token = await _storage.read(key: currentUser);
-
var base = await _storage.read(key: '${currentUser}_base');
if (token == null || base == null) {
return Future.value(true);
}
Client client = Client(null);
client.configure(token: token, base: base, authenticated: true);
- // load new token from server to avoid expiration
- String? newToken = await UserAPIService(client).getToken();
- if(newToken != null) {
- _storage.write(key: currentUser, value: newToken);
- }
+ // load new token from server to avoid expiration
+ String? newToken = await UserAPIService(client).getToken();
+ if (newToken != null) {
+ _storage.write(key: currentUser, value: newToken);
+ }
return Future.value(true);
-
} else {
return Future.value(true);
}
});
}
+
final globalSnackbarKey = GlobalKey();
final globalNavigatorKey = GlobalKey();
@@ -108,60 +108,62 @@ void main() async {
key: UniqueKey(),
)));
}
+
final ValueNotifier updateTheme = ValueNotifier(false);
class VikunjaApp extends StatelessWidget {
final Widget home;
final GlobalKey? navkey;
- const VikunjaApp({Key? key, required this.home, this.navkey}) : super(key: key);
+ const VikunjaApp({Key? key, required this.home, this.navkey})
+ : super(key: key);
@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,
- builder: (BuildContext context, AsyncSnapshot data) {
- if(data.hasData) {
- return new DynamicColorBuilder(builder: (lightTheme, darkTheme)
- {
- ThemeData? themeData = data.data;
- if(themeMode == FlutterThemeMode.materialYouLight)
- themeData = themeData?.copyWith(colorScheme: lightTheme);
- else if(themeMode == FlutterThemeMode.materialYouDark)
- themeData = themeData?.copyWith(colorScheme: darkTheme);
- return MaterialApp(
- title: 'Vikunja',
- theme: themeData,
- scaffoldMessengerKey: globalSnackbarKey,
- navigatorKey: navkey,
- // <= this
- home: this.home,
- );
- });
- } else {
- return Center(child: CircularProgressIndicator());
- }
- });});
+ 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,
+ builder: (BuildContext context, AsyncSnapshot data) {
+ if (data.hasData) {
+ return new DynamicColorBuilder(
+ builder: (lightTheme, darkTheme) {
+ ThemeData? themeData = data.data;
+ if (themeMode == FlutterThemeMode.materialYouLight)
+ themeData = themeData?.copyWith(colorScheme: lightTheme);
+ else if (themeMode == FlutterThemeMode.materialYouDark)
+ themeData = themeData?.copyWith(colorScheme: darkTheme);
+ return MaterialApp(
+ title: 'Vikunja',
+ theme: themeData,
+ scaffoldMessengerKey: globalSnackbarKey,
+ navigatorKey: navkey,
+ // <= this
+ home: this.home,
+ );
+ });
+ } else {
+ return Center(child: CircularProgressIndicator());
+ }
+ });
+ });
}
}
diff --git a/lib/managers/notifications.dart b/lib/managers/notifications.dart
index 973ca89..2b96f18 100644
--- a/lib/managers/notifications.dart
+++ b/lib/managers/notifications.dart
@@ -5,7 +5,8 @@ import 'dart:math';
import 'package:flutter_timezone/flutter_timezone.dart';
import 'package:timezone/timezone.dart' as tz;
-import 'package:flutter_local_notifications/flutter_local_notifications.dart'as notifs;
+import 'package:flutter_local_notifications/flutter_local_notifications.dart'
+ as notifs;
import 'package:rxdart/subjects.dart' as rxSub;
import 'package:vikunja_app/service/services.dart';
@@ -19,62 +20,58 @@ class NotificationClass {
late String currentTimeZone;
notifs.NotificationAppLaunchDetails? notifLaunch;
- notifs.FlutterLocalNotificationsPlugin get notificationsPlugin => new notifs.FlutterLocalNotificationsPlugin();
-
+ notifs.FlutterLocalNotificationsPlugin get notificationsPlugin =>
+ new notifs.FlutterLocalNotificationsPlugin();
var androidSpecificsDueDate = notifs.AndroidNotificationDetails(
- "Vikunja1",
- "Due Date Notifications",
+ "Vikunja1", "Due Date Notifications",
channelDescription: "description",
icon: 'vikunja_notification_logo',
- importance: notifs.Importance.high
- );
+ importance: notifs.Importance.high);
var androidSpecificsReminders = notifs.AndroidNotificationDetails(
- "Vikunja2",
- "Reminder Notifications",
+ "Vikunja2", "Reminder Notifications",
channelDescription: "description",
icon: 'vikunja_notification_logo',
- importance: notifs.Importance.high
- );
- late notifs.IOSNotificationDetails iOSSpecifics;
+ importance: notifs.Importance.high);
+ late notifs.DarwinNotificationDetails iOSSpecifics;
late notifs.NotificationDetails platformChannelSpecificsDueDate;
late notifs.NotificationDetails platformChannelSpecificsReminders;
NotificationClass({this.id, this.body, this.payload, this.title});
- final rxSub.BehaviorSubject<
- NotificationClass> didReceiveLocalNotificationSubject =
- rxSub.BehaviorSubject();
+ final rxSub.BehaviorSubject
+ didReceiveLocalNotificationSubject =
+ rxSub.BehaviorSubject();
final rxSub.BehaviorSubject selectNotificationSubject =
- rxSub.BehaviorSubject();
+ rxSub.BehaviorSubject();
Future _initNotifications() async {
var initializationSettingsAndroid =
- notifs.AndroidInitializationSettings('vikunja_logo');
- var initializationSettingsIOS = notifs.IOSInitializationSettings(
+ notifs.AndroidInitializationSettings('vikunja_logo');
+ var initializationSettingsIOS = notifs.DarwinInitializationSettings(
requestAlertPermission: false,
requestBadgePermission: false,
requestSoundPermission: false,
onDidReceiveLocalNotification:
(int? id, String? title, String? body, String? payload) async {
- didReceiveLocalNotificationSubject
- .add(NotificationClass(
+ didReceiveLocalNotificationSubject.add(NotificationClass(
id: id, title: title, body: body, payload: payload));
});
var initializationSettings = notifs.InitializationSettings(
android: initializationSettingsAndroid, iOS: initializationSettingsIOS);
await notificationsPlugin.initialize(initializationSettings,
- onSelectNotification: (String? payload) async {
- if (payload != null) {
- print('notification payload: ' + payload);
- selectNotificationSubject.add(payload);
- }
- });
+ onDidReceiveNotificationResponse:
+ (notifs.NotificationResponse resp) async {
+ if (payload != null) {
+ print('notification payload: ' + resp.payload!);
+ selectNotificationSubject.add(resp.payload!);
+ }
+ });
print("Notifications initialised successfully");
}
Future notificationInitializer() async {
- iOSSpecifics = notifs.IOSNotificationDetails();
+ iOSSpecifics = notifs.DarwinNotificationDetails();
platformChannelSpecificsDueDate = notifs.NotificationDetails(
android: androidSpecificsDueDate, iOS: iOSSpecifics);
platformChannelSpecificsReminders = notifs.NotificationDetails(
@@ -86,20 +83,23 @@ class NotificationClass {
return Future.value();
}
- Future scheduleNotification(String title, String description,
+ Future scheduleNotification(
+ String title,
+ String description,
notifs.FlutterLocalNotificationsPlugin notifsPlugin,
- DateTime scheduledTime, String currentTimeZone,
- notifs.NotificationDetails platformChannelSpecifics, {int? id}) async {
- if (id == null)
- id = Random().nextInt(1000000);
+ DateTime scheduledTime,
+ String currentTimeZone,
+ notifs.NotificationDetails platformChannelSpecifics,
+ {int? id}) async {
+ if (id == null) id = Random().nextInt(1000000);
// TODO: move to setup
- tz.TZDateTime time = tz.TZDateTime.from(
- scheduledTime, tz.getLocation(currentTimeZone));
+ tz.TZDateTime time =
+ tz.TZDateTime.from(scheduledTime, tz.getLocation(currentTimeZone));
if (time.difference(tz.TZDateTime.now(tz.getLocation(currentTimeZone))) <
- Duration.zero)
- return;
- await notifsPlugin.zonedSchedule(id, title, description,
- time, platformChannelSpecifics, androidAllowWhileIdle: true,
+ Duration.zero) return;
+ await notifsPlugin.zonedSchedule(
+ id, title, description, time, platformChannelSpecifics,
+ androidAllowWhileIdle: true,
uiLocalNotificationDateInterpretation: notifs
.UILocalNotificationDateInterpretation
.wallClockTime); // This literally schedules the notification
@@ -110,30 +110,27 @@ class NotificationClass {
"This is a test notification", platformChannelSpecificsReminders);
}
-
void requestIOSPermissions() {
- notificationsPlugin.resolvePlatformSpecificImplementation<
- notifs.IOSFlutterLocalNotificationsPlugin>()
+ notificationsPlugin
+ .resolvePlatformSpecificImplementation<
+ notifs.IOSFlutterLocalNotificationsPlugin>()
?.requestPermissions(
- alert: true,
- badge: true,
- sound: true,
- );
+ alert: true,
+ badge: true,
+ sound: true,
+ );
}
-
Future scheduleDueNotifications(TaskService taskService,
{List? tasks}) async {
- if (tasks == null)
- tasks = await taskService.getAll();
+ if (tasks == null) tasks = await taskService.getAll();
if (tasks == null) {
print("did not receive tasks on notification update");
return;
}
await notificationsPlugin.cancelAll();
for (final task in tasks) {
- if(task.done)
- continue;
+ if (task.done) continue;
for (final reminder in task.reminderDates) {
scheduleNotification(
"Reminder",
@@ -159,5 +156,4 @@ class NotificationClass {
}
print("notifications scheduled successfully");
}
-
-}
\ No newline at end of file
+}
diff --git a/lib/pages/landing_page.dart b/lib/pages/landing_page.dart
index a627f39..72471fd 100644
--- a/lib/pages/landing_page.dart
+++ b/lib/pages/landing_page.dart
@@ -37,11 +37,11 @@ class LandingPageState extends State
static const platform = const MethodChannel('vikunja');
Future _updateDefaultList() async {
-
- return VikunjaGlobal.of(context).newUserService?.getCurrentUser().then((value) =>
- setState(() {
- defaultList = value?.settings?.default_project_id;
- } ),);
+ return VikunjaGlobal.of(context).newUserService?.getCurrentUser().then(
+ (value) => setState(() {
+ defaultList = value?.settings?.default_project_id;
+ }),
+ );
}
@override
@@ -55,7 +55,10 @@ class LandingPageState extends State
} catch (e) {
log(e.toString());
}
- VikunjaGlobal.of(context).settingsManager.getLandingPageOnlyDueDateTasks().then((value) => onlyDueDate = value);
+ VikunjaGlobal.of(context)
+ .settingsManager
+ .getLandingPageOnlyDueDateTasks()
+ .then((value) => onlyDueDate = value);
}));
super.initState();
}
@@ -133,26 +136,29 @@ class LandingPageState extends State
PopupMenuButton(itemBuilder: (BuildContext context) {
return [
PopupMenuItem(
- child:
- InkWell(
- onTap: () {
- Navigator.pop(context);
- bool newval = !onlyDueDate;
- VikunjaGlobal.of(context).settingsManager.setLandingPageOnlyDueDateTasks(newval).then((value) {
- setState(() {
- onlyDueDate = newval;
- _loadList(context);
- });
- });
- },
- child:
- Row(mainAxisAlignment: MainAxisAlignment.end, children: [
- Text("Only show tasks with due date"),
- Checkbox(
- value: onlyDueDate,
- onChanged: (bool? value) { },
- )
- ])))
+ child: InkWell(
+ onTap: () {
+ Navigator.pop(context);
+ bool newval = !onlyDueDate;
+ VikunjaGlobal.of(context)
+ .settingsManager
+ .setLandingPageOnlyDueDateTasks(newval)
+ .then((value) {
+ setState(() {
+ onlyDueDate = newval;
+ _loadList(context);
+ });
+ });
+ },
+ child: Row(
+ mainAxisAlignment: MainAxisAlignment.end,
+ children: [
+ Text("Only show tasks with due date"),
+ Checkbox(
+ value: onlyDueDate,
+ onChanged: (bool? value) {},
+ )
+ ])))
];
}),
],
@@ -226,41 +232,46 @@ class LandingPageState extends State
.settingsManager
.getLandingPageOnlyDueDateTasks()
.then((showOnlyDueDateTasks) {
+ VikunjaGlobalState global = VikunjaGlobal.of(context);
+ Map? frontend_settings =
+ global.currentUser?.settings?.frontend_settings;
+ int? filterId = 0;
+ if (frontend_settings != null) {
+ if (frontend_settings["filter_id_used_on_overview"] != null)
+ filterId = frontend_settings["filter_id_used_on_overview"];
+ }
+ if (filterId != null && filterId != 0) {
+ return global.taskService.getAllByProject(filterId, {
+ "sort_by": ["due_date", "id"],
+ "order_by": ["asc", "desc"],
+ }).then?>((response) =>
+ _handleTaskList(response?.body, showOnlyDueDateTasks));
+ }
- VikunjaGlobalState global = VikunjaGlobal.of(context);
- Map? frontend_settings = global.currentUser?.settings?.frontend_settings;
- int? filterId = 0;
- if(frontend_settings != null) {
- if(frontend_settings["filter_id_used_on_overview"] != null)
- filterId = frontend_settings["filter_id_used_on_overview"];
- }
- if(filterId != null && filterId != 0) {
- return global.taskService.getAllByProject(filterId, {
- "sort_by": ["due_date", "id"],
- "order_by": ["asc", "desc"],
- }).then?>((response) => _handleTaskList(response?.body, showOnlyDueDateTasks));;
- }
-
- return global.taskService
- .getByOptions(TaskServiceOptions(
- newOptions: [
- TaskServiceOption("sort_by", ["due_date", "id"]),
- TaskServiceOption("order_by", ["asc", "desc"]),
- TaskServiceOption("filter_by", "done"),
- TaskServiceOption("filter_value", "false"),
- TaskServiceOption("filter_comparator", "equals"),
- TaskServiceOption("filter_concat", "and"),
- ],
- clearOther: true
- ))
- .then?>((taskList) => _handleTaskList(taskList, showOnlyDueDateTasks));
-
- });//.onError((error, stackTrace) {print("error");});
+ return global.taskService
+ .getByOptions(TaskServiceOptions(newOptions: [
+ TaskServiceOption(
+ "sort_by", ["due_date", "id"]),
+ TaskServiceOption(
+ "order_by", ["asc", "desc"]),
+ TaskServiceOption("filter_by", "done"),
+ TaskServiceOption(
+ "filter_value", "false"),
+ TaskServiceOption(
+ "filter_comparator", "equals"),
+ TaskServiceOption(
+ "filter_concat", "and"),
+ ], clearOther: true))
+ .then?>(
+ (taskList) => _handleTaskList(taskList, showOnlyDueDateTasks));
+ }); //.onError((error, stackTrace) {print("error");});
}
- Future _handleTaskList(List? taskList, bool showOnlyDueDateTasks) {
- if(showOnlyDueDateTasks)
- taskList?.removeWhere((element) => element.dueDate == null || element.dueDate!.year == 0001);
+ Future _handleTaskList(
+ List? taskList, bool showOnlyDueDateTasks) {
+ if (showOnlyDueDateTasks)
+ taskList?.removeWhere((element) =>
+ element.dueDate == null || element.dueDate!.year == 0001);
if (taskList != null && taskList.isEmpty) {
setState(() {
diff --git a/lib/pages/list/task_edit.dart b/lib/pages/list/task_edit.dart
index 0ccfb8a..1dfdd5e 100644
--- a/lib/pages/list/task_edit.dart
+++ b/lib/pages/list/task_edit.dart
@@ -48,8 +48,8 @@ class _TaskEditPageState extends State {
@override
void initState() {
_repeatAfter = widget.task.repeatAfter;
- if(_repeatAfterType == null)
- _repeatAfterType = getRepeatAfterTypeFromDuration(_repeatAfter);
+ if (_repeatAfterType == null)
+ _repeatAfterType = getRepeatAfterTypeFromDuration(_repeatAfter);
_reminderDates = widget.task.reminderDates;
for (var i = 0; i < _reminderDates.length; i++) {
@@ -86,25 +86,30 @@ class _TaskEditPageState extends State {
actions: [
IconButton(
icon: Icon(Icons.delete),
- onPressed: () {showDialog(context: context, builder: (BuildContext context) {
- return AlertDialog(
- title: Text('Delete Task'),
- content: Text('Are you sure you want to delete this task?'),
- actions: [
- TextButton(
- child: Text('Cancel'),
- onPressed: () => Navigator.of(context).pop(),
- ),
- TextButton(
- child: Text('Delete'),
- onPressed: () {
- _delete(widget.task.id);
- Navigator.of(context).pop();
- },
- ),
- ],
- );
- });},
+ onPressed: () {
+ showDialog(
+ context: context,
+ builder: (BuildContext context) {
+ return AlertDialog(
+ title: Text('Delete Task'),
+ content: Text(
+ 'Are you sure you want to delete this task?'),
+ actions: [
+ TextButton(
+ child: Text('Cancel'),
+ onPressed: () => Navigator.of(context).pop(),
+ ),
+ TextButton(
+ child: Text('Delete'),
+ onPressed: () {
+ _delete(widget.task.id);
+ Navigator.of(context).pop();
+ },
+ ),
+ ],
+ );
+ });
+ },
),
],
),
@@ -114,7 +119,8 @@ class _TaskEditPageState extends State {
key: _formKey,
child: ListView(
key: _listKey,
- padding: EdgeInsets.fromLTRB(16, 16, 16, MediaQuery.of(context).size.height / 2),
+ padding: EdgeInsets.fromLTRB(
+ 16, 16, 16, MediaQuery.of(context).size.height / 2),
children: [
Padding(
padding: EdgeInsets.symmetric(vertical: 10.0),
@@ -182,8 +188,9 @@ class _TaskEditPageState extends State {
flex: 2,
child: TextFormField(
keyboardType: TextInputType.number,
- initialValue: getRepeatAfterValueFromDuration(
- _repeatAfter)?.toString(),
+ initialValue:
+ getRepeatAfterValueFromDuration(_repeatAfter)
+ ?.toString(),
onSaved: (repeatAfter) => _repeatAfter =
getDurationFromType(
repeatAfter, _repeatAfterType),
@@ -200,8 +207,7 @@ class _TaskEditPageState extends State {
isExpanded: true,
isDense: true,
value: _repeatAfterType ??
- getRepeatAfterTypeFromDuration(
- _repeatAfter),
+ getRepeatAfterTypeFromDuration(_repeatAfter),
onChanged: (String? newValue) {
setState(() {
_repeatAfterType = newValue;
@@ -321,9 +327,11 @@ class _TaskEditPageState extends State {
Padding(
padding: EdgeInsets.only(
right: 15,
- left: 2.0 + (IconTheme.of(context).size??0))),
+ left: 2.0 + (IconTheme.of(context).size ?? 0))),
Container(
- width: MediaQuery.of(context).size.width - 80 - ((IconTheme.of(context).size ?? 0) * 2),
+ width: MediaQuery.of(context).size.width -
+ 80 -
+ ((IconTheme.of(context).size ?? 0) * 2),
child: TypeAheadField(
builder: (builder, controller, focusnode) {
return TextFormField(
@@ -427,18 +435,25 @@ class _TaskEditPageState extends State {
trailing: IconButton(
icon: Icon(Icons.download),
onPressed: () async {
- String url = VikunjaGlobal.of(context).client.base;
- url += '/tasks/${widget.task.id}/attachments/${widget.task.attachments[index].id}';
+ String url =
+ VikunjaGlobal.of(context).client.base;
+ url +=
+ '/tasks/${widget.task.id}/attachments/${widget.task.attachments[index].id}';
print(url);
final taskId = await FlutterDownloader.enqueue(
url: url,
- fileName: widget.task.attachments[index].file.name,
- headers: VikunjaGlobal.of(context).client.headers, // optional: header send with url (auth token etc)
+ fileName:
+ widget.task.attachments[index].file.name,
+ headers: VikunjaGlobal.of(context)
+ .client
+ .headers, // optional: header send with url (auth token etc)
savedDir: '/storage/emulated/0/Download/',
- showNotification: true, // show download progress in status bar (for Android)
- openFileFromNotification: true, // click on notification to open downloaded file (for Android)
+ showNotification:
+ true, // show download progress in status bar (for Android)
+ openFileFromNotification:
+ true, // click on notification to open downloaded file (for Android)
);
- if(taskId == null) return;
+ if (taskId == null) return;
FlutterDownloader.open(taskId: taskId);
},
),
@@ -594,8 +609,6 @@ class _TaskEditPageState extends State {
});
}
-
-
_onColorEdit() {
_pickerColor = _resetColor || (_color ?? widget.task.color) == null
? Colors.black
diff --git a/lib/pages/project/overview.dart b/lib/pages/project/overview.dart
index 4ed35e4..c36468a 100644
--- a/lib/pages/project/overview.dart
+++ b/lib/pages/project/overview.dart
@@ -1,4 +1,3 @@
-
import 'package:after_layout/after_layout.dart';
import 'package:flutter/material.dart';
import 'package:vikunja_app/pages/project/project_task_list.dart';
@@ -16,14 +15,9 @@ class ProjectOverviewPage extends StatefulWidget {
class _ProjectOverviewPageState extends State
with AfterLayoutMixin {
List _projects = [];
- int _selectedDrawerIndex = -2, _previousDrawerIndex = -2;
+ int _selectedDrawerIndex = -2;
bool _loading = true;
- Project? get _currentProject =>
- _selectedDrawerIndex >= -1 && _selectedDrawerIndex < _projects.length
- ? _projects[_selectedDrawerIndex]
- : null;
-
@override
void afterFirstLayout(BuildContext context) {
_loadProjects();
@@ -37,9 +31,9 @@ class _ProjectOverviewPageState extends State
bool expanded = expandedList.contains(project.id);
Widget icon;
- List? children = addProjectChildren(project, level+1);
+ List? children = addProjectChildren(project, level + 1);
bool no_children = children.length == 0;
- if(no_children) {
+ if (no_children) {
icon = Icon(Icons.list);
} else {
if (expanded) {
@@ -50,34 +44,34 @@ class _ProjectOverviewPageState extends State
}
}
-
- return Column(children: [
- ListTile(
- onTap: () {
- setState(() {
- openList(context, project);
- });
- },
- contentPadding: insets,
+ return Column(children: [
+ ListTile(
+ onTap: () {
+ setState(() {
+ openList(context, project);
+ });
+ },
+ contentPadding: insets,
leading: IconButton(
disabledColor: Theme.of(context).unselectedWidgetColor,
icon: icon,
- onPressed: !no_children ? () {
- setState(() {
- if (expanded)
- expandedList.remove(project.id);
- else
- expandedList.add(project.id);
- });
- } : null,
+ onPressed: !no_children
+ ? () {
+ setState(() {
+ if (expanded)
+ expandedList.remove(project.id);
+ else
+ expandedList.add(project.id);
+ });
+ }
+ : null,
),
title: new Text(project.title),
//onTap: () => _onSelectItem(i),
),
- ...?children
- ]);
- }
-
+ ...?children
+ ]);
+ }
List addProjectChildren(Project project, level) {
Iterable children =
@@ -120,7 +114,6 @@ class _ProjectOverviewPageState extends State
.toList()),
onRefresh: _loadProjects,
),
-
appBar: AppBar(
title: Text("Projects"),
),
@@ -136,8 +129,6 @@ class _ProjectOverviewPageState extends State
});
}
-
-
_addProjectDialog(BuildContext context) {
showDialog(
context: context,
diff --git a/lib/pages/settings.dart b/lib/pages/settings.dart
index aa5b685..12d0e28 100644
--- a/lib/pages/settings.dart
+++ b/lib/pages/settings.dart
@@ -8,7 +8,6 @@ import '../models/project.dart';
import '../models/user.dart';
import '../service/services.dart';
-
class SettingsPage extends StatefulWidget {
@override
State createState() => SettingsPageState();
@@ -25,7 +24,6 @@ class SettingsPageState extends State {
FlutterThemeMode? themeMode;
User? currentUser;
-
void init() {
durationTextController = TextEditingController();
@@ -51,20 +49,21 @@ class SettingsPageState extends State {
.getCurrentVersionTag()
.then((value) => setState(() => versionTag = value));
+ VikunjaGlobal.of(context).settingsManager.getWorkmanagerDuration().then(
+ (value) => setState(
+ () => durationTextController.text = (value.inMinutes.toString())));
+
VikunjaGlobal.of(context)
.settingsManager
- .getWorkmanagerDuration()
- .then((value) => setState(() => durationTextController.text = (value.inMinutes.toString())));
-
- VikunjaGlobal.of(context).settingsManager.getThemeMode().then((value) => setState(() => themeMode = value));
+ .getThemeMode()
+ .then((value) => setState(() => themeMode = value));
VikunjaGlobal.of(context).newUserService?.getCurrentUser().then((value) => {
- setState(() {
- currentUser = value!;
- defaultProject = value.settings?.default_project_id;
- } ),
- });
-
+ setState(() {
+ currentUser = value!;
+ defaultProject = value.settings?.default_project_id;
+ }),
+ });
initialized = true;
}
@@ -75,18 +74,22 @@ class SettingsPageState extends State {
if (!initialized) init();
return new Scaffold(
- appBar: AppBar(title: Text("Settings"),),
-
+ appBar: AppBar(
+ title: Text("Settings"),
+ ),
body: ListView(
children: [
UserAccountsDrawerHeader(
- accountName: currentUser != null ? Text(currentUser!.username) : null,
+ accountName:
+ currentUser != null ? Text(currentUser!.username) : null,
accountEmail: currentUser != null ? Text(currentUser!.name) : null,
currentAccountPicture: currentUser == null
? null
: CircleAvatar(
- backgroundImage: (currentUser?.username != "") ? NetworkImage(currentUser!.avatarUrl(context)) : null,
- ),
+ backgroundImage: (currentUser?.username != "")
+ ? NetworkImage(currentUser!.avatarUrl(context))
+ : null,
+ ),
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage("assets/graphics/hypnotize.png"),
@@ -109,11 +112,17 @@ class SettingsPageState extends State {
child: Text(e.title), value: e.id))
.toList()
],
- value: projectList?.firstWhereOrNull((element) => element.id == defaultProject) != null ? defaultProject : null,
+ value: projectList?.firstWhereOrNull(
+ (element) => element.id == defaultProject) !=
+ null
+ ? defaultProject
+ : null,
onChanged: (int? value) {
setState(() => defaultProject = value);
- global.newUserService?.setCurrentUserSettings(
- currentUser!.settings!.copyWith(default_project_id: value)).then((value) => currentUser!.settings = value);
+ global.newUserService
+ ?.setCurrentUserSettings(currentUser!.settings!
+ .copyWith(default_project_id: value))
+ .then((value) => currentUser!.settings = value);
//VikunjaGlobal.of(context).userManager.setDefaultList(value);
},
),
@@ -149,9 +158,7 @@ class SettingsPageState extends State {
],
value: themeMode,
onChanged: (FlutterThemeMode? value) {
- VikunjaGlobal.of(context)
- .settingsManager
- .setThemeMode(value!);
+ VikunjaGlobal.of(context).settingsManager.setThemeMode(value!);
setState(() => themeMode = value);
updateTheme.value = true;
},
@@ -164,27 +171,30 @@ class SettingsPageState extends State {
value: ignoreCertificates,
onChanged: (value) {
setState(() => ignoreCertificates = value);
- VikunjaGlobal.of(context).client.reload_ignore_certs(value);
+ VikunjaGlobal.of(context).client.reloadIgnoreCerts(value);
})
: ListTile(title: Text("...")),
- Divider(),
- Padding(padding: EdgeInsets.only(left: 15, right: 15),
+ Divider(),
+ Padding(
+ padding: EdgeInsets.only(left: 15, right: 15),
child: Row(children: [
- Flexible(
- child: TextField(
- controller: durationTextController,
- decoration: InputDecoration(
- labelText: 'Background Refresh Interval (minutes): ',
- helperText: 'Minimum: 15, Set limit of 0 for no refresh',
- ),
- )),
- TextButton(
- onPressed: () => VikunjaGlobal.of(context)
- .settingsManager
- .setWorkmanagerDuration(Duration(
- minutes: int.parse(durationTextController.text))).then((value) => VikunjaGlobal.of(context).updateWorkmanagerDuration()),
- child: Text("Save")),
- ])),
+ Flexible(
+ child: TextField(
+ controller: durationTextController,
+ decoration: InputDecoration(
+ labelText: 'Background Refresh Interval (minutes): ',
+ helperText: 'Minimum: 15, Set limit of 0 for no refresh',
+ ),
+ )),
+ TextButton(
+ onPressed: () => VikunjaGlobal.of(context)
+ .settingsManager
+ .setWorkmanagerDuration(Duration(
+ minutes: int.parse(durationTextController.text)))
+ .then((value) => VikunjaGlobal.of(context)
+ .updateWorkmanagerDuration()),
+ child: Text("Save")),
+ ])),
Divider(),
getVersionNotifications != null
? CheckboxListTile(
diff --git a/lib/pages/user/login.dart b/lib/pages/user/login.dart
index 4ad08ed..5d6a6b1 100644
--- a/lib/pages/user/login.dart
+++ b/lib/pages/user/login.dart
@@ -33,11 +33,10 @@ class _LoginPageState extends State {
final _serverSuggestionController = SuggestionsController();
-
@override
void initState() {
super.initState();
- Future.delayed(Duration.zero, () async{
+ Future.delayed(Duration.zero, () async {
if (VikunjaGlobal.of(context).expired) {
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Text("Login has expired. Please reenter your details!")));
@@ -48,10 +47,16 @@ class _LoginPageState extends State {
});
}
final client = VikunjaGlobal.of(context).client;
- await VikunjaGlobal.of(context).settingsManager.getIgnoreCertificates().then(
- (value) => setState(() => client.ignoreCertificates = value == "1"));
+ await VikunjaGlobal.of(context)
+ .settingsManager
+ .getIgnoreCertificates()
+ .then((value) =>
+ setState(() => client.ignoreCertificates = value == "1"));
- await VikunjaGlobal.of(context).settingsManager.getPastServers().then((value) {
+ await VikunjaGlobal.of(context)
+ .settingsManager
+ .getPastServers()
+ .then((value) {
print(value);
if (value != null) setState(() => pastServers = value);
});
@@ -101,11 +106,11 @@ class _LoginPageState extends State {
enabled: !_loading,
validator: (address) {
return (isUrl(address) ||
- address != null ||
- address!.isEmpty)
- ? null
- : 'Invalid URL';
- },
+ address != null ||
+ address!.isEmpty)
+ ? null
+ : 'Invalid URL';
+ },
decoration: new InputDecoration(
border: OutlineInputBorder(),
labelText: 'Server Address'),
@@ -120,34 +125,42 @@ class _LoginPageState extends State {
),*/
onSelected: (suggestion) {
_serverController.text = suggestion;
- setState(() => _serverController.text = suggestion);
+ setState(
+ () => _serverController.text = suggestion);
},
- itemBuilder: (BuildContext context, Object? itemData) {
+ itemBuilder:
+ (BuildContext context, Object? itemData) {
return Card(
child: Container(
- padding: EdgeInsets.all(10),
- child:
- Row(
- mainAxisAlignment: MainAxisAlignment.spaceBetween,
- children: [
- Text(itemData.toString()),
- IconButton(onPressed: () {
- setState(() {
- pastServers.remove(itemData.toString());
- //_serverSuggestionController.suggestionsBox?.close();
- VikunjaGlobal.of(context).settingsManager.setPastServers(pastServers);
-
- });
- }, icon: Icon(Icons.clear))
- ],
- ))
- );
+ padding: EdgeInsets.all(10),
+ child: Row(
+ mainAxisAlignment:
+ MainAxisAlignment.spaceBetween,
+ children: [
+ Text(itemData.toString()),
+ IconButton(
+ onPressed: () {
+ setState(() {
+ pastServers.remove(
+ itemData.toString());
+ //_serverSuggestionController.suggestionsBox?.close();
+ VikunjaGlobal.of(context)
+ .settingsManager
+ .setPastServers(
+ pastServers);
+ });
+ },
+ icon: Icon(Icons.clear))
+ ],
+ )));
},
suggestionsCallback: (String pattern) {
List matches = [];
matches.addAll(pastServers);
- matches.retainWhere((s){
- return s.toLowerCase().contains(pattern.toLowerCase());
+ matches.retainWhere((s) {
+ return s
+ .toLowerCase()
+ .contains(pattern.toLowerCase());
});
return matches;
},
@@ -246,20 +259,18 @@ class _LoginPageState extends State {
}
},
child: VikunjaButtonText("Login with Frontend"))),
- CheckboxListTile(
- title: Text("Ignore Certificates"),
- value: client.ignoreCertificates,
- onChanged: (value) {
- setState(() =>
- client.reload_ignore_certs(value ?? false));
- VikunjaGlobal.of(context)
- .settingsManager
- .setIgnoreCertificates(value ?? false);
- VikunjaGlobal.of(context)
- .client
- .ignoreCertificates = value ?? false;
- })
-
+ CheckboxListTile(
+ title: Text("Ignore Certificates"),
+ value: client.ignoreCertificates,
+ onChanged: (value) {
+ setState(
+ () => client.reloadIgnoreCerts(value ?? false));
+ VikunjaGlobal.of(context)
+ .settingsManager
+ .setIgnoreCertificates(value ?? false);
+ VikunjaGlobal.of(context).client.ignoreCertificates =
+ value ?? false;
+ })
],
),
),
@@ -276,7 +287,7 @@ class _LoginPageState extends State {
String _password = _passwordController.text;
if (_server.isEmpty) return;
- if(!pastServers.contains(_server)) pastServers.add(_server);
+ if (!pastServers.contains(_server)) pastServers.add(_server);
await VikunjaGlobal.of(context).settingsManager.setPastServers(pastServers);
setState(() => _loading = true);
@@ -285,8 +296,7 @@ class _LoginPageState extends State {
vGlobal.client.showSnackBar = false;
vGlobal.client.configure(base: _server);
Server? info = await vGlobal.serverService.getInfo();
- if (info == null)
- throw Exception("Getting server info failed");
+ if (info == null) throw Exception("Getting server info failed");
UserTokenPair newUser;
@@ -297,27 +307,27 @@ class _LoginPageState extends State {
TextEditingController totpController = TextEditingController();
bool dismissed = true;
await showDialog(
- context: context,
- builder: (context) => new AlertDialog(
- title: Text("Enter One Time Passcode"),
- content: TextField(
- controller: totpController,
- keyboardType: TextInputType.number,
- inputFormatters: [
- FilteringTextInputFormatter.digitsOnly
- ],
- ),
- actions: [
- TextButton(
- onPressed: () {
- dismissed = false;
- Navigator.pop(context);
- },
- child: Text("Login"))
- ],
- ),
+ context: context,
+ builder: (context) => new AlertDialog(
+ title: Text("Enter One Time Passcode"),
+ content: TextField(
+ controller: totpController,
+ keyboardType: TextInputType.number,
+ inputFormatters: [
+ FilteringTextInputFormatter.digitsOnly
+ ],
+ ),
+ actions: [
+ TextButton(
+ onPressed: () {
+ dismissed = false;
+ Navigator.pop(context);
+ },
+ child: Text("Login"))
+ ],
+ ),
);
- if(!dismissed) {
+ if (!dismissed) {
newUser = await vGlobal.newUserService!.login(_username, _password,
rememberMe: this._rememberMe, totp: totpController.text);
} else {
diff --git a/pubspec.lock b/pubspec.lock
index cf06862..e851c5f 100644
--- a/pubspec.lock
+++ b/pubspec.lock
@@ -122,21 +122,21 @@ packages:
source: hosted
version: "2.0.3"
chewie:
- dependency: "direct main"
+ dependency: transitive
description:
name: chewie
- sha256: "745e81e84c6d7f3835f89f85bb49771c0a66099e4caf8f8e9e9a372bc66fb2c1"
+ sha256: "8bc4ac4cf3f316e50a25958c0f5eb9bb12cf7e8308bb1d74a43b230da2cfc144"
url: "https://pub.dev"
source: hosted
- version: "1.5.0"
+ version: "1.7.5"
cli_util:
dependency: transitive
description:
name: cli_util
- sha256: "66f86e916d285c1a93d3b79587d94bd71984a66aac4ff74e524cfa7877f1395c"
+ sha256: c05b7406fdabc7a49a3929d4af76bcaccbbffcbcdcf185b082e1ae07da323d19
url: "https://pub.dev"
source: hosted
- version: "0.3.5"
+ version: "0.4.1"
clock:
dependency: transitive
description:
@@ -253,10 +253,10 @@ packages:
dependency: transitive
description:
name: file
- sha256: "1b92bec4fc2a72f59a8e15af5f52cd441e4a7860b49499d69dfa817af20e925d"
+ sha256: "5fc22d7c25582e38ad9a8515372cd9a93834027aacf1801cf01164dac0ffa08c"
url: "https://pub.dev"
source: hosted
- version: "6.1.4"
+ version: "7.0.0"
fixnum:
dependency: transitive
description:
@@ -298,10 +298,10 @@ packages:
dependency: "direct main"
description:
name: flutter_keyboard_visibility
- sha256: "183ef857869a790aaff0219327a31783017fcc54b895fcdda1909645bb6ab965"
+ sha256: "98664be7be0e3ffca00de50f7f6a287ab62c763fc8c762e0a21584584a3ff4f8"
url: "https://pub.dev"
source: hosted
- version: "5.4.2"
+ version: "6.0.0"
flutter_keyboard_visibility_linux:
dependency: transitive
description:
@@ -346,42 +346,42 @@ packages:
dependency: "direct dev"
description:
name: flutter_launcher_icons
- sha256: a9de6706cd844668beac27c0aed5910fa0534832b3c2cad61a5fd977fce82a5d
+ sha256: "526faf84284b86a4cb36d20a5e45147747b7563d921373d4ee0559c54fcdbcea"
url: "https://pub.dev"
source: hosted
- version: "0.10.0"
+ version: "0.13.1"
flutter_local_notifications:
dependency: "direct main"
description:
name: flutter_local_notifications
- sha256: "57d0012730780fe137260dd180e072c18a73fbeeb924cdc029c18aaa0f338d64"
+ sha256: f9a05409385b77b06c18f200a41c7c2711ebf7415669350bb0f8474c07bd40d1
url: "https://pub.dev"
source: hosted
- version: "9.9.1"
+ version: "17.0.0"
flutter_local_notifications_linux:
dependency: transitive
description:
name: flutter_local_notifications_linux
- sha256: b472bfc173791b59ede323661eae20f7fff0b6908fea33dd720a6ef5d576bae8
+ sha256: "33f741ef47b5f63cc7f78fe75eeeac7e19f171ff3c3df054d84c1e38bedb6a03"
url: "https://pub.dev"
source: hosted
- version: "0.5.1"
+ version: "4.0.0+1"
flutter_local_notifications_platform_interface:
dependency: transitive
description:
name: flutter_local_notifications_platform_interface
- sha256: "21bceee103a66a53b30ea9daf677f990e5b9e89b62f222e60dd241cd08d63d3a"
+ sha256: "7cf643d6d5022f3baed0be777b0662cce5919c0a7b86e700299f22dc4ae660ef"
url: "https://pub.dev"
source: hosted
- version: "5.0.0"
+ version: "7.0.0+1"
flutter_secure_storage:
dependency: "direct main"
description:
name: flutter_secure_storage
- sha256: "22dbf16f23a4bcf9d35e51be1c84ad5bb6f627750565edd70dab70f3ff5fff8f"
+ sha256: ffdbb60130e4665d2af814a0267c481bcf522c41ae2e43caf69fa0146876d685
url: "https://pub.dev"
source: hosted
- version: "8.1.0"
+ version: "9.0.0"
flutter_secure_storage_linux:
dependency: transitive
description:
@@ -418,18 +418,18 @@ packages:
dependency: transitive
description:
name: flutter_secure_storage_windows
- sha256: "38f9501c7cb6f38961ef0e1eacacee2b2d4715c63cc83fe56449c4d3d0b47255"
+ sha256: "5809c66f9dd3b4b93b0a6e2e8561539405322ee767ac2f64d084e2ab5429d108"
url: "https://pub.dev"
source: hosted
- version: "2.1.1"
+ version: "3.0.0"
flutter_svg:
dependency: transitive
description:
name: flutter_svg
- sha256: d39e7f95621fc84376bc0f7d504f05c3a41488c562f4a8ad410569127507402c
+ sha256: "7b4ca6cf3304575fe9c8ec64813c8d02ee41d2afe60bcfe0678bcb5375d596a2"
url: "https://pub.dev"
source: hosted
- version: "2.0.9"
+ version: "2.0.10+1"
flutter_test:
dependency: "direct dev"
description: flutter
@@ -447,10 +447,10 @@ packages:
dependency: "direct main"
description:
name: flutter_typeahead
- sha256: "1f6b248bb4f3ebb4cf1ee0354aa23c77be457fb2d26d6847ecc33a917f65e58e"
+ sha256: d64712c65db240b1057559b952398ebb6e498077baeebf9b0731dade62438a6d
url: "https://pub.dev"
source: hosted
- version: "5.0.1"
+ version: "5.2.0"
flutter_web_plugins:
dependency: transitive
description: flutter
@@ -548,10 +548,10 @@ packages:
dependency: "direct main"
description:
name: http
- sha256: "5895291c13fa8a3bd82e76d5627f69e0d85ca6a30dcac95c4ea19a5d555879c2"
+ sha256: "761a297c042deedc1ffbb156d6e2af13886bb305c2a343a4d972504cd67dd938"
url: "https://pub.dev"
source: hosted
- version: "0.13.6"
+ version: "1.2.1"
http_multi_server:
dependency: transitive
description:
@@ -572,18 +572,18 @@ packages:
dependency: transitive
description:
name: image
- sha256: "8e9d133755c3e84c73288363e6343157c383a0c6c56fc51afcc5d4d7180306d6"
+ sha256: "4c68bfd5ae83e700b5204c1e74451e7bf3cf750e6843c6e158289cf56bda018e"
url: "https://pub.dev"
source: hosted
- version: "3.3.0"
+ version: "4.1.7"
intl:
dependency: "direct main"
description:
name: intl
- sha256: "910f85bce16fb5c6f614e117efa303e85a1731bb0081edf3604a2ae6e9a3cc91"
+ sha256: d6f56758b7d3014a48af9701c085700aac781a92a87a62b1333b46d8879661cf
url: "https://pub.dev"
source: hosted
- version: "0.17.0"
+ version: "0.19.0"
io:
dependency: transitive
description:
@@ -737,13 +737,13 @@ packages:
source: hosted
version: "2.1.0"
package_info_plus:
- dependency: "direct main"
+ dependency: transitive
description:
name: package_info_plus
- sha256: "10259b111176fba5c505b102e3a5b022b51dd97e30522e906d6922c745584745"
+ sha256: "7e76fad405b3e4016cd39d08f455a4eb5199723cf594cd1b8916d47140d93017"
url: "https://pub.dev"
source: hosted
- version: "3.1.2"
+ version: "4.2.0"
package_info_plus_platform_interface:
dependency: transitive
description:
@@ -828,50 +828,58 @@ packages:
dependency: "direct main"
description:
name: permission_handler
- sha256: bc56bfe9d3f44c3c612d8d393bd9b174eb796d706759f9b495ac254e4294baa5
+ sha256: "74e962b7fad7ff75959161bb2c0ad8fe7f2568ee82621c9c2660b751146bfe44"
url: "https://pub.dev"
source: hosted
- version: "10.4.5"
+ version: "11.3.0"
permission_handler_android:
dependency: transitive
description:
name: permission_handler_android
- sha256: "59c6322171c29df93a22d150ad95f3aa19ed86542eaec409ab2691b8f35f9a47"
+ sha256: "1acac6bae58144b442f11e66621c062aead9c99841093c38f5bcdcc24c1c3474"
url: "https://pub.dev"
source: hosted
- version: "10.3.6"
+ version: "12.0.5"
permission_handler_apple:
dependency: transitive
description:
name: permission_handler_apple
- sha256: "99e220bce3f8877c78e4ace901082fb29fa1b4ebde529ad0932d8d664b34f3f5"
+ sha256: e9ad66020b89ff1b63908f247c2c6f931c6e62699b756ef8b3c4569350cd8662
url: "https://pub.dev"
source: hosted
- version: "9.1.4"
+ version: "9.4.4"
+ permission_handler_html:
+ dependency: transitive
+ description:
+ name: permission_handler_html
+ sha256: "54bf176b90f6eddd4ece307e2c06cf977fb3973719c35a93b85cc7093eb6070d"
+ url: "https://pub.dev"
+ source: hosted
+ version: "0.1.1"
permission_handler_platform_interface:
dependency: transitive
description:
name: permission_handler_platform_interface
- sha256: "6760eb5ef34589224771010805bea6054ad28453906936f843a8cc4d3a55c4a4"
+ sha256: "23dfba8447c076ab5be3dee9ceb66aad345c4a648f0cac292c77b1eb0e800b78"
url: "https://pub.dev"
source: hosted
- version: "3.12.0"
+ version: "4.2.0"
permission_handler_windows:
dependency: transitive
description:
name: permission_handler_windows
- sha256: cc074aace208760f1eee6aa4fae766b45d947df85bc831cde77009cdb4720098
+ sha256: "1a790728016f79a41216d88672dbc5df30e686e811ad4e698bfc51f76ad91f1e"
url: "https://pub.dev"
source: hosted
- version: "0.1.3"
+ version: "0.2.1"
petitparser:
dependency: "direct main"
description:
name: petitparser
- sha256: cb3798bef7fc021ac45b308f4b51208a152792445cce0448c9a4ba5879dd8750
+ sha256: c15605cd28af66339f8eb6fbe0e541bfe2d1b72d5825efc6598f3e0a31b9ad27
url: "https://pub.dev"
source: hosted
- version: "5.4.0"
+ version: "6.0.2"
platform:
dependency: transitive
description:
@@ -892,10 +900,34 @@ packages:
dependency: transitive
description:
name: pointer_interceptor
- sha256: adf7a637f97c077041d36801b43be08559fd4322d2127b3f20bb7be1b9eebc22
+ sha256: bd18321519718678d5fa98ad3a3359cbc7a31f018554eab80b73d08a7f0c165a
+ url: "https://pub.dev"
+ source: hosted
+ version: "0.10.1"
+ pointer_interceptor_ios:
+ dependency: transitive
+ description:
+ name: pointer_interceptor_ios
+ sha256: "2e73c39452830adc4695757130676a39412a3b7f3c34e3f752791b5384770877"
url: "https://pub.dev"
source: hosted
- version: "0.9.3+7"
+ version: "0.10.0+2"
+ pointer_interceptor_platform_interface:
+ dependency: transitive
+ description:
+ name: pointer_interceptor_platform_interface
+ sha256: "0597b0560e14354baeb23f8375cd612e8bd4841bf8306ecb71fcd0bb78552506"
+ url: "https://pub.dev"
+ source: hosted
+ version: "0.10.0+1"
+ pointer_interceptor_web:
+ dependency: transitive
+ description:
+ name: pointer_interceptor_web
+ sha256: a6237528b46c411d8d55cdfad8fcb3269fc4cbb26060b14bff94879165887d1e
+ url: "https://pub.dev"
+ source: hosted
+ version: "0.10.2"
pointycastle:
dependency: transitive
description:
@@ -912,14 +944,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.5.1"
- process:
- dependency: transitive
- description:
- name: process
- sha256: "53fd8db9cec1d37b0574e12f07520d582019cb6c44abf5479a01505099a34a09"
- url: "https://pub.dev"
- source: hosted
- version: "4.2.4"
provider:
dependency: "direct main"
description:
@@ -1121,10 +1145,10 @@ packages:
dependency: "direct main"
description:
name: timezone
- sha256: "57b35f6e8ef731f18529695bffc62f92c6189fac2e52c12d478dec1931afb66e"
+ sha256: "1cfd8ddc2d1cfd836bc93e67b9be88c3adaeca6f40a00ca999104c30693cdca0"
url: "https://pub.dev"
source: hosted
- version: "0.8.0"
+ version: "0.9.2"
typed_data:
dependency: transitive
description:
@@ -1209,26 +1233,26 @@ packages:
dependency: transitive
description:
name: vector_graphics
- sha256: "4ac59808bbfca6da38c99f415ff2d3a5d7ca0a6b4809c71d9cf30fba5daf9752"
+ sha256: "32c3c684e02f9bc0afb0ae0aa653337a2fe022e8ab064bcd7ffda27a74e288e3"
url: "https://pub.dev"
source: hosted
- version: "1.1.10+1"
+ version: "1.1.11+1"
vector_graphics_codec:
dependency: transitive
description:
name: vector_graphics_codec
- sha256: f3247e7ab0ec77dc759263e68394990edc608fb2b480b80db8aa86ed09279e33
+ sha256: c86987475f162fadff579e7320c7ddda04cd2fdeffbe1129227a85d9ac9e03da
url: "https://pub.dev"
source: hosted
- version: "1.1.10+1"
+ version: "1.1.11+1"
vector_graphics_compiler:
dependency: transitive
description:
name: vector_graphics_compiler
- sha256: "18489bdd8850de3dd7ca8a34e0c446f719ec63e2bab2e7a8cc66a9028dd76c5a"
+ sha256: "12faff3f73b1741a36ca7e31b292ddeb629af819ca9efe9953b70bd63fc8cd81"
url: "https://pub.dev"
source: hosted
- version: "1.1.10+1"
+ version: "1.1.11+1"
vector_math:
dependency: transitive
description:
@@ -1285,46 +1309,22 @@ packages:
url: "https://pub.dev"
source: hosted
version: "13.0.0"
- wakelock:
- dependency: transitive
- description:
- name: wakelock
- sha256: "769ecf42eb2d07128407b50cb93d7c10bd2ee48f0276ef0119db1d25cc2f87db"
- url: "https://pub.dev"
- source: hosted
- version: "0.6.2"
- wakelock_macos:
- dependency: transitive
- description:
- name: wakelock_macos
- sha256: "047c6be2f88cb6b76d02553bca5a3a3b95323b15d30867eca53a19a0a319d4cd"
- url: "https://pub.dev"
- source: hosted
- version: "0.4.0"
- wakelock_platform_interface:
- dependency: transitive
- description:
- name: wakelock_platform_interface
- sha256: "1f4aeb81fb592b863da83d2d0f7b8196067451e4df91046c26b54a403f9de621"
- url: "https://pub.dev"
- source: hosted
- version: "0.3.0"
- wakelock_web:
+ wakelock_plus:
dependency: transitive
description:
- name: wakelock_web
- sha256: "1b256b811ee3f0834888efddfe03da8d18d0819317f20f6193e2922b41a501b5"
+ name: wakelock_plus
+ sha256: f268ca2116db22e57577fb99d52515a24bdc1d570f12ac18bb762361d43b043d
url: "https://pub.dev"
source: hosted
- version: "0.4.0"
- wakelock_windows:
+ version: "1.1.4"
+ wakelock_plus_platform_interface:
dependency: transitive
description:
- name: wakelock_windows
- sha256: "857f77b3fe6ae82dd045455baa626bc4b93cb9bb6c86bf3f27c182167c3a5567"
+ name: wakelock_plus_platform_interface
+ sha256: "40fabed5da06caff0796dc638e1f07ee395fb18801fbff3255a2372db2d80385"
url: "https://pub.dev"
source: hosted
- version: "0.2.1"
+ version: "1.1.0"
watcher:
dependency: transitive
description:
@@ -1393,10 +1393,10 @@ packages:
dependency: transitive
description:
name: win32
- sha256: a6f0236dbda0f63aa9a25ad1ff9a9d8a4eaaa5012da0dc59d21afdb1dc361ca4
+ sha256: "8cb58b45c47dcb42ab3651533626161d6b67a2921917d8d429791f76972b3480"
url: "https://pub.dev"
source: hosted
- version: "3.1.4"
+ version: "5.3.0"
workmanager:
dependency: "direct main"
description:
@@ -1409,18 +1409,18 @@ packages:
dependency: transitive
description:
name: xdg_directories
- sha256: bd512f03919aac5f1313eb8249f223bacf4927031bf60b02601f81f687689e86
+ sha256: faea9dee56b520b55a566385b84f2e8de55e7496104adada9962e0bd11bcff1d
url: "https://pub.dev"
source: hosted
- version: "0.2.0+3"
+ version: "1.0.4"
xml:
dependency: transitive
description:
name: xml
- sha256: "5bc72e1e45e941d825fd7468b9b4cc3b9327942649aeb6fc5cdbf135f0a86e84"
+ sha256: b015a8ad1c488f66851d762d3090a21c600e479dc75e68328c52774040cf9226
url: "https://pub.dev"
source: hosted
- version: "6.3.0"
+ version: "6.5.0"
yaml:
dependency: transitive
description:
diff --git a/pubspec.yaml b/pubspec.yaml
index 8d215ff..0f65ec8 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -9,44 +9,41 @@ environment:
dependencies:
flutter:
sdk: flutter
- cupertino_icons: ^1.0.5
- http: ^0.13.5
+ cupertino_icons: ^1.0.6
+ http: ^1.2.1
after_layout: ^1.2.0
- intl: ^0.17.0
- flutter_local_notifications: ^9.8.0+1
- rxdart: ^0.27.5
- flutter_timezone: ^1.0.4
- flutter_secure_storage: ^8.0.0
+ intl: ^0.19.0
+ flutter_local_notifications: ^17.0.0
+ rxdart: ^0.27.7
+ flutter_timezone: ^1.0.8
+ flutter_secure_storage: ^9.0.0
datetime_picker_formfield: ^2.0.1
- flutter_typeahead: ^5.0.1
- build: ^2.3.0
- json_serializable: ^6.3.1
- petitparser: ^5.0.0
- provider: ^6.0.3
- webview_flutter: ^4.4.3
+ flutter_typeahead: ^5.2.0
+ build: ^2.4.1
+ json_serializable: ^6.7.1
+ petitparser: ^6.0.2
+ provider: ^6.1.2
+ webview_flutter: ^4.7.0
flutter_colorpicker: ^1.0.3
- flutter_keyboard_visibility: ^5.4.2
- dotted_border: ^2.0.0+2
- package_info_plus: ^3.0.2
- url_launcher: ^6.1.7
- workmanager: ^0.5.1
- permission_handler: ^10.2.0
- dynamic_color: ^1.6.6
- chewie: ^1.5.0
- flutter_widget_from_html: ^0.14.10
+ flutter_keyboard_visibility: ^6.0.0
+ dotted_border: ^2.1.0
+ url_launcher: ^6.2.5
+ workmanager: ^0.5.2
+ permission_handler: ^11.3.0
+ dynamic_color: ^1.7.0
+ flutter_widget_from_html: ^0.14.11
flutter_downloader: ^1.11.6
-
- meta: any
- timezone: any
- json_annotation: any
- collection: any
+ meta: ^1.11.0
+ timezone: ^0.9.2
+ json_annotation: ^4.8.1
+ collection: ^1.18.0
dev_dependencies:
flutter_test:
sdk: flutter
version: any
- test: ^1.21.1
- flutter_launcher_icons: ^0.10.0
+ test: ^1.24.9
+ flutter_launcher_icons: ^0.13.1
flutter_icons:
image_path: "assets/vikunja_logo.png"