2021-06-24 23:10:45 +00:00
|
|
|
import 'dart:convert';
|
2021-07-14 01:16:55 +00:00
|
|
|
import 'package:cwtch/config.dart';
|
2021-06-24 23:10:45 +00:00
|
|
|
import 'package:cwtch/notification_manager.dart';
|
|
|
|
import 'package:cwtch/views/messageview.dart';
|
|
|
|
import 'package:cwtch/widgets/rightshiftfixer.dart';
|
|
|
|
import 'package:flutter/foundation.dart';
|
|
|
|
import 'package:cwtch/cwtch/ffi.dart';
|
|
|
|
import 'package:cwtch/cwtch/gomobile.dart';
|
|
|
|
import 'package:flutter/material.dart';
|
|
|
|
import 'package:cwtch/errorHandler.dart';
|
|
|
|
import 'package:cwtch/settings.dart';
|
|
|
|
import 'package:cwtch/torstatus.dart';
|
|
|
|
import 'package:cwtch/views/triplecolview.dart';
|
|
|
|
import 'package:flutter/services.dart';
|
|
|
|
import 'package:provider/provider.dart';
|
|
|
|
import 'cwtch/cwtch.dart';
|
|
|
|
import 'cwtch/cwtchNotifier.dart';
|
|
|
|
import 'licenses.dart';
|
|
|
|
import 'model.dart';
|
|
|
|
import 'views/profilemgrview.dart';
|
|
|
|
import 'views/splashView.dart';
|
|
|
|
import 'dart:io' show Platform, exit;
|
|
|
|
import 'opaque.dart';
|
|
|
|
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
|
|
|
|
|
|
|
var globalSettings = Settings(Locale("en", ''), OpaqueDark());
|
|
|
|
var globalErrorHandler = ErrorHandler();
|
|
|
|
var globalTorStatus = TorStatus();
|
|
|
|
var globalAppState = AppState();
|
|
|
|
|
|
|
|
void main() {
|
2021-07-14 01:16:55 +00:00
|
|
|
print("Cwtch version: ${EnvironmentConfig.BUILD_VER} built on: ${EnvironmentConfig.BUILD_DATE}");
|
2021-06-24 23:10:45 +00:00
|
|
|
LicenseRegistry.addLicense(() => licenses());
|
|
|
|
WidgetsFlutterBinding.ensureInitialized();
|
|
|
|
print("runApp()");
|
|
|
|
runApp(Flwtch());
|
|
|
|
}
|
|
|
|
|
|
|
|
class Flwtch extends StatefulWidget {
|
|
|
|
final Key flwtch = GlobalKey();
|
|
|
|
|
|
|
|
@override
|
|
|
|
FlwtchState createState() => FlwtchState();
|
|
|
|
}
|
|
|
|
|
|
|
|
class FlwtchState extends State<Flwtch> {
|
|
|
|
final TextStyle biggerFont = const TextStyle(fontSize: 18);
|
|
|
|
late Cwtch cwtch;
|
|
|
|
late ProfileListState profs;
|
|
|
|
final MethodChannel notificationClickChannel = MethodChannel('im.cwtch.flwtch/notificationClickHandler');
|
2021-06-25 00:59:54 +00:00
|
|
|
final MethodChannel shutdownMethodChannel = MethodChannel('im.cwtch.flwtch/shutdownClickHandler');
|
2021-06-24 23:10:45 +00:00
|
|
|
final GlobalKey<NavigatorState> navKey = GlobalKey<NavigatorState>();
|
|
|
|
|
|
|
|
@override
|
|
|
|
initState() {
|
|
|
|
print("initState: running...");
|
|
|
|
super.initState();
|
|
|
|
|
|
|
|
print("initState: registering notification, shutdown handlers...");
|
|
|
|
profs = ProfileListState();
|
|
|
|
notificationClickChannel.setMethodCallHandler(_externalNotificationClicked);
|
2021-06-25 00:59:54 +00:00
|
|
|
shutdownMethodChannel.setMethodCallHandler(modalShutdown);
|
2021-06-24 23:10:45 +00:00
|
|
|
print("initState: creating cwtchnotifier, ffi");
|
|
|
|
if (Platform.isAndroid) {
|
|
|
|
var cwtchNotifier = new CwtchNotifier(profs, globalSettings, globalErrorHandler, globalTorStatus, NullNotificationsManager(), globalAppState);
|
|
|
|
cwtch = CwtchGomobile(cwtchNotifier);
|
|
|
|
} else if (Platform.isLinux) {
|
2021-06-28 21:32:26 +00:00
|
|
|
var cwtchNotifier = new CwtchNotifier(profs, globalSettings, globalErrorHandler, globalTorStatus, newDesktopNotificationsManager(), globalAppState);
|
2021-06-24 23:10:45 +00:00
|
|
|
cwtch = CwtchFfi(cwtchNotifier);
|
|
|
|
} else {
|
|
|
|
var cwtchNotifier = new CwtchNotifier(profs, globalSettings, globalErrorHandler, globalTorStatus, NullNotificationsManager(), globalAppState);
|
|
|
|
cwtch = CwtchFfi(cwtchNotifier);
|
|
|
|
}
|
|
|
|
print("initState: invoking cwtch.Start()");
|
|
|
|
cwtch.Start();
|
|
|
|
print("initState: done!");
|
|
|
|
}
|
|
|
|
|
|
|
|
ChangeNotifierProvider<TorStatus> getTorStatusProvider() => ChangeNotifierProvider.value(value: globalTorStatus);
|
|
|
|
ChangeNotifierProvider<ErrorHandler> getErrorHandlerProvider() => ChangeNotifierProvider.value(value: globalErrorHandler);
|
|
|
|
ChangeNotifierProvider<Settings> getSettingsProvider() => ChangeNotifierProvider.value(value: globalSettings);
|
|
|
|
ChangeNotifierProvider<AppState> getAppStateProvider() => ChangeNotifierProvider.value(value: globalAppState);
|
|
|
|
Provider<FlwtchState> getFlwtchStateProvider() => Provider<FlwtchState>(create: (_) => this);
|
|
|
|
ChangeNotifierProvider<ProfileListState> getProfileListProvider() => ChangeNotifierProvider(create: (context) => profs);
|
|
|
|
|
|
|
|
@override
|
|
|
|
Widget build(BuildContext context) {
|
|
|
|
globalSettings.initPackageInfo();
|
|
|
|
return MultiProvider(
|
|
|
|
providers: [
|
|
|
|
getFlwtchStateProvider(),
|
|
|
|
getProfileListProvider(),
|
|
|
|
getSettingsProvider(),
|
|
|
|
getErrorHandlerProvider(),
|
|
|
|
getTorStatusProvider(),
|
|
|
|
getAppStateProvider(),
|
|
|
|
],
|
|
|
|
builder: (context, widget) {
|
|
|
|
return Consumer2<Settings, AppState>(
|
|
|
|
builder: (context, settings, appState, child) => MaterialApp(
|
|
|
|
key: Key('app'),
|
|
|
|
navigatorKey: navKey,
|
|
|
|
locale: settings.locale,
|
|
|
|
localizationsDelegates: AppLocalizations.localizationsDelegates,
|
|
|
|
supportedLocales: AppLocalizations.supportedLocales,
|
|
|
|
title: 'Cwtch',
|
|
|
|
theme: mkThemeData(settings),
|
|
|
|
home: appState.cwtchInit == true ? ShiftRightFixer(child: ProfileMgrView()) : SplashView(),
|
|
|
|
),
|
|
|
|
);
|
|
|
|
},
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2021-06-25 00:59:54 +00:00
|
|
|
// invoked from either ProfileManagerView's appbar close button, or a ShutdownClicked event on
|
|
|
|
// the MyBroadcastReceiver method channel
|
|
|
|
Future<void> modalShutdown(MethodCall mc) async {
|
|
|
|
// set up the buttons
|
2021-08-27 18:28:04 +00:00
|
|
|
Widget cancelButton = ElevatedButton(
|
2021-06-25 00:59:54 +00:00
|
|
|
child: Text(AppLocalizations.of(navKey.currentContext!)!.cancel),
|
|
|
|
onPressed: () {
|
|
|
|
Navigator.of(navKey.currentContext!).pop(); // dismiss dialog
|
|
|
|
},
|
|
|
|
);
|
2021-08-27 18:28:04 +00:00
|
|
|
Widget continueButton = ElevatedButton(
|
2021-06-25 00:59:54 +00:00
|
|
|
child: Text(AppLocalizations.of(navKey.currentContext!)!.shutdownCwtchAction),
|
|
|
|
onPressed: () {
|
|
|
|
// Directly call the shutdown command, Android will do this for us...
|
|
|
|
Provider.of<FlwtchState>(navKey.currentContext!, listen: false).shutdown();
|
|
|
|
Provider.of<AppState>(navKey.currentContext!, listen: false).cwtchIsClosing = true;
|
|
|
|
});
|
|
|
|
|
|
|
|
// set up the AlertDialog
|
|
|
|
AlertDialog alert = AlertDialog(
|
|
|
|
title: Text(AppLocalizations.of(navKey.currentContext!)!.shutdownCwtchDialogTitle),
|
|
|
|
content: Text(AppLocalizations.of(navKey.currentContext!)!.shutdownCwtchDialog),
|
|
|
|
actions: [
|
|
|
|
cancelButton,
|
|
|
|
continueButton,
|
|
|
|
],
|
|
|
|
);
|
|
|
|
|
|
|
|
// show the dialog
|
|
|
|
showDialog(
|
|
|
|
context: navKey.currentContext!,
|
|
|
|
barrierDismissible: false,
|
|
|
|
builder: (BuildContext context) {
|
|
|
|
return alert;
|
|
|
|
},
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
Future<void> shutdown() async {
|
2021-06-24 23:10:45 +00:00
|
|
|
cwtch.Shutdown();
|
|
|
|
// Wait a few seconds as shutting down things takes a little time..
|
|
|
|
Future.delayed(Duration(seconds: 2)).then((value) {
|
|
|
|
if (Platform.isAndroid) {
|
|
|
|
SystemNavigator.pop();
|
2021-09-10 23:34:43 +00:00
|
|
|
} else if (Platform.isLinux || Platform.isWindows || Platform.isMacOS) {
|
2021-06-24 23:10:45 +00:00
|
|
|
print("Exiting...");
|
|
|
|
exit(0);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
// Invoked via notificationClickChannel by MyBroadcastReceiver in MainActivity.kt
|
|
|
|
// coder beware: args["RemotePeer"] is actually a handle, and could be eg a groupID
|
|
|
|
Future<void> _externalNotificationClicked(MethodCall call) async {
|
|
|
|
var args = jsonDecode(call.arguments);
|
|
|
|
var profile = profs.getProfile(args["ProfileOnion"])!;
|
2021-06-29 18:49:29 +00:00
|
|
|
var convo = profile.contactList.getContact(args["Handle"])!;
|
2021-08-16 23:09:03 +00:00
|
|
|
Provider.of<AppState>(navKey.currentContext!, listen: false).initialScrollIndex = convo.unreadMessages;
|
2021-06-29 18:49:29 +00:00
|
|
|
convo.unreadMessages = 0;
|
2021-06-24 23:10:45 +00:00
|
|
|
|
|
|
|
// single pane mode pushes; double pane mode reads AppState.selectedProfile/Conversation
|
|
|
|
var isLandscape = Provider.of<AppState>(navKey.currentContext!, listen: false).isLandscape(navKey.currentContext!);
|
|
|
|
if (Provider.of<Settings>(navKey.currentContext!, listen: false).uiColumns(isLandscape).length == 1) {
|
2021-07-02 23:27:09 +00:00
|
|
|
while (navKey.currentState!.canPop()) {
|
2021-06-24 23:10:45 +00:00
|
|
|
print("messageview already open; popping before pushing replacement");
|
2021-07-02 23:27:09 +00:00
|
|
|
navKey.currentState!.pop();
|
2021-06-24 23:10:45 +00:00
|
|
|
}
|
|
|
|
navKey.currentState?.push(
|
|
|
|
MaterialPageRoute<void>(
|
|
|
|
builder: (BuildContext builderContext) {
|
|
|
|
return MultiProvider(
|
|
|
|
providers: [
|
|
|
|
ChangeNotifierProvider.value(value: profile),
|
2021-06-29 18:49:29 +00:00
|
|
|
ChangeNotifierProvider.value(value: convo),
|
2021-06-24 23:10:45 +00:00
|
|
|
],
|
2021-08-16 23:09:03 +00:00
|
|
|
builder: (context, child) => MessageView(),
|
2021-06-24 23:10:45 +00:00
|
|
|
);
|
|
|
|
},
|
|
|
|
),
|
|
|
|
);
|
2021-06-30 20:59:52 +00:00
|
|
|
} else {
|
|
|
|
//dual pane
|
2021-06-24 23:10:45 +00:00
|
|
|
Provider.of<AppState>(navKey.currentContext!, listen: false).selectedProfile = args["ProfileOnion"];
|
2021-06-29 18:49:29 +00:00
|
|
|
Provider.of<AppState>(navKey.currentContext!, listen: false).selectedConversation = args["Handle"];
|
2021-06-24 23:10:45 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@override
|
|
|
|
void dispose() {
|
|
|
|
cwtch.dispose();
|
|
|
|
super.dispose();
|
|
|
|
}
|
|
|
|
}
|