Skip to content
This repository was archived by the owner on Dec 23, 2024. It is now read-only.

Commit e8cfecf

Browse files
authored
Merge pull request #25 from Myzel394/add-bluetooth-share
Add bluetooth share
2 parents bc8d7af + af78aa8 commit e8cfecf

File tree

13 files changed

+569
-87
lines changed

13 files changed

+569
-87
lines changed

lib/extensions/string.dart

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
extension StringExtensions on String {
2+
String capitalize() {
3+
return "${this[0].toUpperCase()}${substring(1)}";
4+
}
5+
}

lib/l10n/app_en.arb

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,15 @@
181181
"transferScreen_send_startTransfer": "Transfer",
182182
"transferScreen_receive_connect_description": "Received a transfer request. This is the PIN. Make sure the PIN matches the one on your old device. If it does, tap \"Connect\".",
183183
"transferScreen_receive_connected_label": "Please start the transfer on your old device now.",
184+
"importTask_bluetooth_receive_title": "Receive View Key",
185+
"importTask_bluetooth_receive_description": "Receive a view key from another device via Bluetooth. Ask the other person to open a task. Then go to details, tap on share location and select Bluetooth. Make sure you have Bluetooth enabled.",
186+
"importTask_bluetooth_receive_id_description": "This is your name visible to others:",
187+
"importTask_bluetooth_send_title": "Share location via Bluetooth",
188+
"importTask_bluetooth_send_description": "Make sure you have Bluetooth enabled. Looking for devices...",
189+
"importTask_bluetooth_receive_request_title": "Do you want to accept the request?",
190+
"importTask_bluetooth_receive_request_description": "A connect request to share a location has been made. We can't tell what location is being shared until you accept the connection. If you expected this connection, you can connect. Otherwise, the request will be rejected.",
191+
"importTask_bluetooth_receive_request_decline": "Decline",
192+
"importTask_bluetooth_receive_request_accept": "Accept",
184193
"mainScreen_overview": "Overview",
185194
"mainScreen_createTask": "Create Task",
186195
"mainScreen_logs": "Logs",
@@ -199,6 +208,7 @@
199208
"mainScreen_importTask_action_importMethod_url": "Import URL",
200209
"mainScreen_importTask_action_importMethod_url_title": "Enter the URL of the task",
201210
"mainScreen_importTask_action_importMethod_file": "Import file",
211+
"mainScreen_importTask_action_importMethod_bluetooth": "Receive via Bluetooth",
202212
"mainScreen_importTask_action_importMethod_file_selectFile": "Select a ViewKey file to import",
203213
"mainScreen_importTask_action_import_isLoading": "Importing...",
204214
"mainScreen_importTask_action_name_title": "Enter a name for this view",
@@ -318,6 +328,7 @@
318328
"shareLocation_actions_shareFile_text": "Here's my Locus View Key to see my location",
319329
"shareLocation_actions_shareLink": "Share Link",
320330
"shareLocation_actions_shareLink_text": "Here's my Locus link to see my location",
331+
"shareLocation_actions_shareBluetooth": "Share via Bluetooth",
321332
"shareLocation_scanToImport": "Scan this QR Code to import task {task}",
322333
"@shareLocation_scanToImport": {
323334
"placeholders": {

lib/screens/ImportTaskSheet.dart

Lines changed: 49 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,14 @@ import 'package:provider/provider.dart';
1616

1717
import '../services/task_service.dart';
1818
import '../widgets/ModalSheet.dart';
19+
import 'import_task_sheet_widgets/ReceiveViewByBluetooth.dart';
1920

2021
enum ImportScreen {
2122
ask,
2223
importFile,
2324
askURL,
2425
askName,
26+
bluetoothReceive,
2527
present,
2628
error,
2729
done,
@@ -43,8 +45,7 @@ class ImportTaskSheet extends StatefulWidget {
4345
State<ImportTaskSheet> createState() => _ImportTaskSheetState();
4446
}
4547

46-
class _ImportTaskSheetState extends State<ImportTaskSheet>
47-
with TickerProviderStateMixin {
48+
class _ImportTaskSheetState extends State<ImportTaskSheet> with TickerProviderStateMixin {
4849
final _nameController = TextEditingController();
4950
final _urlController = TextEditingController();
5051
ImportScreen _screen = ImportScreen.ask;
@@ -111,11 +112,40 @@ class _ImportTaskSheetState extends State<ImportTaskSheet>
111112
super.dispose();
112113
}
113114

114-
void _importFile() async {
115+
void parseViewData(final TaskView taskView) async {
115116
final l10n = AppLocalizations.of(context);
116117
final taskService = context.read<TaskService>();
117118
final viewService = context.read<ViewService>();
118119

120+
try {
121+
final errorMessage = await taskView.validate(
122+
taskService: taskService,
123+
viewService: viewService,
124+
);
125+
126+
if (errorMessage != null) {
127+
setState(() {
128+
this.errorMessage = errorMessage;
129+
});
130+
131+
return;
132+
} else {
133+
setState(() {
134+
_taskView = taskView;
135+
_screen = ImportScreen.present;
136+
});
137+
}
138+
} catch (_) {
139+
setState(() {
140+
errorMessage = l10n.unknownError;
141+
_screen = ImportScreen.error;
142+
});
143+
}
144+
}
145+
146+
void _importFile() async {
147+
final l10n = AppLocalizations.of(context);
148+
119149
FilePickerResult? result;
120150

121151
setState(() {
@@ -128,8 +158,7 @@ class _ImportTaskSheetState extends State<ImportTaskSheet>
128158
result = await FilePicker.platform.pickFiles(
129159
type: FileType.custom,
130160
allowedExtensions: ["json"],
131-
dialogTitle:
132-
l10n.mainScreen_importTask_action_importMethod_file_selectFile,
161+
dialogTitle: l10n.mainScreen_importTask_action_importMethod_file_selectFile,
133162
withData: true,
134163
);
135164
} catch (_) {
@@ -143,31 +172,9 @@ class _ImportTaskSheetState extends State<ImportTaskSheet>
143172
reset();
144173
} else {
145174
final rawData = const Utf8Decoder().convert(result.files[0].bytes!);
146-
final data = jsonDecode(rawData);
175+
final taskView = TaskView.fromJSON(jsonDecode(rawData));
147176

148-
final taskView = TaskView(
149-
relays: List<String>.from(data["relays"]),
150-
nostrPublicKey: data["nostrPublicKey"],
151-
encryptionPassword: data["encryptionPassword"],
152-
);
153-
154-
final errorMessage = await taskView.validate(
155-
taskService: taskService,
156-
viewService: viewService,
157-
);
158-
159-
if (errorMessage != null) {
160-
setState(() {
161-
this.errorMessage = errorMessage;
162-
});
163-
164-
return;
165-
} else {
166-
setState(() {
167-
_taskView = taskView;
168-
_screen = ImportScreen.present;
169-
});
170-
}
177+
parseViewData(taskView);
171178
}
172179
} catch (_) {
173180
} finally {
@@ -180,8 +187,6 @@ class _ImportTaskSheetState extends State<ImportTaskSheet>
180187
Future<void> _importURL() async {
181188
final url = _urlController.text;
182189
final l10n = AppLocalizations.of(context);
183-
final taskService = context.read<TaskService>();
184-
final viewService = context.read<ViewService>();
185190

186191
try {
187192
setState(() {
@@ -191,22 +196,8 @@ class _ImportTaskSheetState extends State<ImportTaskSheet>
191196

192197
final parameters = TaskView.parseLink(url);
193198
final taskView = await TaskView.fetchFromNostr(parameters);
194-
final errorMessage = await taskView.validate(
195-
taskService: taskService,
196-
viewService: viewService,
197-
);
198199

199-
if (errorMessage == null) {
200-
setState(() {
201-
_taskView = taskView;
202-
_screen = ImportScreen.present;
203-
});
204-
} else {
205-
setState(() {
206-
this.errorMessage = errorMessage;
207-
_screen = ImportScreen.error;
208-
});
209-
}
200+
parseViewData(taskView);
210201
} catch (_) {
211202
setState(() {
212203
errorMessage = l10n.unknownError;
@@ -247,6 +238,11 @@ class _ImportTaskSheetState extends State<ImportTaskSheet>
247238
_screen = ImportScreen.askURL;
248239
});
249240
break;
241+
case ImportSelectionType.bluetooth:
242+
setState(() {
243+
_screen = ImportScreen.bluetoothReceive;
244+
});
245+
break;
250246
}
251247
},
252248
)
@@ -278,11 +274,14 @@ class _ImportTaskSheetState extends State<ImportTaskSheet>
278274
else if (errorMessage != null)
279275
Text(
280276
errorMessage!,
281-
style: getBodyTextTextStyle(context)
282-
.copyWith(color: getErrorColor(context)),
277+
style: getBodyTextTextStyle(context).copyWith(color: getErrorColor(context)),
283278
),
284279
],
285280
)
281+
else if (_screen == ImportScreen.bluetoothReceive)
282+
ReceiveViewByBluetooth(
283+
onImport: parseViewData,
284+
)
286285
else if (_screen == ImportScreen.present)
287286
ViewImportOverview(
288287
view: _taskView!,
@@ -305,8 +304,7 @@ class _ImportTaskSheetState extends State<ImportTaskSheet>
305304
else if (_screen == ImportScreen.error)
306305
Column(
307306
children: <Widget>[
308-
Icon(context.platformIcons.error,
309-
size: 64, color: getErrorColor(context)),
307+
Icon(context.platformIcons.error, size: 64, color: getErrorColor(context)),
310308
const SizedBox(height: MEDIUM_SPACE),
311309
Text(
312310
l10n.taskImportError,
@@ -315,8 +313,7 @@ class _ImportTaskSheetState extends State<ImportTaskSheet>
315313
const SizedBox(height: SMALL_SPACE),
316314
Text(
317315
errorMessage!,
318-
style: getBodyTextTextStyle(context)
319-
.copyWith(color: getErrorColor(context)),
316+
style: getBodyTextTextStyle(context).copyWith(color: getErrorColor(context)),
320317
),
321318
const SizedBox(height: LARGE_SPACE),
322319
PlatformElevatedButton(

lib/screens/import_task_sheet_widgets/ImportSelection.dart

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import 'dart:io';
2+
13
import 'package:flutter/material.dart';
24
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
35
import 'package:flutter_platform_widgets/flutter_platform_widgets.dart';
@@ -8,6 +10,7 @@ import '../../utils/theme.dart';
810
enum ImportSelectionType {
911
url,
1012
file,
13+
bluetooth,
1114
}
1215

1316
class ImportSelection extends StatefulWidget {
@@ -44,8 +47,7 @@ class _ImportSelectionState extends State<ImportSelection> {
4447
if (errorMessage != null) ...[
4548
Text(
4649
errorMessage!,
47-
style: getBodyTextTextStyle(context)
48-
.copyWith(color: getErrorColor(context)),
50+
style: getBodyTextTextStyle(context).copyWith(color: getErrorColor(context)),
4951
),
5052
const SizedBox(height: MEDIUM_SPACE),
5153
],
@@ -74,6 +76,17 @@ class _ImportSelectionState extends State<ImportSelection> {
7476
},
7577
child: Text(l10n.mainScreen_importTask_action_importMethod_file),
7678
),
79+
if (Platform.isAndroid)
80+
PlatformElevatedButton(
81+
padding: const EdgeInsets.all(MEDIUM_SPACE),
82+
material: (_, __) => MaterialElevatedButtonData(
83+
icon: const Icon(Icons.bluetooth_audio_rounded),
84+
),
85+
onPressed: () async {
86+
widget.onSelect(ImportSelectionType.bluetooth);
87+
},
88+
child: Text(l10n.mainScreen_importTask_action_importMethod_bluetooth),
89+
)
7790
],
7891
),
7992
],

0 commit comments

Comments
 (0)