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
51
lib/app.dart
51
lib/app.dart
|
|
@ -7,10 +7,8 @@ import 'package:provider/provider.dart';
|
|||
import 'package:twonly/globals.dart';
|
||||
import 'package:twonly/locator.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/settings.provider.dart';
|
||||
import 'package:twonly/src/services/subscription.service.dart';
|
||||
import 'package:twonly/src/utils/log.dart';
|
||||
import 'package:twonly/src/utils/pow.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';
|
||||
|
||||
class App extends StatefulWidget {
|
||||
const App({super.key});
|
||||
const App({required this.storageError, super.key});
|
||||
final bool storageError;
|
||||
@override
|
||||
State<App> createState() => _AppState();
|
||||
}
|
||||
|
||||
class _AppState extends State<App> with WidgetsBindingObserver {
|
||||
bool wasPaused = false;
|
||||
Object? _storageError;
|
||||
bool _wasPaused = false;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
AppState.isAppInBackground = false;
|
||||
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
|
||||
void didChangeAppLifecycleState(AppLifecycleState state) {
|
||||
super.didChangeAppLifecycleState(state);
|
||||
if (state == AppLifecycleState.resumed) {
|
||||
if (wasPaused) {
|
||||
if (_wasPaused) {
|
||||
AppState.isAppInBackground = false;
|
||||
twonlyDB.markUpdated();
|
||||
unawaited(apiService.connect());
|
||||
}
|
||||
} else if (state == AppLifecycleState.paused) {
|
||||
wasPaused = true;
|
||||
_wasPaused = true;
|
||||
AppState.isAppInBackground = true;
|
||||
}
|
||||
}
|
||||
|
|
@ -85,7 +62,7 @@ class _AppState extends State<App> with WidgetsBindingObserver {
|
|||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ListenableBuilder(
|
||||
listenable: context.watch<SettingsChangeProvider>(),
|
||||
listenable: context.read<SettingsChangeProvider>(),
|
||||
builder: (context, child) {
|
||||
const localizationsDelegates = [
|
||||
AppLocalizations.delegate,
|
||||
|
|
@ -99,7 +76,7 @@ class _AppState extends State<App> with WidgetsBindingObserver {
|
|||
Locale('de', ''),
|
||||
];
|
||||
|
||||
if (_storageError != null) {
|
||||
if (widget.storageError) {
|
||||
return MaterialApp(
|
||||
scaffoldMessengerKey: AppGlobalKeys.scaffoldMessengerKey,
|
||||
localizationsDelegates: localizationsDelegates,
|
||||
|
|
@ -108,7 +85,7 @@ class _AppState extends State<App> with WidgetsBindingObserver {
|
|||
title: 'twonly',
|
||||
theme: lightTheme,
|
||||
darkTheme: darkTheme,
|
||||
themeMode: context.watch<SettingsChangeProvider>().themeMode,
|
||||
themeMode: context.read<SettingsChangeProvider>().themeMode,
|
||||
home: const CriticalErrorView(),
|
||||
);
|
||||
}
|
||||
|
|
@ -122,7 +99,7 @@ class _AppState extends State<App> with WidgetsBindingObserver {
|
|||
title: 'twonly',
|
||||
theme: lightTheme,
|
||||
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> {
|
||||
bool _showOnboarding = true;
|
||||
bool _isLoaded = false;
|
||||
Object? _storageError;
|
||||
bool _skipBackup = kDebugMode;
|
||||
bool _isTwonlyLocked = true;
|
||||
|
||||
|
|
@ -155,7 +131,6 @@ class _AppMainWidgetState extends State<AppMainWidget> {
|
|||
}
|
||||
|
||||
Future<void> initAsync() async {
|
||||
try {
|
||||
if (userService.isUserCreated) {
|
||||
if (_isTwonlyLocked) {
|
||||
// do not change in case twonly was already unlocked at some point
|
||||
|
|
@ -175,10 +150,6 @@ class _AppMainWidgetState extends State<AppMainWidget> {
|
|||
_proofOfWork = (null, disabled);
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
Log.error('Storage error in AppMainWidget.initAsync: $e');
|
||||
_storageError = e;
|
||||
}
|
||||
|
||||
setState(() {
|
||||
_isLoaded = true;
|
||||
|
|
@ -191,10 +162,6 @@ class _AppMainWidgetState extends State<AppMainWidget> {
|
|||
return Center(child: Container());
|
||||
}
|
||||
|
||||
if (_storageError != null) {
|
||||
return const CriticalErrorView();
|
||||
}
|
||||
|
||||
late Widget child;
|
||||
|
||||
if (userService.isUserCreated) {
|
||||
|
|
|
|||
|
|
@ -126,6 +126,9 @@ void main() async {
|
|||
unawaited(createPushAvatars());
|
||||
}
|
||||
|
||||
await apiService.listenToNetworkChanges();
|
||||
unawaited(apiService.connect());
|
||||
|
||||
runApp(
|
||||
MultiProvider(
|
||||
providers: [
|
||||
|
|
@ -134,7 +137,7 @@ void main() async {
|
|||
ChangeNotifierProvider(create: (_) => ImageEditorProvider()),
|
||||
ChangeNotifierProvider(create: (_) => PurchasesProvider()),
|
||||
],
|
||||
child: const App(),
|
||||
child: App(storageError: storageError),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,11 +4,11 @@ import 'package:twonly/locator.dart';
|
|||
|
||||
class CustomChangeProvider with ChangeNotifier, DiagnosticableTreeMixin {
|
||||
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(
|
||||
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 StreamSubscription<bool> _connSub;
|
||||
|
|
|
|||
|
|
@ -32,8 +32,7 @@ Timer? globalForceIpaCheck;
|
|||
|
||||
class PurchasesProvider with ChangeNotifier, DiagnosticableTreeMixin {
|
||||
PurchasesProvider() {
|
||||
final purchaseUpdated = iapConnection.purchaseStream;
|
||||
_subscription = purchaseUpdated.listen(
|
||||
_subscription = iapConnection.purchaseStream.listen(
|
||||
_onPurchaseUpdate,
|
||||
onDone: _updateStreamOnDone,
|
||||
onError: _updateStreamOnError,
|
||||
|
|
@ -50,6 +49,10 @@ class PurchasesProvider with ChangeNotifier, DiagnosticableTreeMixin {
|
|||
}
|
||||
});
|
||||
|
||||
if (userService.isUserCreated) {
|
||||
updatePlan(planFromString(userService.currentUser.subscriptionPlan));
|
||||
}
|
||||
|
||||
loadPurchases();
|
||||
}
|
||||
|
||||
|
|
@ -73,7 +76,7 @@ class PurchasesProvider with ChangeNotifier, DiagnosticableTreeMixin {
|
|||
final available = await iapConnection.isAvailable();
|
||||
if (!available) {
|
||||
storeState = StoreState.notAvailable;
|
||||
Log.error('Store is not available');
|
||||
Log.warn('Store is not available');
|
||||
notifyListeners();
|
||||
return;
|
||||
}
|
||||
|
|
@ -98,7 +101,6 @@ class PurchasesProvider with ChangeNotifier, DiagnosticableTreeMixin {
|
|||
isPayingUser(
|
||||
planFromString(userService.currentUser.subscriptionPlan),
|
||||
)) {
|
||||
Log.info('Started IPA timer for verification.');
|
||||
globalForceIpaCheck = Timer(const Duration(seconds: 5), () async {
|
||||
Log.info(
|
||||
'Force Ipa check was not stopped. Requesting forced check...',
|
||||
|
|
|
|||
|
|
@ -84,7 +84,7 @@ class ApiService {
|
|||
HashMap();
|
||||
IOWebSocketChannel? _channel;
|
||||
// ignore: cancel_subscriptions
|
||||
StreamSubscription<List<ConnectivityResult>>? connectivitySubscription;
|
||||
StreamSubscription<List<ConnectivityResult>>? _connectivitySubscription;
|
||||
|
||||
Future<bool> _connectTo(String apiUrl) async {
|
||||
if (appIsOutdated) return false;
|
||||
|
|
@ -185,10 +185,10 @@ class ApiService {
|
|||
}
|
||||
|
||||
Future<void> listenToNetworkChanges() async {
|
||||
if (connectivitySubscription != null) {
|
||||
if (_connectivitySubscription != null) {
|
||||
return;
|
||||
}
|
||||
connectivitySubscription = Connectivity().onConnectivityChanged.listen((
|
||||
_connectivitySubscription = Connectivity().onConnectivityChanged.listen((
|
||||
result,
|
||||
) async {
|
||||
if (!result.contains(ConnectivityResult.none)) {
|
||||
|
|
@ -467,10 +467,11 @@ class ApiService {
|
|||
return lockAuthentication.protect(() async {
|
||||
if (isAuthenticated) return;
|
||||
if (await getSignalIdentity() == null) {
|
||||
Log.error('Signal identity not found.');
|
||||
return;
|
||||
}
|
||||
|
||||
if (userService.isUserCreated) return;
|
||||
if (!userService.isUserCreated) return;
|
||||
|
||||
if (await tryAuthenticateWithToken()) {
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ class UserService {
|
|||
final user = await getUser();
|
||||
if (user == null) return false;
|
||||
userService.currentUser = user;
|
||||
isUserCreated = true;
|
||||
userService.isUserCreated = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,9 @@ import 'dart:collection';
|
|||
|
||||
import 'package:flutter/material.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/src/constants/routes.keys.dart';
|
||||
import 'package:twonly/src/database/daos/contacts.dao.dart';
|
||||
import 'package:twonly/src/database/tables/mediafiles.table.dart';
|
||||
import 'package:twonly/src/database/twonly.db.dart';
|
||||
|
|
@ -40,7 +42,7 @@ class ShareImageView extends StatefulWidget {
|
|||
}
|
||||
|
||||
class _ShareImageView extends State<ShareImageView> {
|
||||
List<Group> contacts = [];
|
||||
List<Group> _allGroups = [];
|
||||
List<Group> _otherUsers = [];
|
||||
List<Group> _bestFriends = [];
|
||||
List<Group> _pinnedContacts = [];
|
||||
|
|
@ -61,9 +63,9 @@ class _ShareImageView extends State<ShareImageView> {
|
|||
allGroups,
|
||||
) async {
|
||||
setState(() {
|
||||
contacts = allGroups;
|
||||
_allGroups = allGroups;
|
||||
});
|
||||
await updateGroups(allGroups.where((x) => !x.archived).toList());
|
||||
await updateGroups(_allGroups.where((x) => !x.archived).toList());
|
||||
});
|
||||
|
||||
unawaited(initAsync());
|
||||
|
|
@ -128,7 +130,7 @@ class _ShareImageView extends State<ShareImageView> {
|
|||
lastQuery = query;
|
||||
if (query.isEmpty) {
|
||||
await updateGroups(
|
||||
contacts
|
||||
_allGroups
|
||||
.where(
|
||||
(x) =>
|
||||
!x.archived ||
|
||||
|
|
@ -139,7 +141,7 @@ class _ShareImageView extends State<ShareImageView> {
|
|||
);
|
||||
return;
|
||||
}
|
||||
final usersFiltered = contacts
|
||||
final usersFiltered = _allGroups
|
||||
.where(
|
||||
(user) => user.groupName.toLowerCase().contains(query.toLowerCase()),
|
||||
)
|
||||
|
|
@ -168,6 +170,20 @@ class _ShareImageView extends State<ShareImageView> {
|
|||
),
|
||||
child: Column(
|
||||
children: [
|
||||
if (_allGroups.isEmpty)
|
||||
Expanded(
|
||||
child: Center(
|
||||
child: FilledButton.icon(
|
||||
icon: const Icon(Icons.person_add),
|
||||
onPressed: () => context.push(Routes.chatsAddNewUser),
|
||||
label: Text(
|
||||
context.lang.chatListViewSearchUserNameBtn,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
if (_allGroups.isNotEmpty)
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 10),
|
||||
child: TextField(
|
||||
|
|
@ -202,7 +218,7 @@ class _ShareImageView extends State<ShareImageView> {
|
|||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
HeadLineComp(context.lang.shareImageAllUsers),
|
||||
if (contacts.any((x) => x.archived))
|
||||
if (_allGroups.any((x) => x.archived))
|
||||
Row(
|
||||
children: [
|
||||
Text(
|
||||
|
|
@ -236,6 +252,7 @@ class _ShareImageView extends State<ShareImageView> {
|
|||
),
|
||||
],
|
||||
),
|
||||
if (_otherUsers.isNotEmpty)
|
||||
Expanded(
|
||||
child: UserList(
|
||||
List.from(_otherUsers),
|
||||
|
|
|
|||
|
|
@ -218,7 +218,7 @@ class _ChatListViewState extends State<ChatListView> {
|
|||
? Center(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(10),
|
||||
child: OutlinedButton.icon(
|
||||
child: FilledButton.icon(
|
||||
icon: const Icon(Icons.person_add),
|
||||
onPressed: () => context.push(Routes.chatsAddNewUser),
|
||||
label: Text(
|
||||
|
|
|
|||
Loading…
Reference in a new issue