some bug fixes

This commit is contained in:
otsmr 2025-02-09 21:01:01 +01:00
parent 84448f79ca
commit 20a8f0faa3
7 changed files with 123 additions and 106 deletions

View file

@ -2,6 +2,7 @@ import 'dart:io';
import 'package:flutter_foreground_task/flutter_foreground_task.dart'; import 'package:flutter_foreground_task/flutter_foreground_task.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:twonly/globals.dart'; import 'package:twonly/globals.dart';
import 'package:twonly/src/components/connection_state.dart';
import 'package:twonly/src/providers/contacts_change_provider.dart'; import 'package:twonly/src/providers/contacts_change_provider.dart';
import 'package:twonly/src/providers/download_change_provider.dart'; import 'package:twonly/src/providers/download_change_provider.dart';
import 'package:twonly/src/providers/messages_change_provider.dart'; import 'package:twonly/src/providers/messages_change_provider.dart';
@ -22,10 +23,11 @@ import 'dart:async';
// this callback is called by the apiProvider // this callback is called by the apiProvider
Function(bool) globalCallbackConnectionState = (a) {}; Function(bool) globalCallbackConnectionState = (a) {};
bool globalIsAppInBackground = true;
// these two callbacks are called on updated to the corresponding database // these two callbacks are called on updated to the corresponding database
Function globalCallBackOnContactChange = () {}; Function globalCallBackOnContactChange = () {};
Function(int) globalCallBackOnMessageChange = (a) {}; Future Function(int) globalCallBackOnMessageChange = (a) async {};
Function(List<int>, bool) globalCallBackOnDownloadChange = (a, b) {}; Function(List<int>, bool) globalCallBackOnDownloadChange = (a, b) {};
/// The Widget that configures your application. /// The Widget that configures your application.
@ -37,18 +39,14 @@ class MyApp extends StatefulWidget {
} }
class _MyAppState extends State<MyApp> with WidgetsBindingObserver { class _MyAppState extends State<MyApp> with WidgetsBindingObserver {
Future<bool> _isUserCreated = isUserCreated();
bool _showOnboarding = true;
bool _isConnected = false; bool _isConnected = false;
int redColorOpacity = 0; // Start with dark red bool wasPaused = false;
bool redColorGoUp = true;
bool isConnected = false;
@override @override
void initState() { void initState() {
super.initState(); super.initState();
globalIsAppInBackground = false;
WidgetsBinding.instance.addObserver(this); WidgetsBinding.instance.addObserver(this);
_startColorAnimation();
// init change provider to load data from the database // init change provider to load data from the database
context.read<ContactChangeProvider>().update(); context.read<ContactChangeProvider>().update();
@ -69,17 +67,23 @@ class _MyAppState extends State<MyApp> with WidgetsBindingObserver {
context.read<DownloadChangeProvider>().update(token, add); context.read<DownloadChangeProvider>().update(token, add);
}; };
globalCallBackOnMessageChange = (userId) { globalCallBackOnMessageChange = (userId) async {
context.read<MessagesChangeProvider>().updateLastMessageFor(userId); await context.read<MessagesChangeProvider>().updateLastMessageFor(userId);
}; };
// connect async to the backend api
apiProvider.connect();
FlutterForegroundTask.addTaskDataCallback(_onReceiveTaskData);
WidgetsBinding.instance.addPostFrameCallback((_) { WidgetsBinding.instance.addPostFrameCallback((_) {
_requestPermissions(); _requestPermissions();
_initService(); _initService();
}); });
initAsync();
}
Future initAsync() async {
// make sure the front end service will be killed
FlutterForegroundTask.sendDataToTask("");
await FlutterForegroundTask.stopService();
// connect async to the backend api
apiProvider.connect();
} }
Future<void> _requestPermissions() async { Future<void> _requestPermissions() async {
@ -114,17 +118,6 @@ class _MyAppState extends State<MyApp> with WidgetsBindingObserver {
} }
} }
void _onReceiveTaskData(Object data) {
if (data is Map<String, dynamic>) {
final dynamic timestampMillis = data["timestampMillis"];
if (timestampMillis != null) {
final DateTime timestamp =
DateTime.fromMillisecondsSinceEpoch(timestampMillis, isUtc: true);
print('timestamp: ${timestamp.toString()}');
}
}
}
void _initService() { void _initService() {
FlutterForegroundTask.init( FlutterForegroundTask.init(
androidNotificationOptions: AndroidNotificationOptions( androidNotificationOptions: AndroidNotificationOptions(
@ -154,18 +147,23 @@ class _MyAppState extends State<MyApp> with WidgetsBindingObserver {
} else { } else {
return FlutterForegroundTask.startService( return FlutterForegroundTask.startService(
serviceId: 256, serviceId: 256,
notificationTitle: 'Foreground Service is running', notificationTitle: 'Staying connected to the server.',
notificationText: 'Tap to return to the app', notificationText: 'Tap to return to the app',
notificationIcon: notificationIcon:
NotificationIcon(metaDataName: "eu.twonly.service.TWONLY_LOGO"), NotificationIcon(metaDataName: "eu.twonly.service.TWONLY_LOGO"),
notificationInitialRoute: '/', notificationInitialRoute: '/chats',
callback: startCallback, callback: startCallback,
); );
} }
} }
Future _stopService() async { Future _stopService() async {
FlutterForegroundTask.sendDataToTask("");
await FlutterForegroundTask.stopService(); await FlutterForegroundTask.stopService();
if (context.mounted) {
context.read<MessagesChangeProvider>().init();
context.read<ContactChangeProvider>().update();
}
if (!apiProvider.isAuthenticated) { if (!apiProvider.isAuthenticated) {
apiProvider.connect(); apiProvider.connect();
} }
@ -174,11 +172,14 @@ class _MyAppState extends State<MyApp> with WidgetsBindingObserver {
@override @override
void didChangeAppLifecycleState(AppLifecycleState state) { void didChangeAppLifecycleState(AppLifecycleState state) {
super.didChangeAppLifecycleState(state); super.didChangeAppLifecycleState(state);
print("STATE: $state");
if (state == AppLifecycleState.resumed) { if (state == AppLifecycleState.resumed) {
_stopService(); if (wasPaused) {
//apiProvider.connect(); globalIsAppInBackground = false;
_stopService();
}
} else if (state == AppLifecycleState.paused) { } else if (state == AppLifecycleState.paused) {
wasPaused = true;
globalIsAppInBackground = true;
apiProvider.close(() { apiProvider.close(() {
_startService(); _startService();
}); });
@ -187,41 +188,18 @@ class _MyAppState extends State<MyApp> with WidgetsBindingObserver {
@override @override
void dispose() { void dispose() {
print("STATE: dispose");
// apiProvider.close(() {}); // apiProvider.close(() {});
WidgetsBinding.instance.removeObserver(this); WidgetsBinding.instance.removeObserver(this);
// disable globalCallbacks to the flutter tree // disable globalCallbacks to the flutter tree
globalCallbackConnectionState = (a) {}; globalCallbackConnectionState = (a) {};
globalCallBackOnDownloadChange = (a, b) {}; globalCallBackOnDownloadChange = (a, b) {};
globalCallBackOnContactChange = () {}; globalCallBackOnContactChange = () {};
globalCallBackOnMessageChange = (a) {}; globalCallBackOnMessageChange = (a) async {};
FlutterForegroundTask.removeTaskDataCallback(_onReceiveTaskData);
super.dispose(); super.dispose();
} }
void _startColorAnimation() {
// Change the color every second
Future.delayed(Duration(milliseconds: 200), () {
setState(() {
if (redColorOpacity <= 100) {
redColorGoUp = true;
}
if (redColorOpacity >= 150) {
redColorGoUp = false;
}
if (redColorGoUp) {
redColorOpacity += 10;
} else {
redColorOpacity -= 10;
}
});
_startColorAnimation(); // Repeat the animation
});
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
double screenWidth = MediaQuery.of(context).size.width;
// var isConnected = context.watch<ApiProvider>().isConnected; // var isConnected = context.watch<ApiProvider>().isConnected;
// Glue the SettingsController to the MaterialApp. // Glue the SettingsController to the MaterialApp.
// //
@ -256,54 +234,72 @@ class _MyAppState extends State<MyApp> with WidgetsBindingObserver {
const InputDecorationTheme(border: OutlineInputBorder()), const InputDecorationTheme(border: OutlineInputBorder()),
), ),
themeMode: context.watch<SettingsChangeProvider>().themeMode, themeMode: context.watch<SettingsChangeProvider>().themeMode,
home: Stack( initialRoute: '/',
children: [ routes: {
FutureBuilder<bool>( "/": (context) =>
future: _isUserCreated, MyAppMainWidget(isConnected: _isConnected, initialPage: 0),
builder: (context, snapshot) { "/chats": (context) =>
if (snapshot.hasData) { MyAppMainWidget(isConnected: _isConnected, initialPage: 1)
return snapshot.data! // home: MyAppMainWidget(isConnected: _isConnected, initialPage: 0),
? HomeView() },
: _showOnboarding
? OnboardingView(
callbackOnSuccess: () {
setState(() {
_showOnboarding = false;
});
},
)
: RegisterView(
callbackOnSuccess: () {
_isUserCreated = isUserCreated();
setState(() {});
},
);
} else {
return Container();
}
},
),
if (!_isConnected)
Positioned(
top: 3, // Position it at the top
left: (screenWidth * 0.5) / 2, // Center it horizontally
child: AnimatedContainer(
duration: Duration(milliseconds: 100),
width: screenWidth * 0.5, // 50% of the screen width
decoration: BoxDecoration(
border: Border.all(
color: Colors.red[600]!.withAlpha(redColorOpacity),
width: 2.0), // Red border
borderRadius: BorderRadius.all(
Radius.circular(10.0),
), // Rounded top corners
),
),
),
],
),
); );
}, },
); );
} }
} }
class MyAppMainWidget extends StatefulWidget {
const MyAppMainWidget(
{super.key, required this.isConnected, required this.initialPage});
final bool isConnected;
final int initialPage;
@override
State<MyAppMainWidget> createState() => _MyAppMainWidgetState();
}
class _MyAppMainWidgetState extends State<MyAppMainWidget> {
Future<bool> _isUserCreated =
isUserCreated(); // Assume this is a function that checks if the user is created
bool _showOnboarding = true; // Initial state for onboarding
@override
Widget build(BuildContext context) {
return Stack(
children: [
FutureBuilder<bool>(
future: _isUserCreated,
builder: (context, snapshot) {
if (snapshot.hasData) {
if (snapshot.data!) {
return HomeView(initialPage: widget.initialPage);
}
if (_showOnboarding) {
return OnboardingView(
callbackOnSuccess: () {
setState(() {
_showOnboarding = false;
});
},
);
}
return RegisterView(
callbackOnSuccess: () {
setState(() {
_isUserCreated = isUserCreated();
});
},
);
} else {
return Center(child: Container());
}
},
),
if (!widget.isConnected) ConnectionInfo()
],
);
}
}

View file

@ -1,3 +1,5 @@
import 'dart:async';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
class ConnectionInfo extends StatefulWidget { class ConnectionInfo extends StatefulWidget {
@ -12,6 +14,8 @@ class _ConnectionInfoWidgetState extends State<ConnectionInfo> {
bool redColorGoUp = true; // Direction of the opacity change bool redColorGoUp = true; // Direction of the opacity change
double screenWidth = 0; // To hold the screen width double screenWidth = 0; // To hold the screen width
Timer? _colorAnimationTimer;
@override @override
void initState() { void initState() {
super.initState(); super.initState();
@ -20,7 +24,7 @@ class _ConnectionInfoWidgetState extends State<ConnectionInfo> {
void _startColorAnimation() { void _startColorAnimation() {
// Change the color every 200 milliseconds // Change the color every 200 milliseconds
Future.delayed(Duration(milliseconds: 200), () { _colorAnimationTimer = Timer.periodic(Duration(milliseconds: 200), (timer) {
setState(() { setState(() {
if (redColorOpacity <= 100) { if (redColorOpacity <= 100) {
redColorGoUp = true; redColorGoUp = true;
@ -34,10 +38,15 @@ class _ConnectionInfoWidgetState extends State<ConnectionInfo> {
redColorOpacity -= 10; redColorOpacity -= 10;
} }
}); });
_startColorAnimation(); // Repeat the animation
}); });
} }
@override
void dispose() {
_colorAnimationTimer?.cancel();
super.dispose();
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
screenWidth = MediaQuery.of(context).size.width; // Get the screen width screenWidth = MediaQuery.of(context).size.width; // Get the screen width

View file

@ -181,7 +181,7 @@ class DbMessages extends CvModelBase {
globalCallBackOnMessageChange(userIdFrom); globalCallBackOnMessageChange(userIdFrom);
return messageId; return messageId;
} catch (e) { } catch (e) {
Logger("contacts_model/getUsers").shout("$e"); Logger("messsage_model/insertMyMessage").shout("$e");
return null; return null;
} }
} }
@ -202,7 +202,7 @@ class DbMessages extends CvModelBase {
globalCallBackOnMessageChange(userIdFrom); globalCallBackOnMessageChange(userIdFrom);
return messageId; return messageId;
} catch (e) { } catch (e) {
Logger("contacts_model/getUsers").shout("$e"); Logger("messsage_model/insertOtherMessage").shout("$e");
return null; return null;
} }
} }

View file

@ -105,7 +105,7 @@ Future<client.Response> handleDownloadData(DownloadData data) async {
} }
box.delete(boxId); box.delete(boxId);
globalCallBackOnMessageChange(fromUserId); await globalCallBackOnMessageChange(fromUserId);
globalCallBackOnDownloadChange(data.uploadToken, false); globalCallBackOnDownloadChange(data.uploadToken, false);
} }
} else { } else {
@ -187,6 +187,9 @@ Future<client.Response> handleNewMessage(
List<int> downloadToken = content.downloadToken; List<int> downloadToken = content.downloadToken;
Box box = await getMediaStorage(); Box box = await getMediaStorage();
box.put("${downloadToken}_fromUserId", fromUserId.toInt()); box.put("${downloadToken}_fromUserId", fromUserId.toInt());
if (box.get("${downloadToken}_fromUserId") == null) {
debugPrint("BOX IS NOT WORKING");
}
tryDownloadMedia(messageId, downloadToken); tryDownloadMedia(messageId, downloadToken);
} }
} }

View file

@ -14,7 +14,7 @@ class MessagesChangeProvider with ChangeNotifier, DiagnosticableTreeMixin {
Map<int, int> get changeCounter => _changeCounter; Map<int, int> get changeCounter => _changeCounter;
Map<int, int> get flamesCounter => _flamesCounter; Map<int, int> get flamesCounter => _flamesCounter;
void updateLastMessageFor(int targetUserId) async { Future updateLastMessageFor(int targetUserId) async {
DbMessage? last = DbMessage? last =
await DbMessages.getLastMessagesForPreviewForUser(targetUserId); await DbMessages.getLastMessagesForPreviewForUser(targetUserId);
if (last != null) { if (last != null) {

View file

@ -123,6 +123,7 @@ class _ShareImageView extends State<ShareImageView> {
} else { } else {
_selectedUserIds.remove(userId); _selectedUserIds.remove(userId);
} }
setState(() {});
} }
@override @override

View file

@ -7,7 +7,8 @@ import 'package:flutter/material.dart';
Function(int) globalUpdateOfHomeViewPageIndex = (a) {}; Function(int) globalUpdateOfHomeViewPageIndex = (a) {};
class HomeView extends StatefulWidget { class HomeView extends StatefulWidget {
const HomeView({super.key}); const HomeView({super.key, required this.initialPage});
final int initialPage;
@override @override
State<HomeView> createState() => HomeViewState(); State<HomeView> createState() => HomeViewState();
@ -15,11 +16,13 @@ class HomeView extends StatefulWidget {
class HomeViewState extends State<HomeView> { class HomeViewState extends State<HomeView> {
int activePageIdx = 0; int activePageIdx = 0;
final PageController homeViewPageController = PageController(initialPage: 0); late PageController homeViewPageController;
@override @override
void initState() { void initState() {
super.initState(); super.initState();
activePageIdx = widget.initialPage;
homeViewPageController = PageController(initialPage: widget.initialPage);
globalUpdateOfHomeViewPageIndex = (index) { globalUpdateOfHomeViewPageIndex = (index) {
homeViewPageController.jumpToPage(index); homeViewPageController.jumpToPage(index);
setState(() { setState(() {
@ -32,6 +35,7 @@ class HomeViewState extends State<HomeView> {
void dispose() { void dispose() {
// disable globalCallbacks to the flutter tree // disable globalCallbacks to the flutter tree
globalUpdateOfHomeViewPageIndex = (a) {}; globalUpdateOfHomeViewPageIndex = (a) {};
//homeViewPageController.dispose();
super.dispose(); super.dispose();
} }
@ -64,6 +68,7 @@ class HomeViewState extends State<HomeView> {
controller: homeViewPageController, controller: homeViewPageController,
onPageChanged: (index) { onPageChanged: (index) {
activePageIdx = index; activePageIdx = index;
setState(() {});
}, },
children: [ children: [
CameraPreviewViewPermission(), CameraPreviewViewPermission(),
@ -73,6 +78,9 @@ class HomeViewState extends State<HomeView> {
bottomNavigationBar: BottomNavigationBar( bottomNavigationBar: BottomNavigationBar(
showSelectedLabels: false, showSelectedLabels: false,
showUnselectedLabels: false, showUnselectedLabels: false,
unselectedIconTheme: IconThemeData(
color:
Theme.of(context).colorScheme.inverseSurface.withAlpha(150)),
selectedIconTheme: IconThemeData( selectedIconTheme: IconThemeData(
color: Theme.of(context).colorScheme.inverseSurface), color: Theme.of(context).colorScheme.inverseSurface),
items: [ items: [