Commit 446eab12 authored by hywang's avatar hywang

1.使用新的ble库

parent 7ade97c9
......@@ -10,6 +10,8 @@ A few resources to get you started if this is your first Flutter project:
- [Lab: Write your first Flutter app](https://docs.flutter.dev/get-started/codelab)
- [Cookbook: Useful Flutter samples](https://docs.flutter.dev/cookbook)
flutter pub run build_runner build
For help getting started with Flutter development, view the
[online documentation](https://docs.flutter.dev/), which offers tutorials,
......
......@@ -2,17 +2,14 @@ import 'dart:async';
import 'dart:io';
import 'package:anchor_collect_flutter/utils/dialog_utils.dart';
import 'package:anchor_collect_flutter/utils/empty_utils.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_blue_plus/flutter_blue_plus.dart';
import 'package:get/get.dart';
import 'package:isar/isar.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:uuid/uuid.dart';
import '../models/cattle_resume_entity.dart';
import '../models/dict_entity.dart';
import '../models/user_model.dart';
import '../rfid/rfid_plugin.dart';
typedef void DiscoveredCallback(args);
typedef void ConnectCallback(args);
......@@ -23,36 +20,37 @@ class BleService extends GetxService {
late DiscoveredCallback? discoveredCallback;
late ConnectCallback? connectCallback;
late BluetoothService _service;
late BluetoothService selectService;
late BluetoothCharacteristic _writeCharacteristic;
late BluetoothCharacteristic _notifyCharacteristic;
late
// 读取数据的 Stream
List<BluetoothDevice> _systemDevices = [];
//
List<ScanResult> _scanResults = [];
RxList<ScanResult> scanResults = <ScanResult>[].obs;
RxBool isScanning = false.obs;
bool isConnect = false;
late StreamSubscription<List<ScanResult>> _scanResultsSubscription;
late StreamSubscription<bool> _isScanningSubscription;
late StreamSubscription<BluetoothConnectionState>
_connectionStateSubscription;
late StreamSubscription<BluetoothConnectionState> _connectionStateSubscription;
late StreamSubscription<List<int>> _lastValueSubscription;
late StreamSubscription<List<int>> _valueReceivedSubscription;
late BluetoothDevice selectedDevice;
Future<BleService> init() async {
_isScanningSubscription = FlutterBluePlus.isScanning.listen((state) {
isScanning.value = state;
});
_scanResultsSubscription = FlutterBluePlus.scanResults.listen((results) {
_scanResults = results;
List<ScanResult> tempList = List.from(results);
for (var element in tempList) {
if (!EmptyUtils.isStrNotEmpty(element.device.platformName)) {
tempList.remove(element);
}
}
scanResults.value = tempList;
}, onError: (e) {
DialogUtils.showToast('扫描错误');
});
......@@ -60,11 +58,10 @@ class BleService extends GetxService {
}
// 切换扫描状态
Future<void> toggleScan(DiscoveredCallback callback) async {
discoveredCallback = callback;
Future<void> toggleScan() async {
// discoveredCallback = callback;
if (isScanning.value) {
FlutterBluePlus.stopScan();
isScanning.value = false;
stopScan();
} else {
await scanDevices();
}
......@@ -86,60 +83,70 @@ class BleService extends GetxService {
// so instead we only ask for 1/8 of them
int divisor = Platform.isAndroid ? 8 : 1;
await FlutterBluePlus.startScan(
timeout: const Duration(seconds: 15),
continuousUpdates: true,
continuousDivisor: divisor);
timeout: const Duration(seconds: 15), continuousUpdates: true, continuousDivisor: divisor);
} catch (e) {
DialogUtils.showToast('扫描错误');
}
///扫描10秒
// Future.delayed(const Duration(seconds: 15), () async {
// FlutterBluePlus.stopScan();
// isScanning.value = false;
// DialogUtils.showToast('自动停止扫描');
// });
Future.delayed(const Duration(seconds: 15), () async {
FlutterBluePlus.stopScan();
isScanning.value = false;
DialogUtils.dismissDialog();
});
}
stopScan() {
FlutterBluePlus.stopScan();
isScanning.value = false;
}
// 连接设备
Future<void> connectToDevice(BluetoothDevice device, BuildContext context, ConnectCallback callback) async {
Future<void> connectToDevice(int index, ConnectCallback callback) async {
connectCallback = callback;
selectedDevice = device; // 设置当前选中的设备
var selectedDevice = scanResults[index].device; // 设置当前选中的设备
// 在连接设备之前,停止扫描
await FlutterBluePlus.stopScan();
isScanning.value = false; // 设置 isScanning 为 false
DialogUtils.showLoadingDialog('正在连接到 ${device.name}');
// listen for disconnection
_connectionStateSubscription = device.connectionState.listen((BluetoothConnectionState state) async {
DialogUtils.showLoadingDialog('正在连接到 ${selectedDevice.advName}');
_connectionStateSubscription = selectedDevice.connectionState.listen((BluetoothConnectionState state) async {
if (state == BluetoothConnectionState.disconnected) {
// 1. typically, start a periodic timer that tries to
// reconnect, or just call connect() again right now
// 2. you must always re-discover services after disconnection!
DialogUtils.showToast('断开连接');
print(
"${device.disconnectReason!.code} ${device.disconnectReason!.description}");
isConnect = false;
if (kDebugMode) {
print("${selectedDevice.disconnectReason!.code} ${selectedDevice.disconnectReason!.description}");
}
} else if (state == BluetoothConnectionState.connected) {
// Note: You must call discoverServices after every re-connection!
List<BluetoothService> services = await device.discoverServices();
if (Platform.isAndroid) {
await selectedDevice.requestMtu(512);
}
List<BluetoothService> services = await selectedDevice.discoverServices();
services.forEach((service) {
//打印所有服务的 uuid
print('service uuid: ${service.uuid}');
if (kDebugMode) {
print('service uuid: ${service.uuid}');
}
if (!service.serviceUuid.toString().contains('000180')) {
_service = service;
selectService = service;
//打印 service uuid
print('service uuid: ${service.uuid}');
if (kDebugMode) {
print('service 000180 uuid: ${service.uuid}');
}
var characteristics = service.characteristics;
for (BluetoothCharacteristic c in characteristics) {
if (c.properties.write) {
//打印写的特征值 uuid
print('write characteristic uuid: ${c.uuid}');
if (kDebugMode) {
print('write characteristic uuid: ${c.uuid}');
}
_writeCharacteristic = c;
}
if (c.properties.notify) {
//打印通知的特征值 uuid
print('notify characteristic uuid: ${c.uuid}');
if (kDebugMode) {
print('notify characteristic uuid: ${c.uuid}');
}
_notifyCharacteristic = c;
c.setNotifyValue(true);
......@@ -147,36 +154,38 @@ class BleService extends GetxService {
// print(value);
// });
_valueReceivedSubscription = c.onValueReceived.listen((value) {
print(value);
RfidPlugin.pushRemoteRFIDData(value);
});
}
}
}
});
if (connectCallback != null) {
connectCallback!('');
}
DialogUtils.dismissDialog();
} else if (state == BluetoothConnectionState.connecting) {
isConnect = false;
DialogUtils.showToast('正在连接');
}
});
// 连接设备
await device.connect().catchError((onError) {
await selectedDevice.connect().catchError((onError) {
DialogUtils.dismissDialog();
DialogUtils.showToast('连接设备失败$onError');
});
}
// 写入数据
Future<void> writeData(List<int> data) async {
if (selectedDevice.value == null) {
throw Exception('No device connected');
}
final characteristic = QualifiedCharacteristic(
deviceId: selectedDevice.value!.id,
serviceId: _serviceId,
characteristicId: _writeCharacteristicId,
);
// if (selectedDevice == null) {
// throw Exception('No device connected');
// }
await ble.writeCharacteristicWithResponse(characteristic, value: data);
await _writeCharacteristic.write(data, allowLongWrite: true);
}
// 检查权限
......
import 'package:anchor_collect_flutter/congifs.dart';
import 'package:anchor_collect_flutter/pages/login/login_view.dart';
import 'package:anchor_collect_flutter/rfid/rfid_plugin.dart';
import 'package:anchor_collect_flutter/routes/pages.dart';
import 'package:anchor_collect_flutter/routes/routes.dart';
import 'package:anchor_collect_flutter/utils/sp_helper.dart';
......@@ -44,6 +45,8 @@ Future<void> initServices() async {
await Get.putAsync(() => GlobalService().init());
await Get.putAsync(() => BleService().init());
RfidPlugin();
print('All services started...');
}
......
import 'package:isar/isar.dart';
import '../generated/json/base/json_field.dart';
@JsonSerializable()
@collection
class Performance{
Id id = Isar.autoIncrement;
/** unid主键 */
@Index(unique: true, replace: true)
String? unid;
/**
* 基本信息ID
*/
String? cattleresumeId;
/**
* 年龄
*/
String? age;
/**
* 测量日期
*/
String? measureDate;
/**
* 体高(cm)
*/
double? height;
/**
* 体长(cm)
*/
double? length;
/**
* 胸围(cm)
*/
double? bust;
/**
* 体重
*/
double? weight;
/**
* 胸宽(cm)
*/
double? chestWidth;
/**
* 胸深(cm)
*/
double? chestDeep;
/**
* 腰角宽(cm)
*/
double? waistWidth;
/**
* 十字部宽(cm)
*/
double? crossWidth;
/**
* 管维(cm)
*/
double? guanWei;
/**
* 眼肌面积
*/
double? eyeMuscleArea;
/**
* 等级
*/
String? grade;
/**
* 羊毛长度(cm)
*/
double? hairLength;
/**
* 羊毛细度(微米)
*/
double? hairFineness;
/**
* 剪毛量(kg)
*/
double? shearing;
/**
* 背腰宽
*/
double? backWidth;
/**
* 繁殖成绩
*/
String? breedRes;
/**
* 健康状况
*/
String? health;
/**
* 免疫情况
*/
String? immune;
/** 是否上传 0未上传,1已上传 */
String? uploadStatus;
/**
* 部门id
*/
String? deptId;
/** 搜索值 */
String? searchValue;
/** 创建者 */
String? createBy;
/** 创建时间 */
String? createTime;
/** 更新者 */
String? updateBy;
/** 更新时间 */
String? updateTime;
/** 备注 */
String? remark;
}
\ No newline at end of file
......@@ -7,17 +7,18 @@ import 'package:anchor_collect_flutter/pages/sync/sync_view.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import '../../congifs.dart';
import '../message/message_logic.dart';
import 'MyBottomNavigationBarItem.dart';
import 'main_logic.dart';
class MainPage extends StatelessWidget {
final logic = Get.find<MainLogic>();
final state = Get.find<MainLogic>().state;
final homeLogic = Get.find<HomeLogic>();
final messageLogic = Get.find<MessageLogic>();
final syncLogic = Get.find<SyncLogic>();
static final List<Widget> _pageList = [
final logic = Get.find<MainLogic>();
final state = Get.find<MainLogic>().state;
final homeLogic = Get.find<HomeLogic>();
final messageLogic = Get.find<MessageLogic>();
final syncLogic = Get.find<SyncLogic>();
static final List<Widget> _pageList = [
HomePage(),
MessagePage(),
SyncPage(),
......@@ -32,13 +33,12 @@ class MainPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
body: PageView(
controller: _pageController,
onPageChanged: (value) {
state.currentIndex.value = value;
if(value==1){
if (value == 1) {
logic.setMessageStatus(false);
}
},
......@@ -53,25 +53,27 @@ class MainPage extends StatelessWidget {
// 选中颜色
selectedItemColor: Colors.green,
items: [
MyBottomNavigationBarItem('首页', state.currentIndex.value, 0,
'images/home_selected.png', 'images/home.png', false),
MyBottomNavigationBarItem('消息', state.currentIndex.value, 1,
'images/message_selected.png', 'images/message.png', state.isNewMessage.value),
MyBottomNavigationBarItem('同步', state.currentIndex.value, 2,
'images/sync_selected.png', 'images/sync.png', false),
MyBottomNavigationBarItem('我的', state.currentIndex.value, 3,
'images/mine_selected.png', 'images/mine.png', false),
MyBottomNavigationBarItem(
'首页', state.currentIndex.value, 0, 'images/home_selected.png', 'images/home.png', false),
MyBottomNavigationBarItem('消息', state.currentIndex.value, 1, 'images/message_selected.png',
'images/message.png', state.isNewMessage.value),
MyBottomNavigationBarItem(
'同步', state.currentIndex.value, 2, 'images/sync_selected.png', 'images/sync.png', false),
MyBottomNavigationBarItem(
'我的', state.currentIndex.value, 3, 'images/mine_selected.png', 'images/mine.png', false),
],
onTap: (int position) {
switch(position){
switch (position) {
case 0:
homeLogic.getBreedingCount();
break;
case 1:
messageLogic.getMessageCount();
if (Config.isOnLine) {
messageLogic.getMessageCount();
}
break;
case 2:
syncLogic.queryCount();
syncLogic.queryCount();
break;
}
_pageController.jumpToPage(position);
......
import 'package:get/get.dart';
import 'package:package_info/package_info.dart';
import 'package:r_upgrade/r_upgrade.dart';
import '../../api/HttpUtils.dart';
import '../../api/apis.dart';
import '../../utils/dialog_utils.dart';
import 'mine_state.dart';
class MineLogic extends GetxController {
final MineState state = MineState();
checkUpdate() async {
///拉取版本信息
PackageInfo packageInfo = await PackageInfo.fromPlatform();
String buildNumber = packageInfo.buildNumber;
///检查更新
HttpUtils<int>()
..get()
..setUrl(APIS.get_version)
..onResponse((response) {
if (buildNumber != response.toString()) {
// DialogUtils.showToast('最新版本$response');
DialogUtils.showLoadingDialog('正在下载新版本');
upgrade();
} else {
DialogUtils.showToast('已经是最新版本');
}
// var _appName = packageInfo.appName;
// var _packageName = packageInfo.packageName;
})
..onError((msg, code) {
// DialogUtils.dismissDialog();
})
..build();
}
///下载app
void upgrade() async {
int appId = await RUpgrade.upgrade(
'${APIS.baseUrl}/api/download?type=Flutter',
fileName: 'anchor_collect_flutter.apk',
installType: RUpgradeInstallType.normal,
) ??
0;
bool isSuccess = await RUpgrade.install(appId) ?? false;
}
}
import 'package:anchor_collect_flutter/routes/routes.dart';
import 'package:anchor_collect_flutter/utils/dialog_utils.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import '../../congifs.dart';
import '../../utils/sp_helper.dart';
import 'mine_logic.dart';
class MinePage extends StatelessWidget {
......@@ -25,13 +29,13 @@ class MinePage extends StatelessWidget {
children: [
Container(
width: double.infinity,
height: 300,
height: 200,
color: Colors.blue,
),
Expanded(
child: Container(
width: double.infinity,
color: Colors.grey,
color: const Color(0xf5f6f8),
),
),
],
......@@ -39,54 +43,116 @@ class MinePage extends StatelessWidget {
///上层
Column(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.max,
children: [
Row(
children: [
CircleAvatar(
radius: 50, // 头像的半径大小
backgroundImage: AssetImage('assets/images/ic_launcher.png'), // 头像的图片路径
),
Text('用户名'),
Expanded(child: SizedBox()),
Text('个人信息>'),
],
),
Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(8),
),
child: const Column(
Padding(
padding: const EdgeInsets.fromLTRB(20.0, 40.0, 20.0, 20.0),
child: Row(
children: [
ListTile(
title: Text('编辑资料'),
leading: Icon(Icons.account_box),
trailing: Icon(Icons.add),
CircleAvatar(
radius: 35, // 头像的半径大小
backgroundImage: AssetImage('images/ic_launcher.png'), // 头像的图片路径
child: Container(
// 边框容器
decoration: BoxDecoration(
shape: BoxShape.circle,
border: Border.all(
color: Colors.grey, // 边框的颜色
width: 2, // 边框的宽度
),
),
),
),
ListTile(
title: Text('关于我们'),
leading: Icon(Icons.accessibility),
trailing: Icon(Icons.add),
SizedBox(
width: 10,
),
ListTile(
title: Text('修改密码'),
leading: Icon(Icons.account_balance_wallet_outlined),
trailing: Icon(Icons.add),
Text(
'用户名',
style: TextStyle(
fontSize: 20,
color: Colors.white,
),
),
ListTile(
title: Text('检查更新'),
leading: Icon(Icons.ad_units_outlined),
trailing: Icon(Icons.add),
Expanded(child: SizedBox()),
Text(
'个人信息>',
style: TextStyle(
fontSize: 16,
color: Colors.white,
),
),
],
),
),
Padding(
padding: const EdgeInsets.all(20.0),
child: Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(8),
),
child: Column(
children: [
ListTile(
title: const Text('编辑资料'),
leading: const Icon(Icons.account_box),
trailing: const Icon(Icons.add),
onTap: () => {},
),
SizedBox(
height: 1,
child: Container(
height: 1,
color: Colors.black12,
),
),
ListTile(
title: const Text('关于我们'),
leading: const Icon(Icons.accessibility),
trailing: const Icon(Icons.add),
onTap: () => {},
),
SizedBox(
height: 1,
child: Container(
height: 1,
color: Colors.black12,
),
),
ListTile(
title: const Text('修改密码'),
leading: const Icon(Icons.account_balance_wallet_outlined),
trailing: const Icon(Icons.add),
onTap: () => {},
),
SizedBox(
height: 1,
child: Container(
height: 1,
color: Colors.black12,
),
),
ListTile(
title: const Text('检查更新'),
leading: const Icon(Icons.ad_units_outlined),
trailing: const Icon(Icons.add),
onTap: () => {
if(Config.isOnLine){
logic.checkUpdate(),
}
},
),
],
),
),
),
const SizedBox(
height: 100,
height: 30,
),
Row(children: [
const SizedBox(
width: 10,
),
Expanded(
child: TextButton(
style: ButtonStyle(
......@@ -94,10 +160,20 @@ class MinePage extends StatelessWidget {
foregroundColor: MaterialStateProperty.all(Colors.white),
padding: MaterialStateProperty.all(const EdgeInsets.all(8)),
),
onPressed: () => (),
onPressed: () => {
SpHelper.putStorage(Config.SP_STR_USERNAME, ''),
SpHelper.putStorage(Config.SP_STR_PASSWORD, ''),
SpHelper.putStorage(Config.SP_STR_TOKEN, ''),
SpHelper.putStorage(Config.SP_DEPT_ID, ''),
Config.isOnLine = false,
Get.offNamed(AppRoute.LOGIN),
},
child: const Text("退出登录"),
),
),
const SizedBox(
width: 10,
),
]),
],
),
......
......@@ -20,29 +20,18 @@ class SettingLogic extends GetxController {
if (BleService.to.isScanning.value) {
DialogUtils.showToast('停止扫描');
} else {
state.deviceList.clear();
BleService.to.scanResults.clear();
DialogUtils.showToast('开始扫描');
}
BleService.to.toggleScan((device) => {
// 如果列表中没有该设备,则添加到列表中
if (!state.deviceList.any((element) => element.id == device.id))
{
state.deviceList.add(device),
state.deviceList.refresh(), // 手动触发 Obx 的更新
}
});
BleService.to.toggleScan();
}
connectBle(BuildContext context, int index) {
if (BleService.to.deviceStatus == 'Connected') {
if (state.deviceList[index].id != BleService.to.selectedDevice.value!.id) {
BleService.to.streamSubscriptionConnection.cancel();
} else {
DialogUtils.showToast('请勿重复链接蓝牙设备');
return;
}
if (BleService.to.isConnect) {
BleService.to.stopScan();
}
BleService.to.connectToDevice(state.deviceList[index], context, (args) {
BleService.to.connectToDevice(index, (args) {
BleService.to.isConnect = true;
DialogUtils.showToast('蓝牙设备连接成功');
// DialogUtils.dismissDialog();
Get.back();
......
......@@ -4,7 +4,6 @@ import 'package:get/get.dart';
class SettingState {
final deviceList = <DiscoveredDevice>[].obs;
bool isBleOn = false;
......
import 'dart:ffi';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
......@@ -27,11 +29,11 @@ class SettingPage extends StatelessWidget {
Obx(() {
return Expanded(
child: ListView.separated(
itemCount: state.deviceList.length,
itemCount: BleService.to.scanResults.length,
itemBuilder: (BuildContext context, int index) {
return ListTile(
title: Text(state.deviceList[index].name),
subtitle: Text(state.deviceList[index].id),
title: Text(BleService.to.scanResults[index].device.advName),
subtitle: Text(BleService.to.scanResults[index].device.platformName),
onTap: ()=>{
logic.connectBle(context,index),
},
......@@ -80,7 +82,7 @@ class SettingPage extends StatelessWidget {
// ),
TextButton(
onPressed: () => {
state.deviceList.clear(),
BleService.to.scanResults.clear(),
},
child: const Text(
'清空',
......
......@@ -17,7 +17,7 @@ class RfidPlugin {
late StreamSubscription<dynamic> _streamSubscription;
String rfidTagTemp = '';
static String rfidTagTemp = '';
RfidPlugin() {
_streamSubscription = _eventChannel.receiveBroadcastStream().listen((event) async {
......@@ -33,27 +33,27 @@ class RfidPlugin {
}, onError: errorEventListen, onDone: doneEventListen);
}
Future<void> initRfid() async {
static Future<void> initRfid() async {
await _methodChannel.invokeMethod('init_rfid');
}
Future<String> getVersion() async {
static Future<String> getVersion() async {
String version = await _methodChannel.invokeMethod('get_version');
return version;
}
Future<void> startInventory(EventCallback callback) async {
static Future<void> startInventory(EventCallback callback) async {
_callback = callback;
rfidTagTemp = '';
await _methodChannel.invokeMethod('start_inventory');
}
Future<void> stopInventory() async {
static Future<void> stopInventory() async {
await _methodChannel.invokeMethod('stop_inventory');
}
Future<void> pushRemoteRFIDData() async {
List<int> readData = await BleService.to.readData();
static Future<void> pushRemoteRFIDData(List<int> readData) async {
// List<int> readData = await BleService.to.readData();
Map params = {
"value":readData,
};
......
......@@ -6,6 +6,7 @@ import FlutterMacOS
import Foundation
import device_info_plus
import flutter_blue_plus
import flutter_image_compress_macos
import isar_flutter_libs
import package_info
......@@ -15,6 +16,7 @@ import sqflite
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
DeviceInfoPlusMacosPlugin.register(with: registry.registrar(forPlugin: "DeviceInfoPlusMacosPlugin"))
FlutterBluePlusPlugin.register(with: registry.registrar(forPlugin: "FlutterBluePlusPlugin"))
FlutterImageCompressMacosPlugin.register(with: registry.registrar(forPlugin: "FlutterImageCompressMacosPlugin"))
IsarFlutterLibsPlugin.register(with: registry.registrar(forPlugin: "IsarFlutterLibsPlugin"))
FLTPackageInfoPlugin.register(with: registry.registrar(forPlugin: "FLTPackageInfoPlugin"))
......
......@@ -342,14 +342,14 @@ packages:
description: flutter
source: sdk
version: "0.0.0"
flutter_blue:
flutter_blue_plus:
dependency: "direct main"
description:
name: flutter_blue
sha256: f7f76b9b80455b0375693ec96c276fadb01e94d8441fa1740a64980cd1aeda5c
name: flutter_blue_plus
sha256: c4b25ca6bf232bda4919e656179221aabeceb8271476b641ac59ae8aad085329
url: "https://pub.flutter-io.cn"
source: hosted
version: "0.8.0"
version: "1.31.2"
flutter_cache_manager:
dependency: transitive
description:
......
......@@ -57,7 +57,9 @@ dependencies:
package_info: ^2.0.2 #获取包名
device_info_plus: ^8.2.2 #获取设备信息(版本号等)
r_upgrade: ^0.4.2 #版本更新
flutter_blue: ^0.8.0
# flutter_blue: ^0.8.0
flutter_blue_plus: 1.31.2
dev_dependencies:
flutter_test:
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment