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:provider/provider.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/download_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
Function(bool) globalCallbackConnectionState = (a) {};
bool globalIsAppInBackground = true;
// these two callbacks are called on updated to the corresponding database
Function globalCallBackOnContactChange = () {};
Function(int) globalCallBackOnMessageChange = (a) {};
Future Function(int) globalCallBackOnMessageChange = (a) async {};
Function(List<int>, bool) globalCallBackOnDownloadChange = (a, b) {};
/// The Widget that configures your application.
@ -37,18 +39,14 @@ class MyApp extends StatefulWidget {
}
class _MyAppState extends State<MyApp> with WidgetsBindingObserver {
Future<bool> _isUserCreated = isUserCreated();
bool _showOnboarding = true;
bool _isConnected = false;
int redColorOpacity = 0; // Start with dark red
bool redColorGoUp = true;
bool isConnected = false;
bool wasPaused = false;
@override
void initState() {
super.initState();
globalIsAppInBackground = false;
WidgetsBinding.instance.addObserver(this);
_startColorAnimation();
// init change provider to load data from the database
context.read<ContactChangeProvider>().update();
@ -69,17 +67,23 @@ class _MyAppState extends State<MyApp> with WidgetsBindingObserver {
context.read<DownloadChangeProvider>().update(token, add);
};
globalCallBackOnMessageChange = (userId) {
context.read<MessagesChangeProvider>().updateLastMessageFor(userId);
globalCallBackOnMessageChange = (userId) async {
await context.read<MessagesChangeProvider>().updateLastMessageFor(userId);
};
// connect async to the backend api
apiProvider.connect();
FlutterForegroundTask.addTaskDataCallback(_onReceiveTaskData);
WidgetsBinding.instance.addPostFrameCallback((_) {
_requestPermissions();
_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 {
@ -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() {
FlutterForegroundTask.init(
androidNotificationOptions: AndroidNotificationOptions(
@ -154,18 +147,23 @@ class _MyAppState extends State<MyApp> with WidgetsBindingObserver {
} else {
return FlutterForegroundTask.startService(
serviceId: 256,
notificationTitle: 'Foreground Service is running',
notificationTitle: 'Staying connected to the server.',
notificationText: 'Tap to return to the app',
notificationIcon:
NotificationIcon(metaDataName: "eu.twonly.service.TWONLY_LOGO"),
notificationInitialRoute: '/',
notificationInitialRoute: '/chats',
callback: startCallback,
);
}
}
Future _stopService() async {
FlutterForegroundTask.sendDataToTask("");
await FlutterForegroundTask.stopService();
if (context.mounted) {
context.read<MessagesChangeProvider>().init();
context.read<ContactChangeProvider>().update();
}
if (!apiProvider.isAuthenticated) {
apiProvider.connect();
}
@ -174,11 +172,14 @@ class _MyAppState extends State<MyApp> with WidgetsBindingObserver {
@override
void didChangeAppLifecycleState(AppLifecycleState state) {
super.didChangeAppLifecycleState(state);
print("STATE: $state");
if (state == AppLifecycleState.resumed) {
if (wasPaused) {
globalIsAppInBackground = false;
_stopService();
//apiProvider.connect();
}
} else if (state == AppLifecycleState.paused) {
wasPaused = true;
globalIsAppInBackground = true;
apiProvider.close(() {
_startService();
});
@ -187,41 +188,18 @@ class _MyAppState extends State<MyApp> with WidgetsBindingObserver {
@override
void dispose() {
print("STATE: dispose");
// apiProvider.close(() {});
WidgetsBinding.instance.removeObserver(this);
// disable globalCallbacks to the flutter tree
globalCallbackConnectionState = (a) {};
globalCallBackOnDownloadChange = (a, b) {};
globalCallBackOnContactChange = () {};
globalCallBackOnMessageChange = (a) {};
FlutterForegroundTask.removeTaskDataCallback(_onReceiveTaskData);
globalCallBackOnMessageChange = (a) async {};
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
Widget build(BuildContext context) {
double screenWidth = MediaQuery.of(context).size.width;
// var isConnected = context.watch<ApiProvider>().isConnected;
// Glue the SettingsController to the MaterialApp.
//
@ -256,54 +234,72 @@ class _MyAppState extends State<MyApp> with WidgetsBindingObserver {
const InputDecorationTheme(border: OutlineInputBorder()),
),
themeMode: context.watch<SettingsChangeProvider>().themeMode,
home: Stack(
initialRoute: '/',
routes: {
"/": (context) =>
MyAppMainWidget(isConnected: _isConnected, initialPage: 0),
"/chats": (context) =>
MyAppMainWidget(isConnected: _isConnected, initialPage: 1)
// home: MyAppMainWidget(isConnected: _isConnected, initialPage: 0),
},
);
},
);
}
}
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) {
return snapshot.data!
? HomeView()
: _showOnboarding
? OnboardingView(
if (snapshot.data!) {
return HomeView(initialPage: widget.initialPage);
}
if (_showOnboarding) {
return OnboardingView(
callbackOnSuccess: () {
setState(() {
_showOnboarding = false;
});
},
)
: RegisterView(
);
}
return RegisterView(
callbackOnSuccess: () {
setState(() {
_isUserCreated = isUserCreated();
setState(() {});
});
},
);
} else {
return Container();
return Center(child: 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
),
),
),
if (!widget.isConnected) ConnectionInfo()
],
),
);
},
);
}
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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