Tor Status Pane Initial Cut
continuous-integration/drone/pr Build is passing Details

This commit is contained in:
Sarah Jamie Lewis 2021-04-13 15:29:23 -07:00
parent 1d98f57cad
commit a56a1e1f89
13 changed files with 261 additions and 3 deletions

BIN
assets/core/Tor_icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 575 B

58
assets/core/Tor_icon.svg Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 6.5 KiB

View File

@ -9,6 +9,9 @@ abstract class Cwtch {
// ignore: non_constant_identifier_names
void LoadProfiles(String pass);
// ignore: non_constant_identifier_names
void ResetTor();
// todo: remove these
// ignore: non_constant_identifier_names
void SendProfileEvent(String onion, String jsonEvent);

View File

@ -1,6 +1,8 @@
import 'dart:convert';
import 'dart:developer';
import 'package:flutter_app/torstatus.dart';
import '../errorHandler.dart';
import '../model.dart';
import '../settings.dart';
@ -11,11 +13,13 @@ class CwtchNotifier {
ProfileListState profileCN;
Settings settings;
ErrorHandler error;
TorStatus torStatus;
CwtchNotifier(ProfileListState pcn, Settings settingsCN, ErrorHandler errorCN) {
CwtchNotifier(ProfileListState pcn, Settings settingsCN, ErrorHandler errorCN, TorStatus torStatusCN) {
profileCN = pcn;
settings = settingsCN;
error = errorCN;
torStatus = torStatusCN;
}
void handleMessage(String type, dynamic data) {
@ -75,6 +79,7 @@ class CwtchNotifier {
break;
case "ACNStatus":
print("acn status: $data");
torStatus.handleUpdate(int.parse(data["Progress"]), data["Status"]);
break;
default:
print("unhandled event: $type");

View File

@ -297,4 +297,11 @@ class CwtchFfi implements Cwtch {
final u3 = message.toNativeUtf8();
SendMessage(u1, u1.length, u2, u2.length, u3, u3.length);
}
@override
void ResetTor() {
var resetTor = library.lookup<NativeFunction<Void Function()>>("c_ResetTor");
final ResetTor = resetTor.asFunction<void Function()>();
ResetTor();
}
}

View File

@ -142,4 +142,10 @@ class CwtchGomobile implements Cwtch {
void SendMessage(String profileOnion, String contactHandle, String message) {
cwtchPlatform.invokeMethod("SendMessage", {"ProfileOnion": profileOnion, "handle": contactHandle, "message": message});
}
@override
// ignore: non_constant_identifier_names
void ResetTor() {
cwtchPlatform.invokeMethod("ResetTor", {});
}
}

View File

@ -4,6 +4,7 @@ import 'package:flutter_app/cwtch/gomobile.dart';
import 'package:flutter/material.dart';
import 'package:flutter_app/errorHandler.dart';
import 'package:flutter_app/settings.dart';
import 'package:flutter_app/torstatus.dart';
import 'package:flutter_app/views/triplecolview.dart';
import 'package:provider/provider.dart';
import 'cwtch/cwtch.dart';
@ -18,6 +19,7 @@ import 'package:flutter_gen/gen_l10n/app_localizations.dart';
var globalSettings = Settings(Locale("en", ''), Opaque.dark);
var globalErrorHandler = ErrorHandler();
var globalTorStatus = TorStatus();
void main() {
LicenseRegistry.addLicense(() => licenses());
@ -48,7 +50,7 @@ class FlwtchState extends State<Flwtch> {
cwtchInit = false;
profs = ProfileListState();
var cwtchNotifier = new CwtchNotifier(profs, globalSettings, globalErrorHandler);
var cwtchNotifier = new CwtchNotifier(profs, globalSettings, globalErrorHandler, globalTorStatus);
if (Platform.isAndroid) {
cwtch = CwtchGomobile(cwtchNotifier);
@ -65,6 +67,7 @@ class FlwtchState extends State<Flwtch> {
appStatus = AppModel(cwtch: cwtch);
}
ChangeNotifierProvider<TorStatus> getTorStatusProvider() => ChangeNotifierProvider.value(value: globalTorStatus);
ChangeNotifierProvider<ErrorHandler> getErrorHandlerProvider() => ChangeNotifierProvider.value(value: globalErrorHandler);
ChangeNotifierProvider<Settings> getSettingsProvider() => ChangeNotifierProvider.value(value: globalSettings);
Provider<FlwtchState> getFlwtchStateProvider() => Provider<FlwtchState>(create: (_) => this);
@ -75,7 +78,7 @@ class FlwtchState extends State<Flwtch> {
//appStatus = AppModel(cwtch: cwtch);
return MultiProvider(
providers: [getFlwtchStateProvider(), getProfileListProvider(), getSettingsProvider(), getErrorHandlerProvider()],
providers: [getFlwtchStateProvider(), getProfileListProvider(), getSettingsProvider(), getErrorHandlerProvider(), getTorStatusProvider()],
builder: (context, widget) {
Provider.of<Settings>(context).initPackageInfo();
return Consumer<Settings>(

21
lib/torstatus.dart Normal file
View File

@ -0,0 +1,21 @@
import 'package:flutter/material.dart';
class TorStatus extends ChangeNotifier {
int progress;
String status;
bool connected;
/// Called by the event bus.
handleUpdate(int new_progress, String new_status) {
if (progress == 100) {
connected = true;
} else {
connected = false;
}
progress = new_progress;
status = new_status;
notifyListeners();
}
}

View File

@ -2,6 +2,7 @@ import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter_app/settings.dart';
import 'package:flutter_app/views/torstatusview.dart';
import 'package:flutter_app/widgets/passwordfield.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:flutter_app/widgets/profilerow.dart';
@ -34,6 +35,13 @@ class _ProfileMgrViewState extends State<ProfileMgrView> {
appBar: AppBar(
title: Text(AppLocalizations.of(context).titleManageProfiles),
actions: [
IconButton(
icon: Image(
image: AssetImage("assets/core/Tor_icon.png"),
filterQuality: FilterQuality.low,
isAntiAlias: false,
),
onPressed: _pushTorStatus),
IconButton(icon: Icon(Icons.bug_report_outlined), onPressed: _setLoggingLevelDebug),
IconButton(
icon: Icon(Icons.lock_open),
@ -75,6 +83,17 @@ class _ProfileMgrViewState extends State<ProfileMgrView> {
));
}
void _pushTorStatus() {
Navigator.of(context).push(MaterialPageRoute<void>(
builder: (BuildContext context) {
return Provider(
create: (_) => Provider.of<FlwtchState>(context, listen: false),
child: TorStatusView(),
);
},
));
}
void _pushAddEditProfile({onion: ""}) {
Navigator.of(context).push(MaterialPageRoute<void>(
builder: (BuildContext context) {

View File

@ -0,0 +1,63 @@
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_app/settings.dart';
import 'package:flutter_app/torstatus.dart';
import 'package:provider/provider.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import '../main.dart';
/// Tor Status View provides all info on Tor network state and the (future) ability to configure the network in a variety
/// of ways (restart, enable bridges, enable pluggable transports etc)
class TorStatusView extends StatefulWidget {
@override
_TorStatusView createState() => _TorStatusView();
}
class _TorStatusView extends State<TorStatusView> {
@override
void dispose() {
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Tor Network Status"),
),
body: _buildSettingsList(),
);
}
Widget _buildSettingsList() {
return Consumer<TorStatus>(builder: (context, torStatus, child) {
return LayoutBuilder(builder: (BuildContext context, BoxConstraints viewportConstraints) {
return Scrollbar(
isAlwaysShown: true,
child: SingleChildScrollView(
clipBehavior: Clip.antiAlias,
child: ConstrainedBox(
constraints: BoxConstraints(
minHeight: viewportConstraints.maxHeight,
),
child: Column(children: [
ListTile(
leading: Image(
image: AssetImage("assets/core/Tor_icon.png"),
),
title: Text("Tor Status"),
subtitle: Text(torStatus.progress == 100 ? AppLocalizations.of(context).networkStatusOnline : torStatus.status),
trailing: ElevatedButton(
child: Text("Reset"),
onPressed: () {
Provider.of<FlwtchState>(context, listen: false).cwtch.ResetTor();
},
),
)
]))));
});
});
}
}

View File

@ -83,6 +83,7 @@ flutter:
assets:
- assets/
- assets/core/
- assets/profiles/
# To add custom fonts to your application, add a fonts section here,

BIN
test/profileimage_init.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

View File

@ -0,0 +1,72 @@
// This is a basic Flutter widget test.
//
// To perform an interaction with a widget in your test, use the WidgetTester
// utility that Flutter provides. For example, you can send tap and scroll
// gestures. You can also use WidgetTester to find child widgets in the widget
// tree, read text, and verify that the values of widget properties are correct.
import 'package:flutter/material.dart';
import 'package:flutter_app/opaque.dart';
import 'package:flutter_app/settings.dart';
import 'package:flutter_app/widgets/cwtchlabel.dart';
import 'package:flutter_app/widgets/profileimage.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:provider/provider.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
var settingsEnglishDark = Settings(Locale("en", ''), Opaque.dark);
var settingsEnglishLight = Settings(Locale("en", ''), Opaque.light);
ChangeNotifierProvider<Settings> getSettingsEnglishDark() => ChangeNotifierProvider.value(value: settingsEnglishDark);
String file(String slug) {
return "profileimage_" + slug + ".png";
}
void main() {
testWidgets('ProfileImage widget test', (WidgetTester tester) async {
tester.binding.window.physicalSizeTestValue = Size(200, 200);
// await tester.pumpWidget(MultiProvider(
// providers:[getSettingsEnglishDark()],
// child: Directionality(textDirection: TextDirection.ltr, child: CwtchLabel(label: testingStr))
// ));
Widget testWidget = ProfileImage(
imagePath: "profiles/001-centaur.png",
badgeTextColor: settingsEnglishDark.theme.portraitProfileBadgeTextColor(),
badgeColor: settingsEnglishDark.theme.portraitProfileBadgeColor(),
maskOut: false,
border: settingsEnglishDark.theme.portraitOfflineBorderColor(),
diameter: 64.0,
badgeCount: 10,
);
Widget testHarness = MultiProvider(
providers:[getSettingsEnglishDark()],
builder: (context, child) { return MaterialApp(
locale: Provider.of<Settings>(context).locale,
localizationsDelegates: AppLocalizations.localizationsDelegates,
supportedLocales: AppLocalizations.supportedLocales,
title: 'Test',
theme: mkThemeData(Provider.of<Settings>(context)),
home: Card(child: testWidget),
);}
);
// Verify that our counter starts at 0.
//expect(find.text(testingStr), findsOneWidget);
//expect(find.text('1'), findsNothing);
await tester.pumpWidget(testHarness);
await expectLater(find.byWidget(testHarness), matchesGoldenFile(file('init')));
// Tap the '+' icon and trigger a frame.
// await tester.tap(find.byIcon(Icons.add));
// await tester.pump();
//
// // Verify that our counter has incremented.
// expect(find.text('0'), findsNothing);
// expect(find.text('1'), findsOneWidget);
});
}