diff --git a/assets/filters/location/germany.png b/assets/filters/location/germany.png new file mode 100644 index 0000000..7fce53e Binary files /dev/null and b/assets/filters/location/germany.png differ diff --git a/assets/filters/location/germany_frankfurt_am_main.png b/assets/filters/location/germany_frankfurt_am_main.png new file mode 100644 index 0000000..4050672 Binary files /dev/null and b/assets/filters/location/germany_frankfurt_am_main.png differ diff --git a/assets/filters/random/avocardio.png b/assets/filters/random/avocardio.png new file mode 100644 index 0000000..46a0321 Binary files /dev/null and b/assets/filters/random/avocardio.png differ diff --git a/assets/filters/random/chillen.png b/assets/filters/random/chillen.png new file mode 100644 index 0000000..e379ce1 Binary files /dev/null and b/assets/filters/random/chillen.png differ diff --git a/assets/filters/random/duck.png b/assets/filters/random/duck.png new file mode 100644 index 0000000..eae7f36 Binary files /dev/null and b/assets/filters/random/duck.png differ diff --git a/assets/filters/random/hide_the_pain.png b/assets/filters/random/hide_the_pain.png new file mode 100644 index 0000000..f8a7205 Binary files /dev/null and b/assets/filters/random/hide_the_pain.png differ diff --git a/assets/filters/random/lol.png b/assets/filters/random/lol.png new file mode 100644 index 0000000..76b7707 Binary files /dev/null and b/assets/filters/random/lol.png differ diff --git a/assets/filters/random/yolo.png b/assets/filters/random/yolo.png new file mode 100644 index 0000000..8f13fb0 Binary files /dev/null and b/assets/filters/random/yolo.png differ diff --git a/lib/src/components/image_editor/data/layer.dart b/lib/src/components/image_editor/data/layer.dart index db25ac2..f5cd576 100755 --- a/lib/src/components/image_editor/data/layer.dart +++ b/lib/src/components/image_editor/data/layer.dart @@ -32,6 +32,8 @@ class BackgroundLayerData extends Layer { }); } +class FilterLayerData extends Layer {} + /// Attributes used by [EmojiLayer] class EmojiLayerData extends Layer { String text; diff --git a/lib/src/components/image_editor/layers/filter_layer.dart b/lib/src/components/image_editor/layers/filter_layer.dart new file mode 100644 index 0000000..6a08efc --- /dev/null +++ b/lib/src/components/image_editor/layers/filter_layer.dart @@ -0,0 +1,81 @@ +import 'package:flutter/material.dart'; +import 'package:twonly/src/components/image_editor/data/layer.dart'; +import 'package:twonly/src/components/image_editor/layers/filters/datetime_filter.dart'; +import 'package:twonly/src/components/image_editor/layers/filters/image_filter.dart'; +import 'package:twonly/src/components/image_editor/layers/filters/location_filter.dart'; + +/// Main layer +class FilterLayer extends StatefulWidget { + final FilterLayerData layerData; + // final VoidCallback? onUpdate; + + const FilterLayer({ + super.key, + required this.layerData, + // this.onUpdate, + }); + + @override + State createState() => _FilterLayerState(); +} + +class FilterSceleton extends StatelessWidget { + const FilterSceleton({super.key, this.child}); + final Widget? child; + + @override + Widget build(BuildContext context) { + return Container( + color: Colors.transparent, + child: Stack( + children: [ + Positioned.fill(child: Container()), + if (child != null) child!, + ], + ), + ); + } +} + +class FilterText extends StatelessWidget { + const FilterText(this.text, {super.key, this.fontSize = 24}); + final String text; + final double fontSize; + + @override + Widget build(BuildContext context) { + return Text( + text, + textAlign: TextAlign.start, + style: TextStyle( + fontSize: fontSize, + color: Colors.white, + shadows: [ + Shadow( + color: const Color.fromARGB(122, 0, 0, 0), + blurRadius: 5.0, + ) + ], + ), + ); + } +} + +class _FilterLayerState extends State { + @override + Widget build(BuildContext context) { + return PageView( + children: [ + FilterSceleton(), + DateTimeFilter(), + LocationFilter(), + ImageFilter(imagePath: "random/lol.png"), + ImageFilter(imagePath: "random/hide_the_pain.png"), + ImageFilter(imagePath: "random/yolo.png"), + ImageFilter(imagePath: "random/chillen.png"), + ImageFilter(imagePath: "random/avocardio.png"), + ImageFilter(imagePath: "random/duck.png"), + ], + ); + } +} diff --git a/lib/src/components/image_editor/layers/filters/datetime_filter.dart b/lib/src/components/image_editor/layers/filters/datetime_filter.dart new file mode 100644 index 0000000..850d99e --- /dev/null +++ b/lib/src/components/image_editor/layers/filters/datetime_filter.dart @@ -0,0 +1,26 @@ +import 'package:flutter/material.dart'; +import 'package:intl/intl.dart'; +import 'package:twonly/src/components/image_editor/layers/filter_layer.dart'; + +class DateTimeFilter extends StatelessWidget { + const DateTimeFilter({super.key}); + + @override + Widget build(BuildContext context) { + String currentTime = DateFormat('HH:mm').format(DateTime.now()); + String currentDate = DateFormat('dd.MM.yyyy').format(DateTime.now()); + return FilterSceleton( + child: Positioned( + bottom: 80, + left: 40, + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + FilterText(currentTime), + FilterText(currentDate), + ], + ), + ), + ); + } +} diff --git a/lib/src/components/image_editor/layers/filters/image_filter.dart b/lib/src/components/image_editor/layers/filters/image_filter.dart new file mode 100644 index 0000000..19901af --- /dev/null +++ b/lib/src/components/image_editor/layers/filters/image_filter.dart @@ -0,0 +1,24 @@ +import 'package:flutter/material.dart'; +import 'package:twonly/src/components/image_editor/layers/filter_layer.dart'; + +class ImageFilter extends StatelessWidget { + const ImageFilter({super.key, required this.imagePath}); + final String imagePath; + + @override + Widget build(BuildContext context) { + return FilterSceleton( + child: Positioned( + bottom: 50, + left: 10, + right: 10, + child: Center( + child: Image.asset( + "assets/filters/$imagePath", + height: 150, + ), + ), + ), + ); + } +} diff --git a/lib/src/components/image_editor/layers/filters/location_filter.dart b/lib/src/components/image_editor/layers/filters/location_filter.dart new file mode 100644 index 0000000..a615f48 --- /dev/null +++ b/lib/src/components/image_editor/layers/filters/location_filter.dart @@ -0,0 +1,87 @@ +import 'package:flutter/material.dart'; +import 'package:twonly/globals.dart'; +import 'package:twonly/src/components/image_editor/layers/filter_layer.dart'; +import 'package:twonly/src/components/image_editor/layers/filters/image_filter.dart'; +import 'package:twonly/src/proto/api/server_to_client.pb.dart'; + +class LocationFilter extends StatefulWidget { + const LocationFilter({super.key}); + + @override + State createState() => _LocationFilterState(); +} + +Map cities = { + "Frankfurt am Main": "germany_frankfurt_am_main.png", +}; + +Map countries = { + "Germany": "germany.png", +}; + +class _LocationFilterState extends State { + String? selectedImage; + String overlayText = ""; + Response_Location? location; + + @override + void initState() { + super.initState(); + initAsync(); + } + + Future initAsync() async { + final res = await apiProvider.getCurrentLocation(); + if (res.isSuccess) { + location = res.value.location; + + if (cities.containsKey(location!.city)) { + selectedImage = cities[location!.city]; + overlayText = location!.city; + } else if (countries.containsKey(location!.county)) { + selectedImage = countries[location!.county]; + overlayText = location!.county; + } + + setState(() {}); + } + } + + @override + Widget build(BuildContext context) { + if (selectedImage != null) { + return Stack( + children: [ + ImageFilter(imagePath: "location/${selectedImage!}"), + Positioned( + bottom: 55, + left: 0, + right: 0, + child: Center( + child: Text(overlayText), + ), + ) + ], + ); + } + + if (location != null) { + return FilterSceleton( + child: Positioned( + bottom: 50, + left: 40, + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + FilterText(location!.city), + FilterText(location!.region), + FilterText(location!.county), + ], + ), + ), + ); + } + + return Container(); + } +} diff --git a/lib/src/components/image_editor/layers_viewer.dart b/lib/src/components/image_editor/layers_viewer.dart index e60fdea..854a6e5 100644 --- a/lib/src/components/image_editor/layers_viewer.dart +++ b/lib/src/components/image_editor/layers_viewer.dart @@ -3,6 +3,7 @@ import 'package:twonly/src/components/image_editor/data/layer.dart'; import 'package:twonly/src/components/image_editor/layers/background_layer.dart'; import 'package:twonly/src/components/image_editor/layers/draw_layer.dart'; import 'package:twonly/src/components/image_editor/layers/emoji_layer.dart'; +import 'package:twonly/src/components/image_editor/layers/filter_layer.dart'; import 'package:twonly/src/components/image_editor/layers/text_layer.dart'; /// View stacked layers (unbounded height, width) @@ -27,6 +28,11 @@ class LayersViewer extends StatelessWidget { onUpdate: onUpdate, ); }), + ...layers.whereType().map((layerItem) { + return FilterLayer( + layerData: layerItem, + ); + }), ...layers .where((layerItem) => layerItem is EmojiLayerData || layerItem is DrawLayerData) diff --git a/lib/src/database/daos/contacts_dao.dart b/lib/src/database/daos/contacts_dao.dart index 9679081..2e05f36 100644 --- a/lib/src/database/daos/contacts_dao.dart +++ b/lib/src/database/daos/contacts_dao.dart @@ -56,7 +56,8 @@ class ContactsDao extends DatabaseAccessor // today a message was already send -> update flame updateFlame = true; } - } else if (contact.lastMessageReceived!.isAfter(startOfToday)) { + } else if (contact.lastMessageReceived != null && + contact.lastMessageReceived!.isAfter(startOfToday)) { // today a message was already received -> update flame updateFlame = true; } diff --git a/lib/src/providers/api_provider.dart b/lib/src/providers/api_provider.dart index 340a92b..8817c65 100644 --- a/lib/src/providers/api_provider.dart +++ b/lib/src/providers/api_provider.dart @@ -337,6 +337,13 @@ class ApiProvider { return await sendRequestSync(req); } + Future getCurrentLocation() async { + var get = ApplicationData_GetLocation(); + var appData = ApplicationData()..getlocation = get; + var req = createClientToServerFromApplicationData(appData); + return await sendRequestSync(req); + } + Future triggerDownload(List token, int offset) async { var get = ApplicationData_DownloadData() ..downloadToken = token diff --git a/lib/src/views/camera_to_share/share_image_editor_view.dart b/lib/src/views/camera_to_share/share_image_editor_view.dart index 58f8af9..4dc08ef 100644 --- a/lib/src/views/camera_to_share/share_image_editor_view.dart +++ b/lib/src/views/camera_to_share/share_image_editor_view.dart @@ -246,6 +246,8 @@ class _ShareImageEditorView extends State { image: currentImage, )); + layers.add(FilterLayerData()); + setState(() {}); } diff --git a/pubspec.yaml b/pubspec.yaml index d47f6c5..aabea90 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -89,4 +89,7 @@ flutter: - assets/images/onboarding/ricky_the_greedy_racoon.png - assets/animated_icons/ - assets/animations/ + - assets/filters/ + - assets/filters/location/ + - assets/filters/random/