Skip to content

Commit

Permalink
✨feature: connect core function to ui
Browse files Browse the repository at this point in the history
  • Loading branch information
tom8zds committed Jul 3, 2024
1 parent 1ec1ba0 commit b7cfe27
Show file tree
Hide file tree
Showing 22 changed files with 731 additions and 121 deletions.
6 changes: 5 additions & 1 deletion build.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,8 @@ targets:
slang_build_runner:
options:
input_directory: assets/i18n
output_directory: lib/i18n # defaulting to lib/gen if input is outside of lib/
output_directory: lib/i18n # defaulting to lib/gen if input is outside of lib/
sources:
exclude:
# Example that excludes intellij's swap files
- lib/rust/**
22 changes: 22 additions & 0 deletions lib/common/constants.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import 'package:flutter/material.dart';

class Language {
final String name;
final String localeName;
Expand All @@ -9,3 +11,23 @@ const Map<String, Language> supportLanguages = {
"zh": Language("中文", "zh"),
"en": Language("English", "en"),
};

enum DeviceType {
mobile,
desktop,
web,
headless,
server,
}

extension DeviceTypeExt on DeviceType {
IconData get icon {
return switch (this) {
DeviceType.mobile => Icons.smartphone,
DeviceType.desktop => Icons.computer,
DeviceType.web => Icons.language,
DeviceType.headless => Icons.terminal,
DeviceType.server => Icons.dns,
};
}
}
140 changes: 140 additions & 0 deletions lib/common/device_info_utils.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
import 'dart:io';

import 'package:device_info_plus/device_info_plus.dart';
import 'package:flutter/foundation.dart';
import 'package:localsend_rs/rust/actor/model.dart';
import 'package:slang/builder/model/enums.dart';
import 'package:slang/builder/utils/string_extensions.dart';
import 'package:uuid/uuid.dart';

import 'constants.dart';

class DeviceInfoResult {
final DeviceType deviceType;
final String? deviceModel;

// Used to properly set Edge-to-Edge mode on Android
// See https://github.com/flutter/flutter/issues/90098
final int? androidSdkInt;

DeviceInfoResult({
required this.deviceType,
required this.deviceModel,
required this.androidSdkInt,
});
}

Future<List<String>> getInterface() async {
List<String> addressList = [];
List<NetworkInterface> interfaces = await NetworkInterface.list();
for (var interface in interfaces) {
for (var addr in interface.addresses) {
if (addr.isLinkLocal ||
addr.isLoopback ||
addr.isMulticast ||
addr.type != InternetAddressType.IPv4) {
continue;
}
addressList.add(addr.address);
}
}
addressList.sort();
return addressList;
}

Future<NodeDevice> newDevice() async {
final deviceInfo = await getDeviceInfo();
final addressList = await getInterface();
return NodeDevice(
alias: "test",
version: "2,0",
deviceModel: deviceInfo.deviceModel ?? "unknown",
deviceType: deviceInfo.deviceType.name,
fingerprint: const Uuid().v4(),
address: addressList[0],
port: 30030,
protocol: "http",
download: true,
announcement: true,
announce: true,
);
}

Future<DeviceInfoResult> getDeviceInfo() async {
final plugin = DeviceInfoPlugin();
final DeviceType deviceType;
final String? deviceModel;
int? androidSdkInt;

if (kIsWeb) {
deviceType = DeviceType.web;
final deviceInfo = await plugin.webBrowserInfo;
deviceModel = deviceInfo.browserName.humanName;
} else {
switch (defaultTargetPlatform) {
case TargetPlatform.android:
case TargetPlatform.iOS:
deviceType = DeviceType.mobile;
break;
case TargetPlatform.linux:
case TargetPlatform.macOS:
case TargetPlatform.windows:
case TargetPlatform.fuchsia:
deviceType = DeviceType.desktop;
break;
}

switch (defaultTargetPlatform) {
case TargetPlatform.android:
final deviceInfo = await plugin.androidInfo;
deviceModel = deviceInfo.brand.toCase(CaseStyle.pascal);
androidSdkInt = deviceInfo.version.sdkInt;
break;
case TargetPlatform.iOS:
final deviceInfo = await plugin.iosInfo;
deviceModel = deviceInfo.localizedModel;
break;
case TargetPlatform.linux:
deviceModel = 'Linux';
break;
case TargetPlatform.macOS:
deviceModel = 'macOS';
break;
case TargetPlatform.windows:
deviceModel = 'Windows';
break;
case TargetPlatform.fuchsia:
deviceModel = 'Fuchsia';
break;
}
}

return DeviceInfoResult(
deviceType: deviceType,
deviceModel: deviceModel,
androidSdkInt: androidSdkInt,
);
}

extension on BrowserName {
String? get humanName {
switch (this) {
case BrowserName.firefox:
return 'Firefox';
case BrowserName.samsungInternet:
return 'Samsung Internet';
case BrowserName.opera:
return 'Opera';
case BrowserName.msie:
return 'Internet Explorer';
case BrowserName.edge:
return 'Microsoft Edge';
case BrowserName.chrome:
return 'Google Chrome';
case BrowserName.safari:
return 'Safari';
case BrowserName.unknown:
return null;
}
}
}
2 changes: 1 addition & 1 deletion lib/i18n/strings.g.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
/// Locales: 2
/// Strings: 26 (13 per locale)
///
/// Built on 2024-05-19 at 06:03 UTC
/// Built on 2024-07-03 at 15:38 UTC
// coverage:ignore-file
// ignore_for_file: type=lint
Expand Down
9 changes: 4 additions & 5 deletions lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@ import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:localsend_rs/common/device_info_utils.dart';
import 'package:localsend_rs/config_store.dart';
import 'package:localsend_rs/pages/frame_page.dart';
import 'package:localsend_rs/rust/actor/model.dart';
import 'package:localsend_rs/rust/bridge.dart';
import 'package:path_provider/path_provider.dart';

Expand All @@ -33,7 +35,6 @@ Future<void> main() async {
// storePath: storePath,
// ),
// );
await setup();
await ConfigStore.ensureInitialized();
final locale = ConfigStore().locale();
print(locale);
Expand All @@ -43,10 +44,8 @@ Future<void> main() async {
print("test");
LocaleSettings.setLocaleRaw(locale);
}
// createLogStream().listen((event) {
// print(
// 'rust log [${event.level}] - ${event.tag} ${event.msg}(rust_time=${event.timeMillis})');
// });
final device = await newDevice();
await setup(device: device);
runApp(ProviderScope(child: TranslationProvider(child: const MyApp())));
}

Expand Down
30 changes: 28 additions & 2 deletions lib/pages/home_page.dart
Original file line number Diff line number Diff line change
@@ -1,13 +1,32 @@
import 'package:flutter/material.dart';
import 'package:localsend_rs/i18n/strings.g.dart';
import 'package:localsend_rs/rust/bridge.dart';
import 'package:localsend_rs/widget/network_widget.dart';

import '../widget/mission_widget.dart';
import '../widget/node_widget.dart';

class HomePage extends StatelessWidget {
class HomePage extends StatefulWidget {
const HomePage({super.key});

@override
State<HomePage> createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
bool refreshing = false;

Future<void> refresh() async {
setState(() {
refreshing = true;
});
await announce();
await Future.delayed(Duration(seconds: 4));
setState(() {
refreshing = false;
});
}

@override
Widget build(BuildContext context) {
return Scaffold(
Expand Down Expand Up @@ -43,13 +62,20 @@ class HomePage extends StatelessWidget {
minimumSize: WidgetStatePropertyAll(Size(16, 16)),
maximumSize: WidgetStatePropertyAll(Size(36, 36)),
),
onPressed: () {},
onPressed: () {
refresh();
},
icon: Icon(
Icons.sync,
))
],
),
),
if (refreshing)
Padding(
padding: const EdgeInsets.all(8.0),
child: LinearProgressIndicator(),
),
Expanded(child: NodeWidget()),
],
),
Expand Down
51 changes: 32 additions & 19 deletions lib/pages/setting_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:localsend_rs/i18n/strings.g.dart';
import 'package:localsend_rs/providers/core_provider.dart';
import 'package:localsend_rs/rust/bridge.dart';
import 'package:localsend_rs/widget/network_widget.dart';

Expand Down Expand Up @@ -45,25 +46,7 @@ class SettingPage extends StatelessWidget {
title: t.setting.core.title,
children: [
// core status
ListTile(
title: Text(t.setting.core.server.title),
trailing: OverflowBar(
children: [
IconButton(
onPressed: () async {
await startServer();
},
icon: const Icon(Icons.play_arrow),
),
IconButton(
onPressed: () async {
await shutdownServer();
},
icon: const Icon(Icons.stop),
),
],
),
),
ServerTile(),
// core log
NetworkWidget(
onPressed: (addr) {
Expand Down Expand Up @@ -258,3 +241,33 @@ class LocaleTile extends ConsumerWidget {
);
}
}

class ServerTile extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final core = ref.watch(coreStateProvider);
return ListTile(
title: Text(t.setting.core.server.title),
trailing: OverflowBar(
children: [
IconButton(
onPressed: core.serverState
? null
: () async {
await startServer();
},
icon: const Icon(Icons.play_arrow),
),
IconButton(
onPressed: core.serverState
? () async {
await shutdownServer();
}
: null,
icon: const Icon(Icons.stop),
),
],
),
);
}
}
41 changes: 41 additions & 0 deletions lib/providers/core_provider.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import 'package:equatable/equatable.dart';
import 'package:localsend_rs/rust/actor/model.dart';
import 'package:localsend_rs/rust/bridge.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';

part 'core_provider.g.dart';

class RustCoreState {
final bool serverState;
final List<NodeDevice> devices;

RustCoreState({required this.serverState, required this.devices});

RustCoreState copyWith({bool? serverState, List<NodeDevice>? devices}) =>
RustCoreState(
serverState: serverState ?? this.serverState,
devices: devices ?? this.devices,
);
}

@riverpod
class CoreState extends _$CoreState {
@override
RustCoreState build() {
final subServerState = listenServerState().listen(
(event) {
state = state.copyWith(serverState: event);
},
);
final subDevice = listenDevice().listen(
(event) {
state = state.copyWith(devices: event);
},
);
ref.onDispose(() {
subServerState.cancel();
subDevice.cancel();
});
return RustCoreState(serverState: false, devices: []);
}
}
Loading

0 comments on commit b7cfe27

Please sign in to comment.