mirror of
https://github.com/twonlyapp/twonly-app.git
synced 2026-01-15 12:48:41 +00:00
fix #101 and show when not connected
This commit is contained in:
parent
b6a4cca884
commit
8763313c41
10 changed files with 185 additions and 171 deletions
|
|
@ -4,6 +4,7 @@ import 'package:twonly/globals.dart';
|
||||||
import 'package:twonly/src/database/twonly_database.dart';
|
import 'package:twonly/src/database/twonly_database.dart';
|
||||||
import 'package:twonly/src/providers/api_provider.dart';
|
import 'package:twonly/src/providers/api_provider.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:twonly/src/providers/connection_provider.dart';
|
||||||
import 'package:twonly/src/providers/hive.dart';
|
import 'package:twonly/src/providers/hive.dart';
|
||||||
import 'package:twonly/src/providers/settings_change_provider.dart';
|
import 'package:twonly/src/providers/settings_change_provider.dart';
|
||||||
import 'package:twonly/src/services/fcm_service.dart';
|
import 'package:twonly/src/services/fcm_service.dart';
|
||||||
|
|
@ -34,6 +35,7 @@ void main() async {
|
||||||
MultiProvider(
|
MultiProvider(
|
||||||
providers: [
|
providers: [
|
||||||
ChangeNotifierProvider(create: (_) => settingsController),
|
ChangeNotifierProvider(create: (_) => settingsController),
|
||||||
|
ChangeNotifierProvider(create: (_) => ConnectionChangeProvider()),
|
||||||
],
|
],
|
||||||
child: MyApp(),
|
child: MyApp(),
|
||||||
),
|
),
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
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/connection_provider.dart';
|
||||||
import 'package:twonly/src/providers/settings_change_provider.dart';
|
import 'package:twonly/src/providers/settings_change_provider.dart';
|
||||||
import 'package:twonly/src/services/notification_service.dart';
|
import 'package:twonly/src/services/notification_service.dart';
|
||||||
import 'package:twonly/src/utils/storage.dart';
|
import 'package:twonly/src/utils/storage.dart';
|
||||||
|
|
@ -31,7 +31,6 @@ class MyApp extends StatefulWidget {
|
||||||
}
|
}
|
||||||
|
|
||||||
class _MyAppState extends State<MyApp> with WidgetsBindingObserver {
|
class _MyAppState extends State<MyApp> with WidgetsBindingObserver {
|
||||||
bool _isConnected = false;
|
|
||||||
bool wasPaused = false;
|
bool wasPaused = false;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|
@ -41,60 +40,18 @@ class _MyAppState extends State<MyApp> with WidgetsBindingObserver {
|
||||||
WidgetsBinding.instance.addObserver(this);
|
WidgetsBinding.instance.addObserver(this);
|
||||||
|
|
||||||
// register global callbacks to the widget tree
|
// register global callbacks to the widget tree
|
||||||
globalCallbackConnectionState = (isConnected) {
|
globalCallbackConnectionState = (update) {
|
||||||
setState(() {
|
context.read<ConnectionChangeProvider>().updateConnectionState(update);
|
||||||
_isConnected = isConnected;
|
|
||||||
});
|
|
||||||
setupNotificationWithUsers();
|
setupNotificationWithUsers();
|
||||||
};
|
};
|
||||||
|
|
||||||
// WidgetsBinding.instance.addPostFrameCallback((_) {
|
|
||||||
// _requestPermissions();
|
|
||||||
// _initService();
|
|
||||||
// });
|
|
||||||
initAsync();
|
initAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
Future initAsync() async {
|
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();
|
apiProvider.connect();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Future<void> _requestPermissions() async {
|
|
||||||
// // Android 13+, you need to allow notification permission to display foreground service notification.
|
|
||||||
// //
|
|
||||||
// // iOS: If you need notification, ask for permission.
|
|
||||||
// final NotificationPermission notificationPermission =
|
|
||||||
// await FlutterForegroundTask.checkNotificationPermission();
|
|
||||||
// if (notificationPermission != NotificationPermission.granted) {
|
|
||||||
// await FlutterForegroundTask.requestNotificationPermission();
|
|
||||||
// }
|
|
||||||
|
|
||||||
// if (Platform.isAndroid) {
|
|
||||||
// // Android 12+, there are restrictions on starting a foreground service.
|
|
||||||
// //
|
|
||||||
// // To restart the service on device reboot or unexpected problem, you need to allow below permission.
|
|
||||||
// if (!await FlutterForegroundTask.isIgnoringBatteryOptimizations) {
|
|
||||||
// // This function requires `android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS` permission.
|
|
||||||
// await FlutterForegroundTask.requestIgnoreBatteryOptimization();
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // Use this utility only if you provide services that require long-term survival,
|
|
||||||
// // such as exact alarm service, healthcare service, or Bluetooth communication.
|
|
||||||
// //
|
|
||||||
// // This utility requires the "android.permission.SCHEDULE_EXACT_ALARM" permission.
|
|
||||||
// // Using this permission may make app distribution difficult due to Google policy.
|
|
||||||
// // if (!await FlutterForegroundTask.canScheduleExactAlarms) {
|
|
||||||
// // When you call this function, will be gone to the settings page.
|
|
||||||
// // So you need to explain to the user why set it.
|
|
||||||
// // await FlutterForegroundTask.openAlarmsAndRemindersSettings();
|
|
||||||
// // }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void didChangeAppLifecycleState(AppLifecycleState state) {
|
void didChangeAppLifecycleState(AppLifecycleState state) {
|
||||||
super.didChangeAppLifecycleState(state);
|
super.didChangeAppLifecycleState(state);
|
||||||
|
|
@ -108,11 +65,6 @@ class _MyAppState extends State<MyApp> with WidgetsBindingObserver {
|
||||||
} else if (state == AppLifecycleState.paused) {
|
} else if (state == AppLifecycleState.paused) {
|
||||||
wasPaused = true;
|
wasPaused = true;
|
||||||
globalIsAppInBackground = true;
|
globalIsAppInBackground = true;
|
||||||
|
|
||||||
// apiProvider.close(() {
|
|
||||||
// use this only when uploading an image
|
|
||||||
// _startService();
|
|
||||||
// });
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -165,11 +117,9 @@ class _MyAppState extends State<MyApp> with WidgetsBindingObserver {
|
||||||
themeMode: context.watch<SettingsChangeProvider>().themeMode,
|
themeMode: context.watch<SettingsChangeProvider>().themeMode,
|
||||||
initialRoute: '/',
|
initialRoute: '/',
|
||||||
routes: {
|
routes: {
|
||||||
"/": (context) =>
|
"/": (context) => MyAppMainWidget(initialPage: 0),
|
||||||
MyAppMainWidget(isConnected: _isConnected, initialPage: 0),
|
"/chats": (context) => MyAppMainWidget(initialPage: 1)
|
||||||
"/chats": (context) =>
|
// home: MyAppMainWidget(isConnected: isConnected, initialPage: 0),
|
||||||
MyAppMainWidget(isConnected: _isConnected, initialPage: 1)
|
|
||||||
// home: MyAppMainWidget(isConnected: _isConnected, initialPage: 0),
|
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
@ -178,10 +128,8 @@ class _MyAppState extends State<MyApp> with WidgetsBindingObserver {
|
||||||
}
|
}
|
||||||
|
|
||||||
class MyAppMainWidget extends StatefulWidget {
|
class MyAppMainWidget extends StatefulWidget {
|
||||||
const MyAppMainWidget(
|
const MyAppMainWidget({super.key, required this.initialPage});
|
||||||
{super.key, required this.isConnected, required this.initialPage});
|
|
||||||
|
|
||||||
final bool isConnected;
|
|
||||||
final int initialPage;
|
final int initialPage;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|
@ -201,7 +149,9 @@ class _MyAppMainWidgetState extends State<MyAppMainWidget> {
|
||||||
builder: (context, snapshot) {
|
builder: (context, snapshot) {
|
||||||
if (snapshot.hasData) {
|
if (snapshot.hasData) {
|
||||||
if (snapshot.data!) {
|
if (snapshot.data!) {
|
||||||
return HomeView(initialPage: widget.initialPage);
|
return HomeView(
|
||||||
|
initialPage: widget.initialPage,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_showOnboarding) {
|
if (_showOnboarding) {
|
||||||
|
|
@ -226,7 +176,6 @@ class _MyAppMainWidgetState extends State<MyAppMainWidget> {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
if (!widget.isConnected) ConnectionInfo()
|
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
import 'dart:async';
|
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:twonly/src/utils/misc.dart';
|
||||||
|
|
||||||
class ConnectionInfo extends StatefulWidget {
|
class ConnectionInfo extends StatefulWidget {
|
||||||
const ConnectionInfo({super.key});
|
const ConnectionInfo({super.key});
|
||||||
|
|
@ -9,69 +8,87 @@ class ConnectionInfo extends StatefulWidget {
|
||||||
State<ConnectionInfo> createState() => _ConnectionInfoWidgetState();
|
State<ConnectionInfo> createState() => _ConnectionInfoWidgetState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _ConnectionInfoWidgetState extends State<ConnectionInfo> {
|
class _ConnectionInfoWidgetState extends State<ConnectionInfo>
|
||||||
int redColorOpacity = 100; // Initial opacity value
|
with SingleTickerProviderStateMixin {
|
||||||
bool redColorGoUp = true; // Direction of the opacity change
|
late AnimationController _controller;
|
||||||
double screenWidth = 0; // To hold the screen width
|
late Animation<double> _positionAnim;
|
||||||
|
late Animation<double> _widthAnim;
|
||||||
|
|
||||||
Timer? _colorAnimationTimer;
|
bool showAnimation = false;
|
||||||
|
|
||||||
|
final double minBarWidth = 40;
|
||||||
|
final double maxBarWidth = 150;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
_startColorAnimation();
|
|
||||||
}
|
|
||||||
|
|
||||||
void _startColorAnimation() {
|
_controller = AnimationController(
|
||||||
// Change the color every 200 milliseconds
|
vsync: this,
|
||||||
_colorAnimationTimer = Timer.periodic(Duration(milliseconds: 200), (timer) {
|
duration: const Duration(seconds: 4),
|
||||||
|
);
|
||||||
|
|
||||||
|
_positionAnim = Tween<double>(begin: 0, end: 1).animate(
|
||||||
|
CurvedAnimation(parent: _controller, curve: Curves.easeInOut),
|
||||||
|
);
|
||||||
|
|
||||||
|
_widthAnim = TweenSequence([
|
||||||
|
TweenSequenceItem(
|
||||||
|
tween: Tween<double>(begin: minBarWidth, end: maxBarWidth),
|
||||||
|
weight: 50),
|
||||||
|
TweenSequenceItem(
|
||||||
|
tween: Tween<double>(begin: maxBarWidth, end: minBarWidth),
|
||||||
|
weight: 50),
|
||||||
|
]).animate(CurvedAnimation(parent: _controller, curve: Curves.easeInOut));
|
||||||
|
|
||||||
|
// Delay start by 2 seconds
|
||||||
|
Future.delayed(const Duration(seconds: 2), () {
|
||||||
|
if (mounted) {
|
||||||
|
_controller.repeat(reverse: true);
|
||||||
setState(() {
|
setState(() {
|
||||||
if (redColorOpacity <= 100) {
|
showAnimation = true;
|
||||||
redColorGoUp = true;
|
|
||||||
}
|
|
||||||
if (redColorOpacity >= 150) {
|
|
||||||
redColorGoUp = false;
|
|
||||||
}
|
|
||||||
if (redColorGoUp) {
|
|
||||||
redColorOpacity += 10;
|
|
||||||
} else {
|
|
||||||
redColorOpacity -= 10;
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
_colorAnimationTimer?.cancel();
|
_controller.dispose();
|
||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
screenWidth = MediaQuery.of(context).size.width; // Get the screen width
|
if (!showAnimation) return Container();
|
||||||
|
double screenWidth = MediaQuery.of(context).size.width;
|
||||||
|
|
||||||
|
return SizedBox(
|
||||||
|
width: screenWidth,
|
||||||
|
height: 1,
|
||||||
|
child: AnimatedBuilder(
|
||||||
|
animation: _controller,
|
||||||
|
builder: (context, child) {
|
||||||
|
double barWidth = _widthAnim.value;
|
||||||
|
double left = _positionAnim.value * (screenWidth - barWidth);
|
||||||
return Stack(
|
return Stack(
|
||||||
children: [
|
children: [
|
||||||
Positioned(
|
Positioned(
|
||||||
top: 3, // Position it at the top
|
left: left,
|
||||||
left: (screenWidth * 0.5) / 2, // Center it horizontally
|
top: 0,
|
||||||
child: AnimatedContainer(
|
bottom: 0,
|
||||||
duration: Duration(milliseconds: 100),
|
child: Container(
|
||||||
width: screenWidth * 0.5, // 50% of the screen width
|
width: barWidth,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
border: Border.all(
|
color: context.color.primary,
|
||||||
color: Colors.red[600]!
|
borderRadius: BorderRadius.circular(4),
|
||||||
.withAlpha(redColorOpacity), // Use the animated opacity
|
|
||||||
width: 2.0, // Red border width
|
|
||||||
),
|
|
||||||
borderRadius: BorderRadius.all(
|
|
||||||
Radius.circular(10.0),
|
|
||||||
), // Rounded corners
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -238,8 +238,6 @@ class ImageUploader {
|
||||||
);
|
);
|
||||||
|
|
||||||
if (wasSend.isError) {
|
if (wasSend.isError) {
|
||||||
// await box.put("retransmit-$messageId-offset", 0);
|
|
||||||
// await box.delete("retransmit-$messageId-uploadtoken");
|
|
||||||
Logger("api.dart").shout("error while uploading media");
|
Logger("api.dart").shout("error while uploading media");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -141,13 +141,13 @@ class ApiProvider {
|
||||||
isAuthenticated = false;
|
isAuthenticated = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void _onData(dynamic msgBuffer) {
|
void _onData(dynamic msgBuffer) async {
|
||||||
try {
|
try {
|
||||||
final msg = server.ServerToClient.fromBuffer(msgBuffer);
|
final msg = server.ServerToClient.fromBuffer(msgBuffer);
|
||||||
if (msg.v0.hasResponse()) {
|
if (msg.v0.hasResponse()) {
|
||||||
messagesV0[msg.v0.seq] = msg;
|
messagesV0[msg.v0.seq] = msg;
|
||||||
} else {
|
} else {
|
||||||
handleServerMessage(msg);
|
await handleServerMessage(msg);
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
log.shout("Error parsing the servers message: $e");
|
log.shout("Error parsing the servers message: $e");
|
||||||
|
|
|
||||||
10
lib/src/providers/connection_provider.dart
Normal file
10
lib/src/providers/connection_provider.dart
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
|
|
||||||
|
class ConnectionChangeProvider with ChangeNotifier, DiagnosticableTreeMixin {
|
||||||
|
bool _isConnected = false;
|
||||||
|
bool get isConnected => _isConnected;
|
||||||
|
Future<void> updateConnectionState(bool update) async {
|
||||||
|
_isConnected = update;
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -19,6 +19,7 @@ import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||||
extension ShortCutsExtension on BuildContext {
|
extension ShortCutsExtension on BuildContext {
|
||||||
AppLocalizations get lang => AppLocalizations.of(this)!;
|
AppLocalizations get lang => AppLocalizations.of(this)!;
|
||||||
TwonlyDatabase get db => Provider.of<TwonlyDatabase>(this);
|
TwonlyDatabase get db => Provider.of<TwonlyDatabase>(this);
|
||||||
|
ColorScheme get color => Theme.of(this).colorScheme;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> writeLogToFile(LogRecord record) async {
|
Future<void> writeLogToFile(LogRecord record) async {
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,9 @@
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
import 'package:font_awesome_flutter/font_awesome_flutter.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/components/flame.dart';
|
import 'package:twonly/src/components/flame.dart';
|
||||||
import 'package:twonly/src/components/initialsavatar.dart';
|
import 'package:twonly/src/components/initialsavatar.dart';
|
||||||
import 'package:twonly/src/components/message_send_state_icon.dart';
|
import 'package:twonly/src/components/message_send_state_icon.dart';
|
||||||
|
|
@ -12,6 +14,7 @@ import 'package:twonly/src/database/twonly_database.dart';
|
||||||
import 'package:twonly/src/database/tables/messages_table.dart';
|
import 'package:twonly/src/database/tables/messages_table.dart';
|
||||||
import 'package:twonly/src/json_models/message.dart';
|
import 'package:twonly/src/json_models/message.dart';
|
||||||
import 'package:twonly/src/providers/api/media.dart';
|
import 'package:twonly/src/providers/api/media.dart';
|
||||||
|
import 'package:twonly/src/providers/connection_provider.dart';
|
||||||
import 'package:twonly/src/utils/misc.dart';
|
import 'package:twonly/src/utils/misc.dart';
|
||||||
import 'package:twonly/src/views/camera_to_share/share_image_view.dart';
|
import 'package:twonly/src/views/camera_to_share/share_image_view.dart';
|
||||||
import 'package:twonly/src/views/chats/chat_item_details_view.dart';
|
import 'package:twonly/src/views/chats/chat_item_details_view.dart';
|
||||||
|
|
@ -31,6 +34,7 @@ class ChatListView extends StatefulWidget {
|
||||||
class _ChatListViewState extends State<ChatListView> {
|
class _ChatListViewState extends State<ChatListView> {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
bool isConnected = context.watch<ConnectionChangeProvider>().isConnected;
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: Text("twonly"),
|
title: Text("twonly"),
|
||||||
|
|
@ -71,7 +75,16 @@ class _ChatListViewState extends State<ChatListView> {
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
body: StreamBuilder(
|
body: Stack(
|
||||||
|
children: [
|
||||||
|
Positioned(
|
||||||
|
top: 0,
|
||||||
|
left: 0,
|
||||||
|
right: 0,
|
||||||
|
child: isConnected ? Container() : ConnectionInfo(),
|
||||||
|
),
|
||||||
|
Positioned.fill(
|
||||||
|
child: StreamBuilder(
|
||||||
stream: twonlyDatabase.contactsDao.watchContactsForChatList(),
|
stream: twonlyDatabase.contactsDao.watchContactsForChatList(),
|
||||||
builder: (context, snapshot) {
|
builder: (context, snapshot) {
|
||||||
if (!snapshot.hasData || snapshot.data == null) {
|
if (!snapshot.hasData || snapshot.data == null) {
|
||||||
|
|
@ -93,7 +106,8 @@ class _ChatListViewState extends State<ChatListView> {
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
label: Text(context.lang.chatListViewSearchUserNameBtn)),
|
label:
|
||||||
|
Text(context.lang.chatListViewSearchUserNameBtn)),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -126,6 +140,9 @@ class _ChatListViewState extends State<ChatListView> {
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
floatingActionButton: Padding(
|
floatingActionButton: Padding(
|
||||||
padding: const EdgeInsets.only(bottom: 30.0),
|
padding: const EdgeInsets.only(bottom: 30.0),
|
||||||
child: FloatingActionButton(
|
child: FloatingActionButton(
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
import 'package:drift/drift.dart' hide Column;
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
||||||
import 'package:pie_menu/pie_menu.dart';
|
import 'package:pie_menu/pie_menu.dart';
|
||||||
|
|
@ -34,6 +35,8 @@ class _StartNewChat extends State<StartNewChat> {
|
||||||
twonlyDatabase.contactsDao.watchContactsForShareView();
|
twonlyDatabase.contactsDao.watchContactsForShareView();
|
||||||
|
|
||||||
contactSub = stream.listen((update) {
|
contactSub = stream.listen((update) {
|
||||||
|
update.sort((a, b) =>
|
||||||
|
getContactDisplayName(a).compareTo(getContactDisplayName(b)));
|
||||||
setState(() {
|
setState(() {
|
||||||
allContacts = update;
|
allContacts = update;
|
||||||
});
|
});
|
||||||
|
|
@ -83,6 +86,7 @@ class _StartNewChat extends State<StartNewChat> {
|
||||||
onChanged: (_) {
|
onChanged: (_) {
|
||||||
filterUsers();
|
filterUsers();
|
||||||
},
|
},
|
||||||
|
controller: searchUserName,
|
||||||
decoration: getInputDecoration(
|
decoration: getInputDecoration(
|
||||||
context,
|
context,
|
||||||
context.lang.shareImageSearchAllContacts,
|
context.lang.shareImageSearchAllContacts,
|
||||||
|
|
@ -116,21 +120,18 @@ class UserList extends StatelessWidget {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
// Step 1: Sort the users alphabetically
|
|
||||||
users
|
|
||||||
.sort((a, b) => b.lastMessageExchange.compareTo(a.lastMessageExchange));
|
|
||||||
|
|
||||||
return ListView.builder(
|
return ListView.builder(
|
||||||
restorationId: 'new_message_users_list',
|
restorationId: 'new_message_users_list',
|
||||||
itemCount: users.length + 2,
|
itemCount: users.length + 2,
|
||||||
itemBuilder: (BuildContext context, int i) {
|
itemBuilder: (BuildContext context, int i) {
|
||||||
if (i == 0) {
|
if (i == 0) {
|
||||||
return ListTile(
|
return ListTile(
|
||||||
|
key: Key("add_new_contact"),
|
||||||
title: Text(context.lang.startNewChatNewContact),
|
title: Text(context.lang.startNewChatNewContact),
|
||||||
leading: CircleAvatar(
|
leading: CircleAvatar(
|
||||||
child: FaIcon(
|
child: FaIcon(
|
||||||
FontAwesomeIcons.userPlus,
|
FontAwesomeIcons.userPlus,
|
||||||
size: 15,
|
size: 13,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
|
|
@ -144,17 +145,17 @@ class UserList extends StatelessWidget {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (i == 1) {
|
if (i == 1) {
|
||||||
return HeadLineComponent(context.lang.startNewChatYourContacts);
|
return Divider();
|
||||||
}
|
}
|
||||||
Contact user = users[i - 2];
|
Contact user = users[i - 2];
|
||||||
int flameCounter = getFlameCounterFromContact(user);
|
int flameCounter = getFlameCounterFromContact(user);
|
||||||
return UserContextMenu(
|
return UserContextMenu(
|
||||||
|
key: Key(user.userId.toString()),
|
||||||
contact: user,
|
contact: user,
|
||||||
child: ListTile(
|
child: ListTile(
|
||||||
title: Row(
|
title: Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.start, // Center horizontally
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
crossAxisAlignment:
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
CrossAxisAlignment.center, // Center vertically
|
|
||||||
children: [
|
children: [
|
||||||
Text(getContactDisplayName(user)),
|
Text(getContactDisplayName(user)),
|
||||||
if (flameCounter >= 1)
|
if (flameCounter >= 1)
|
||||||
|
|
@ -164,9 +165,25 @@ class UserList extends StatelessWidget {
|
||||||
maxTotalMediaCounter,
|
maxTotalMediaCounter,
|
||||||
prefix: true,
|
prefix: true,
|
||||||
),
|
),
|
||||||
|
Spacer(),
|
||||||
|
IconButton(
|
||||||
|
icon: FaIcon(FontAwesomeIcons.boxOpen,
|
||||||
|
size: 13,
|
||||||
|
color: user.archived ? null : Colors.transparent),
|
||||||
|
onPressed: user.archived
|
||||||
|
? () async {
|
||||||
|
final update =
|
||||||
|
ContactsCompanion(archived: Value(false));
|
||||||
|
await twonlyDatabase.contactsDao
|
||||||
|
.updateContact(user.userId, update);
|
||||||
|
}
|
||||||
|
: null)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
leading: ContactAvatar(contact: user),
|
leading: ContactAvatar(
|
||||||
|
contact: user,
|
||||||
|
fontSize: 13,
|
||||||
|
),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
Navigator.pushReplacement(
|
Navigator.pushReplacement(
|
||||||
context,
|
context,
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,10 @@ 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, required this.initialPage});
|
const HomeView({
|
||||||
|
super.key,
|
||||||
|
required this.initialPage,
|
||||||
|
});
|
||||||
final int initialPage;
|
final int initialPage;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue