add filters
BIN
assets/filters/location/germany.png
Normal file
|
After Width: | Height: | Size: 167 KiB |
BIN
assets/filters/location/germany_frankfurt_am_main.png
Normal file
|
After Width: | Height: | Size: 8.4 KiB |
BIN
assets/filters/random/avocardio.png
Normal file
|
After Width: | Height: | Size: 117 KiB |
BIN
assets/filters/random/chillen.png
Normal file
|
After Width: | Height: | Size: 121 KiB |
BIN
assets/filters/random/duck.png
Normal file
|
After Width: | Height: | Size: 39 KiB |
BIN
assets/filters/random/hide_the_pain.png
Normal file
|
After Width: | Height: | Size: 178 KiB |
BIN
assets/filters/random/lol.png
Normal file
|
After Width: | Height: | Size: 42 KiB |
BIN
assets/filters/random/yolo.png
Normal file
|
After Width: | Height: | Size: 59 KiB |
|
|
@ -32,6 +32,8 @@ class BackgroundLayerData extends Layer {
|
|||
});
|
||||
}
|
||||
|
||||
class FilterLayerData extends Layer {}
|
||||
|
||||
/// Attributes used by [EmojiLayer]
|
||||
class EmojiLayerData extends Layer {
|
||||
String text;
|
||||
|
|
|
|||
81
lib/src/components/image_editor/layers/filter_layer.dart
Normal file
|
|
@ -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<FilterLayer> 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<FilterLayer> {
|
||||
@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"),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -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),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -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,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -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<LocationFilter> createState() => _LocationFilterState();
|
||||
}
|
||||
|
||||
Map<String, String> cities = {
|
||||
"Frankfurt am Main": "germany_frankfurt_am_main.png",
|
||||
};
|
||||
|
||||
Map<String, String> countries = {
|
||||
"Germany": "germany.png",
|
||||
};
|
||||
|
||||
class _LocationFilterState extends State<LocationFilter> {
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
|
@ -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<FilterLayerData>().map((layerItem) {
|
||||
return FilterLayer(
|
||||
layerData: layerItem,
|
||||
);
|
||||
}),
|
||||
...layers
|
||||
.where((layerItem) =>
|
||||
layerItem is EmojiLayerData || layerItem is DrawLayerData)
|
||||
|
|
|
|||
|
|
@ -56,7 +56,8 @@ class ContactsDao extends DatabaseAccessor<TwonlyDatabase>
|
|||
// 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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -337,6 +337,13 @@ class ApiProvider {
|
|||
return await sendRequestSync(req);
|
||||
}
|
||||
|
||||
Future<Result> getCurrentLocation() async {
|
||||
var get = ApplicationData_GetLocation();
|
||||
var appData = ApplicationData()..getlocation = get;
|
||||
var req = createClientToServerFromApplicationData(appData);
|
||||
return await sendRequestSync(req);
|
||||
}
|
||||
|
||||
Future<Result> triggerDownload(List<int> token, int offset) async {
|
||||
var get = ApplicationData_DownloadData()
|
||||
..downloadToken = token
|
||||
|
|
|
|||
|
|
@ -246,6 +246,8 @@ class _ShareImageEditorView extends State<ShareImageEditorView> {
|
|||
image: currentImage,
|
||||
));
|
||||
|
||||
layers.add(FilterLayerData());
|
||||
|
||||
setState(() {});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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/
|
||||
|
||||
|
|
|
|||