mirror of
https://github.com/twonlyapp/twonly-app.git
synced 2026-05-25 03:42:13 +00:00
bug fixes
This commit is contained in:
parent
a7d64a2307
commit
dcca2cbec0
8 changed files with 82 additions and 92 deletions
85
lib/app.dart
85
lib/app.dart
|
|
@ -7,10 +7,8 @@ import 'package:provider/provider.dart';
|
||||||
import 'package:twonly/globals.dart';
|
import 'package:twonly/globals.dart';
|
||||||
import 'package:twonly/locator.dart';
|
import 'package:twonly/locator.dart';
|
||||||
import 'package:twonly/src/localization/generated/app_localizations.dart';
|
import 'package:twonly/src/localization/generated/app_localizations.dart';
|
||||||
import 'package:twonly/src/providers/purchases.provider.dart';
|
|
||||||
import 'package:twonly/src/providers/routing.provider.dart';
|
import 'package:twonly/src/providers/routing.provider.dart';
|
||||||
import 'package:twonly/src/providers/settings.provider.dart';
|
import 'package:twonly/src/providers/settings.provider.dart';
|
||||||
import 'package:twonly/src/services/subscription.service.dart';
|
|
||||||
import 'package:twonly/src/utils/log.dart';
|
import 'package:twonly/src/utils/log.dart';
|
||||||
import 'package:twonly/src/utils/pow.dart';
|
import 'package:twonly/src/utils/pow.dart';
|
||||||
import 'package:twonly/src/visual/components/app_outdated.comp.dart';
|
import 'package:twonly/src/visual/components/app_outdated.comp.dart';
|
||||||
|
|
@ -24,54 +22,33 @@ import 'package:twonly/src/visual/views/settings/backup/backup_setup.view.dart';
|
||||||
import 'package:twonly/src/visual/views/unlock_twonly.view.dart';
|
import 'package:twonly/src/visual/views/unlock_twonly.view.dart';
|
||||||
|
|
||||||
class App extends StatefulWidget {
|
class App extends StatefulWidget {
|
||||||
const App({super.key});
|
const App({required this.storageError, super.key});
|
||||||
|
final bool storageError;
|
||||||
@override
|
@override
|
||||||
State<App> createState() => _AppState();
|
State<App> createState() => _AppState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _AppState extends State<App> with WidgetsBindingObserver {
|
class _AppState extends State<App> with WidgetsBindingObserver {
|
||||||
bool wasPaused = false;
|
bool _wasPaused = false;
|
||||||
Object? _storageError;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
AppState.isAppInBackground = false;
|
AppState.isAppInBackground = false;
|
||||||
WidgetsBinding.instance.addObserver(this);
|
WidgetsBinding.instance.addObserver(this);
|
||||||
|
|
||||||
unawaited(initAsync());
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> initAsync() async {
|
|
||||||
try {
|
|
||||||
if (userService.isUserCreated && mounted) {
|
|
||||||
context.read<PurchasesProvider>().updatePlan(
|
|
||||||
planFromString(userService.currentUser.subscriptionPlan),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
Log.error('Storage error in App.initAsync: $e');
|
|
||||||
if (mounted) {
|
|
||||||
setState(() {
|
|
||||||
_storageError = e;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
await apiService.connect();
|
|
||||||
await apiService.listenToNetworkChanges();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void didChangeAppLifecycleState(AppLifecycleState state) {
|
void didChangeAppLifecycleState(AppLifecycleState state) {
|
||||||
super.didChangeAppLifecycleState(state);
|
super.didChangeAppLifecycleState(state);
|
||||||
if (state == AppLifecycleState.resumed) {
|
if (state == AppLifecycleState.resumed) {
|
||||||
if (wasPaused) {
|
if (_wasPaused) {
|
||||||
AppState.isAppInBackground = false;
|
AppState.isAppInBackground = false;
|
||||||
twonlyDB.markUpdated();
|
twonlyDB.markUpdated();
|
||||||
unawaited(apiService.connect());
|
unawaited(apiService.connect());
|
||||||
}
|
}
|
||||||
} else if (state == AppLifecycleState.paused) {
|
} else if (state == AppLifecycleState.paused) {
|
||||||
wasPaused = true;
|
_wasPaused = true;
|
||||||
AppState.isAppInBackground = true;
|
AppState.isAppInBackground = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -85,7 +62,7 @@ class _AppState extends State<App> with WidgetsBindingObserver {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return ListenableBuilder(
|
return ListenableBuilder(
|
||||||
listenable: context.watch<SettingsChangeProvider>(),
|
listenable: context.read<SettingsChangeProvider>(),
|
||||||
builder: (context, child) {
|
builder: (context, child) {
|
||||||
const localizationsDelegates = [
|
const localizationsDelegates = [
|
||||||
AppLocalizations.delegate,
|
AppLocalizations.delegate,
|
||||||
|
|
@ -99,7 +76,7 @@ class _AppState extends State<App> with WidgetsBindingObserver {
|
||||||
Locale('de', ''),
|
Locale('de', ''),
|
||||||
];
|
];
|
||||||
|
|
||||||
if (_storageError != null) {
|
if (widget.storageError) {
|
||||||
return MaterialApp(
|
return MaterialApp(
|
||||||
scaffoldMessengerKey: AppGlobalKeys.scaffoldMessengerKey,
|
scaffoldMessengerKey: AppGlobalKeys.scaffoldMessengerKey,
|
||||||
localizationsDelegates: localizationsDelegates,
|
localizationsDelegates: localizationsDelegates,
|
||||||
|
|
@ -108,7 +85,7 @@ class _AppState extends State<App> with WidgetsBindingObserver {
|
||||||
title: 'twonly',
|
title: 'twonly',
|
||||||
theme: lightTheme,
|
theme: lightTheme,
|
||||||
darkTheme: darkTheme,
|
darkTheme: darkTheme,
|
||||||
themeMode: context.watch<SettingsChangeProvider>().themeMode,
|
themeMode: context.read<SettingsChangeProvider>().themeMode,
|
||||||
home: const CriticalErrorView(),
|
home: const CriticalErrorView(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -122,7 +99,7 @@ class _AppState extends State<App> with WidgetsBindingObserver {
|
||||||
title: 'twonly',
|
title: 'twonly',
|
||||||
theme: lightTheme,
|
theme: lightTheme,
|
||||||
darkTheme: darkTheme,
|
darkTheme: darkTheme,
|
||||||
themeMode: context.watch<SettingsChangeProvider>().themeMode,
|
themeMode: context.read<SettingsChangeProvider>().themeMode,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
@ -142,7 +119,6 @@ class AppMainWidget extends StatefulWidget {
|
||||||
class _AppMainWidgetState extends State<AppMainWidget> {
|
class _AppMainWidgetState extends State<AppMainWidget> {
|
||||||
bool _showOnboarding = true;
|
bool _showOnboarding = true;
|
||||||
bool _isLoaded = false;
|
bool _isLoaded = false;
|
||||||
Object? _storageError;
|
|
||||||
bool _skipBackup = kDebugMode;
|
bool _skipBackup = kDebugMode;
|
||||||
bool _isTwonlyLocked = true;
|
bool _isTwonlyLocked = true;
|
||||||
|
|
||||||
|
|
@ -155,29 +131,24 @@ class _AppMainWidgetState extends State<AppMainWidget> {
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> initAsync() async {
|
Future<void> initAsync() async {
|
||||||
try {
|
if (userService.isUserCreated) {
|
||||||
if (userService.isUserCreated) {
|
if (_isTwonlyLocked) {
|
||||||
if (_isTwonlyLocked) {
|
// do not change in case twonly was already unlocked at some point
|
||||||
// do not change in case twonly was already unlocked at some point
|
_isTwonlyLocked = userService.currentUser.screenLockEnabled;
|
||||||
_isTwonlyLocked = userService.currentUser.screenLockEnabled;
|
}
|
||||||
}
|
} else {
|
||||||
} else {
|
// This means the user is in the onboarding screen, so start with the Proof of Work.
|
||||||
// This means the user is in the onboarding screen, so start with the Proof of Work.
|
|
||||||
|
final (proof, disabled) = await apiService.getProofOfWork();
|
||||||
final (proof, disabled) = await apiService.getProofOfWork();
|
if (proof != null) {
|
||||||
if (proof != null) {
|
Log.info('Starting with proof of work calculation.');
|
||||||
Log.info('Starting with proof of work calculation.');
|
_proofOfWork = (
|
||||||
_proofOfWork = (
|
calculatePoW(proof.prefix, proof.difficulty.toInt()),
|
||||||
calculatePoW(proof.prefix, proof.difficulty.toInt()),
|
false,
|
||||||
false,
|
);
|
||||||
);
|
} else {
|
||||||
} else {
|
_proofOfWork = (null, disabled);
|
||||||
_proofOfWork = (null, disabled);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} catch (e) {
|
|
||||||
Log.error('Storage error in AppMainWidget.initAsync: $e');
|
|
||||||
_storageError = e;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
setState(() {
|
setState(() {
|
||||||
|
|
@ -191,10 +162,6 @@ class _AppMainWidgetState extends State<AppMainWidget> {
|
||||||
return Center(child: Container());
|
return Center(child: Container());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_storageError != null) {
|
|
||||||
return const CriticalErrorView();
|
|
||||||
}
|
|
||||||
|
|
||||||
late Widget child;
|
late Widget child;
|
||||||
|
|
||||||
if (userService.isUserCreated) {
|
if (userService.isUserCreated) {
|
||||||
|
|
|
||||||
|
|
@ -126,6 +126,9 @@ void main() async {
|
||||||
unawaited(createPushAvatars());
|
unawaited(createPushAvatars());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await apiService.listenToNetworkChanges();
|
||||||
|
unawaited(apiService.connect());
|
||||||
|
|
||||||
runApp(
|
runApp(
|
||||||
MultiProvider(
|
MultiProvider(
|
||||||
providers: [
|
providers: [
|
||||||
|
|
@ -134,7 +137,7 @@ void main() async {
|
||||||
ChangeNotifierProvider(create: (_) => ImageEditorProvider()),
|
ChangeNotifierProvider(create: (_) => ImageEditorProvider()),
|
||||||
ChangeNotifierProvider(create: (_) => PurchasesProvider()),
|
ChangeNotifierProvider(create: (_) => PurchasesProvider()),
|
||||||
],
|
],
|
||||||
child: const App(),
|
child: App(storageError: storageError),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,11 +4,11 @@ import 'package:twonly/locator.dart';
|
||||||
|
|
||||||
class CustomChangeProvider with ChangeNotifier, DiagnosticableTreeMixin {
|
class CustomChangeProvider with ChangeNotifier, DiagnosticableTreeMixin {
|
||||||
CustomChangeProvider() {
|
CustomChangeProvider() {
|
||||||
|
// The API is connected before the subscription has started so ensure that the connection state is correct
|
||||||
|
_isConnected = apiService.isConnected;
|
||||||
_connSub = apiService.onConnectionStateUpdated.listen(
|
_connSub = apiService.onConnectionStateUpdated.listen(
|
||||||
updateConnectionState,
|
updateConnectionState,
|
||||||
);
|
);
|
||||||
// The API is connected before the subscription has started so ensure that the connection state is correct
|
|
||||||
_isConnected = apiService.isConnected;
|
|
||||||
}
|
}
|
||||||
late bool _isConnected;
|
late bool _isConnected;
|
||||||
late StreamSubscription<bool> _connSub;
|
late StreamSubscription<bool> _connSub;
|
||||||
|
|
|
||||||
|
|
@ -32,8 +32,7 @@ Timer? globalForceIpaCheck;
|
||||||
|
|
||||||
class PurchasesProvider with ChangeNotifier, DiagnosticableTreeMixin {
|
class PurchasesProvider with ChangeNotifier, DiagnosticableTreeMixin {
|
||||||
PurchasesProvider() {
|
PurchasesProvider() {
|
||||||
final purchaseUpdated = iapConnection.purchaseStream;
|
_subscription = iapConnection.purchaseStream.listen(
|
||||||
_subscription = purchaseUpdated.listen(
|
|
||||||
_onPurchaseUpdate,
|
_onPurchaseUpdate,
|
||||||
onDone: _updateStreamOnDone,
|
onDone: _updateStreamOnDone,
|
||||||
onError: _updateStreamOnError,
|
onError: _updateStreamOnError,
|
||||||
|
|
@ -50,6 +49,10 @@ class PurchasesProvider with ChangeNotifier, DiagnosticableTreeMixin {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (userService.isUserCreated) {
|
||||||
|
updatePlan(planFromString(userService.currentUser.subscriptionPlan));
|
||||||
|
}
|
||||||
|
|
||||||
loadPurchases();
|
loadPurchases();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -73,7 +76,7 @@ class PurchasesProvider with ChangeNotifier, DiagnosticableTreeMixin {
|
||||||
final available = await iapConnection.isAvailable();
|
final available = await iapConnection.isAvailable();
|
||||||
if (!available) {
|
if (!available) {
|
||||||
storeState = StoreState.notAvailable;
|
storeState = StoreState.notAvailable;
|
||||||
Log.error('Store is not available');
|
Log.warn('Store is not available');
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -98,7 +101,6 @@ class PurchasesProvider with ChangeNotifier, DiagnosticableTreeMixin {
|
||||||
isPayingUser(
|
isPayingUser(
|
||||||
planFromString(userService.currentUser.subscriptionPlan),
|
planFromString(userService.currentUser.subscriptionPlan),
|
||||||
)) {
|
)) {
|
||||||
Log.info('Started IPA timer for verification.');
|
|
||||||
globalForceIpaCheck = Timer(const Duration(seconds: 5), () async {
|
globalForceIpaCheck = Timer(const Duration(seconds: 5), () async {
|
||||||
Log.info(
|
Log.info(
|
||||||
'Force Ipa check was not stopped. Requesting forced check...',
|
'Force Ipa check was not stopped. Requesting forced check...',
|
||||||
|
|
|
||||||
|
|
@ -84,7 +84,7 @@ class ApiService {
|
||||||
HashMap();
|
HashMap();
|
||||||
IOWebSocketChannel? _channel;
|
IOWebSocketChannel? _channel;
|
||||||
// ignore: cancel_subscriptions
|
// ignore: cancel_subscriptions
|
||||||
StreamSubscription<List<ConnectivityResult>>? connectivitySubscription;
|
StreamSubscription<List<ConnectivityResult>>? _connectivitySubscription;
|
||||||
|
|
||||||
Future<bool> _connectTo(String apiUrl) async {
|
Future<bool> _connectTo(String apiUrl) async {
|
||||||
if (appIsOutdated) return false;
|
if (appIsOutdated) return false;
|
||||||
|
|
@ -185,10 +185,10 @@ class ApiService {
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> listenToNetworkChanges() async {
|
Future<void> listenToNetworkChanges() async {
|
||||||
if (connectivitySubscription != null) {
|
if (_connectivitySubscription != null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
connectivitySubscription = Connectivity().onConnectivityChanged.listen((
|
_connectivitySubscription = Connectivity().onConnectivityChanged.listen((
|
||||||
result,
|
result,
|
||||||
) async {
|
) async {
|
||||||
if (!result.contains(ConnectivityResult.none)) {
|
if (!result.contains(ConnectivityResult.none)) {
|
||||||
|
|
@ -467,10 +467,11 @@ class ApiService {
|
||||||
return lockAuthentication.protect(() async {
|
return lockAuthentication.protect(() async {
|
||||||
if (isAuthenticated) return;
|
if (isAuthenticated) return;
|
||||||
if (await getSignalIdentity() == null) {
|
if (await getSignalIdentity() == null) {
|
||||||
|
Log.error('Signal identity not found.');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (userService.isUserCreated) return;
|
if (!userService.isUserCreated) return;
|
||||||
|
|
||||||
if (await tryAuthenticateWithToken()) {
|
if (await tryAuthenticateWithToken()) {
|
||||||
return;
|
return;
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@ class UserService {
|
||||||
final user = await getUser();
|
final user = await getUser();
|
||||||
if (user == null) return false;
|
if (user == null) return false;
|
||||||
userService.currentUser = user;
|
userService.currentUser = user;
|
||||||
isUserCreated = true;
|
userService.isUserCreated = true;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,9 @@ import 'dart:collection';
|
||||||
|
|
||||||
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:go_router/go_router.dart';
|
||||||
import 'package:twonly/locator.dart';
|
import 'package:twonly/locator.dart';
|
||||||
|
import 'package:twonly/src/constants/routes.keys.dart';
|
||||||
import 'package:twonly/src/database/daos/contacts.dao.dart';
|
import 'package:twonly/src/database/daos/contacts.dao.dart';
|
||||||
import 'package:twonly/src/database/tables/mediafiles.table.dart';
|
import 'package:twonly/src/database/tables/mediafiles.table.dart';
|
||||||
import 'package:twonly/src/database/twonly.db.dart';
|
import 'package:twonly/src/database/twonly.db.dart';
|
||||||
|
|
@ -40,7 +42,7 @@ class ShareImageView extends StatefulWidget {
|
||||||
}
|
}
|
||||||
|
|
||||||
class _ShareImageView extends State<ShareImageView> {
|
class _ShareImageView extends State<ShareImageView> {
|
||||||
List<Group> contacts = [];
|
List<Group> _allGroups = [];
|
||||||
List<Group> _otherUsers = [];
|
List<Group> _otherUsers = [];
|
||||||
List<Group> _bestFriends = [];
|
List<Group> _bestFriends = [];
|
||||||
List<Group> _pinnedContacts = [];
|
List<Group> _pinnedContacts = [];
|
||||||
|
|
@ -61,9 +63,9 @@ class _ShareImageView extends State<ShareImageView> {
|
||||||
allGroups,
|
allGroups,
|
||||||
) async {
|
) async {
|
||||||
setState(() {
|
setState(() {
|
||||||
contacts = allGroups;
|
_allGroups = allGroups;
|
||||||
});
|
});
|
||||||
await updateGroups(allGroups.where((x) => !x.archived).toList());
|
await updateGroups(_allGroups.where((x) => !x.archived).toList());
|
||||||
});
|
});
|
||||||
|
|
||||||
unawaited(initAsync());
|
unawaited(initAsync());
|
||||||
|
|
@ -128,7 +130,7 @@ class _ShareImageView extends State<ShareImageView> {
|
||||||
lastQuery = query;
|
lastQuery = query;
|
||||||
if (query.isEmpty) {
|
if (query.isEmpty) {
|
||||||
await updateGroups(
|
await updateGroups(
|
||||||
contacts
|
_allGroups
|
||||||
.where(
|
.where(
|
||||||
(x) =>
|
(x) =>
|
||||||
!x.archived ||
|
!x.archived ||
|
||||||
|
|
@ -139,7 +141,7 @@ class _ShareImageView extends State<ShareImageView> {
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
final usersFiltered = contacts
|
final usersFiltered = _allGroups
|
||||||
.where(
|
.where(
|
||||||
(user) => user.groupName.toLowerCase().contains(query.toLowerCase()),
|
(user) => user.groupName.toLowerCase().contains(query.toLowerCase()),
|
||||||
)
|
)
|
||||||
|
|
@ -168,16 +170,30 @@ class _ShareImageView extends State<ShareImageView> {
|
||||||
),
|
),
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
Padding(
|
if (_allGroups.isEmpty)
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 10),
|
Expanded(
|
||||||
child: TextField(
|
child: Center(
|
||||||
onChanged: _filterUsers,
|
child: FilledButton.icon(
|
||||||
decoration: getInputDecoration(
|
icon: const Icon(Icons.person_add),
|
||||||
context,
|
onPressed: () => context.push(Routes.chatsAddNewUser),
|
||||||
context.lang.shareImageSearchAllContacts,
|
label: Text(
|
||||||
|
context.lang.chatListViewSearchUserNameBtn,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
|
if (_allGroups.isNotEmpty)
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 10),
|
||||||
|
child: TextField(
|
||||||
|
onChanged: _filterUsers,
|
||||||
|
decoration: getInputDecoration(
|
||||||
|
context,
|
||||||
|
context.lang.shareImageSearchAllContacts,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
|
||||||
if (_pinnedContacts.isNotEmpty) const SizedBox(height: 10),
|
if (_pinnedContacts.isNotEmpty) const SizedBox(height: 10),
|
||||||
BestFriendsSelector(
|
BestFriendsSelector(
|
||||||
groups: _pinnedContacts,
|
groups: _pinnedContacts,
|
||||||
|
|
@ -202,7 +218,7 @@ class _ShareImageView extends State<ShareImageView> {
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: [
|
children: [
|
||||||
HeadLineComp(context.lang.shareImageAllUsers),
|
HeadLineComp(context.lang.shareImageAllUsers),
|
||||||
if (contacts.any((x) => x.archived))
|
if (_allGroups.any((x) => x.archived))
|
||||||
Row(
|
Row(
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
|
|
@ -236,13 +252,14 @@ class _ShareImageView extends State<ShareImageView> {
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
Expanded(
|
if (_otherUsers.isNotEmpty)
|
||||||
child: UserList(
|
Expanded(
|
||||||
List.from(_otherUsers),
|
child: UserList(
|
||||||
selectedGroupIds: widget.selectedGroupIds,
|
List.from(_otherUsers),
|
||||||
updateSelectedGroupIds: updateSelectedGroupIds,
|
selectedGroupIds: widget.selectedGroupIds,
|
||||||
|
updateSelectedGroupIds: updateSelectedGroupIds,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
|
||||||
|
|
@ -218,7 +218,7 @@ class _ChatListViewState extends State<ChatListView> {
|
||||||
? Center(
|
? Center(
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.all(10),
|
padding: const EdgeInsets.all(10),
|
||||||
child: OutlinedButton.icon(
|
child: FilledButton.icon(
|
||||||
icon: const Icon(Icons.person_add),
|
icon: const Icon(Icons.person_add),
|
||||||
onPressed: () => context.push(Routes.chatsAddNewUser),
|
onPressed: () => context.push(Routes.chatsAddNewUser),
|
||||||
label: Text(
|
label: Text(
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue