mirror of
https://github.com/twonlyapp/twonly-app.git
synced 2026-01-15 09:28:41 +00:00
fixing multiple issues
This commit is contained in:
parent
e9fd8726c9
commit
a71eb1fe94
7 changed files with 120 additions and 110 deletions
|
|
@ -33,7 +33,7 @@ android {
|
||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
|
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
|
||||||
applicationId = "eu.twonly.testing"
|
applicationId = "eu.twonly"
|
||||||
multiDexEnabled true
|
multiDexEnabled true
|
||||||
// You can update the following values to match your application needs.
|
// You can update the following values to match your application needs.
|
||||||
// For more information, see: https://flutter.dev/to/review-gradle-config.
|
// For more information, see: https://flutter.dev/to/review-gradle-config.
|
||||||
|
|
@ -53,7 +53,7 @@ android {
|
||||||
|
|
||||||
buildTypes {
|
buildTypes {
|
||||||
debug {
|
debug {
|
||||||
applicationIdSuffix ".debug"
|
applicationIdSuffix ".testing"
|
||||||
}
|
}
|
||||||
release {
|
release {
|
||||||
signingConfig signingConfigs.release
|
signingConfig signingConfigs.release
|
||||||
|
|
|
||||||
|
|
@ -497,11 +497,18 @@ class ApiService {
|
||||||
return sendRequestSync(req);
|
return sendRequestSync(req);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<Result> getUserData(String username) async {
|
Future<Response_UserData?> getUserData(String username) async {
|
||||||
final get = ApplicationData_GetUserByUsername()..username = username;
|
final get = ApplicationData_GetUserByUsername()..username = username;
|
||||||
final appData = ApplicationData()..getuserbyusername = get;
|
final appData = ApplicationData()..getuserbyusername = get;
|
||||||
final req = createClientToServerFromApplicationData(appData);
|
final req = createClientToServerFromApplicationData(appData);
|
||||||
return sendRequestSync(req);
|
final res = await sendRequestSync(req);
|
||||||
|
if (res.isSuccess) {
|
||||||
|
final ok = res.value as server.Response_Ok;
|
||||||
|
if (ok.hasUserdata()) {
|
||||||
|
return ok.userdata;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<Response_PlanBallance?> getPlanBallance() async {
|
Future<Response_PlanBallance?> getPlanBallance() async {
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ import 'package:cryptography_flutter_plus/cryptography_flutter_plus.dart';
|
||||||
import 'package:cryptography_plus/cryptography_plus.dart';
|
import 'package:cryptography_plus/cryptography_plus.dart';
|
||||||
import 'package:drift/drift.dart';
|
import 'package:drift/drift.dart';
|
||||||
import 'package:http/http.dart' as http;
|
import 'package:http/http.dart' as http;
|
||||||
|
import 'package:mutex/mutex.dart';
|
||||||
import 'package:path/path.dart';
|
import 'package:path/path.dart';
|
||||||
import 'package:path_provider/path_provider.dart';
|
import 'package:path_provider/path_provider.dart';
|
||||||
import 'package:twonly/globals.dart';
|
import 'package:twonly/globals.dart';
|
||||||
|
|
@ -20,11 +21,8 @@ import 'package:twonly/src/utils/log.dart';
|
||||||
import 'package:twonly/src/utils/storage.dart';
|
import 'package:twonly/src/utils/storage.dart';
|
||||||
import 'package:twonly/src/views/camera/share_image_editor_view.dart';
|
import 'package:twonly/src/views/camera/share_image_editor_view.dart';
|
||||||
|
|
||||||
Map<int, DateTime> downloadStartedForMediaReceived = {};
|
|
||||||
|
|
||||||
Future<void> tryDownloadAllMediaFiles({bool force = false}) async {
|
Future<void> tryDownloadAllMediaFiles({bool force = false}) async {
|
||||||
// This is called when WebSocket is newly connected, so allow all downloads to be restarted.
|
// This is called when WebSocket is newly connected, so allow all downloads to be restarted.
|
||||||
downloadStartedForMediaReceived = {};
|
|
||||||
final messages =
|
final messages =
|
||||||
await twonlyDB.messagesDao.getAllMessagesPendingDownloading();
|
await twonlyDB.messagesDao.getAllMessagesPendingDownloading();
|
||||||
|
|
||||||
|
|
@ -102,13 +100,15 @@ Future<void> handleDownloadStatusUpdate(TaskStatusUpdate update) async {
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> handleDownloadStatusUpdateInternal(
|
Future<void> handleDownloadStatusUpdateInternal(
|
||||||
int messageId, bool failed) async {
|
int messageId,
|
||||||
|
bool failed,
|
||||||
|
) async {
|
||||||
if (failed) {
|
if (failed) {
|
||||||
Log.error('Download failed for $messageId');
|
Log.error('Download failed for $messageId');
|
||||||
final message = await twonlyDB.messagesDao
|
final message = await twonlyDB.messagesDao
|
||||||
.getMessageByMessageId(messageId)
|
.getMessageByMessageId(messageId)
|
||||||
.getSingleOrNull();
|
.getSingleOrNull();
|
||||||
if (message != null) {
|
if (message != null && message.downloadState != DownloadState.downloaded) {
|
||||||
await handleMediaError(message);
|
await handleMediaError(message);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -117,18 +117,10 @@ Future<void> handleDownloadStatusUpdateInternal(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> startDownloadMedia(Message message, bool force,
|
Mutex protectDownload = Mutex();
|
||||||
{int retryCounter = 0}) async {
|
|
||||||
|
Future<void> startDownloadMedia(Message message, bool force) async {
|
||||||
if (message.contentJson == null) return;
|
if (message.contentJson == null) return;
|
||||||
if (downloadStartedForMediaReceived[message.messageId] != null &&
|
|
||||||
retryCounter == 0) {
|
|
||||||
final started = downloadStartedForMediaReceived[message.messageId]!;
|
|
||||||
final elapsed = DateTime.now().difference(started);
|
|
||||||
if (elapsed <= const Duration(seconds: 60)) {
|
|
||||||
Log.error('Download already started...');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
final content = MessageContent.fromJson(
|
final content = MessageContent.fromJson(
|
||||||
message.kind, jsonDecode(message.contentJson!) as Map);
|
message.kind, jsonDecode(message.contentJson!) as Map);
|
||||||
|
|
@ -157,16 +149,33 @@ Future<void> startDownloadMedia(Message message, bool force,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (message.downloadState != DownloadState.downloaded) {
|
final isBlocked = await protectDownload.protect<bool>(() async {
|
||||||
|
final msg = await twonlyDB.messagesDao
|
||||||
|
.getMessageByMessageId(message.messageId)
|
||||||
|
.getSingleOrNull();
|
||||||
|
|
||||||
|
if (msg == null) return true;
|
||||||
|
|
||||||
|
if (msg.downloadState != DownloadState.pending) {
|
||||||
|
Log.error(
|
||||||
|
'${message.messageId} is already downloaded or is downloading.');
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
await twonlyDB.messagesDao.updateMessageByMessageId(
|
await twonlyDB.messagesDao.updateMessageByMessageId(
|
||||||
message.messageId,
|
message.messageId,
|
||||||
const MessagesCompanion(
|
const MessagesCompanion(
|
||||||
downloadState: Value(DownloadState.downloading),
|
downloadState: Value(DownloadState.downloading),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
|
||||||
|
|
||||||
downloadStartedForMediaReceived[message.messageId] = DateTime.now();
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (isBlocked) {
|
||||||
|
Log.info('Download for ${message.messageId} already started.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
final downloadToken = uint8ListToHex(content.downloadToken!);
|
final downloadToken = uint8ListToHex(content.downloadToken!);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -43,8 +43,14 @@ class CameraSendToViewState extends State<CameraSendToView> {
|
||||||
return cameraController;
|
return cameraController;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// same function also in home.view.dart
|
||||||
Future<void> toggleSelectedCamera() async {
|
Future<void> toggleSelectedCamera() async {
|
||||||
await cameraController?.dispose();
|
if (cameraController == null) return;
|
||||||
|
// do not allow switching camera when recording
|
||||||
|
if (cameraController!.value.isRecordingVideo == true) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
await cameraController!.dispose();
|
||||||
cameraController = null;
|
cameraController = null;
|
||||||
await selectCamera((selectedCameraDetails.cameraId + 1) % 2, false, false);
|
await selectCamera((selectedCameraDetails.cameraId + 1) % 2, false, false);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -50,7 +50,7 @@ class _LocationFilterState extends State<LocationFilter> {
|
||||||
for (final item in imageIndex) {
|
for (final item in imageIndex) {
|
||||||
if (item.imageSrc.contains('/cities/$normalizedCountry/')) {
|
if (item.imageSrc.contains('/cities/$normalizedCountry/')) {
|
||||||
// Check if the item matches the normalized city
|
// Check if the item matches the normalized city
|
||||||
if (item.imageSrc.endsWith('$normalizedCity.png')) {
|
if (item.imageSrc.contains('$normalizedCity.')) {
|
||||||
if (item.imageSrc.startsWith('/api/')) {
|
if (item.imageSrc.startsWith('/api/')) {
|
||||||
_imageUrl = 'https://twonly.eu/${item.imageSrc}';
|
_imageUrl = 'https://twonly.eu/${item.imageSrc}';
|
||||||
if (mounted) setState(() {});
|
if (mounted) setState(() {});
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,3 @@
|
||||||
// ignore_for_file: avoid_dynamic_calls
|
|
||||||
|
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:drift/drift.dart' hide Column;
|
import 'package:drift/drift.dart' hide Column;
|
||||||
|
|
@ -11,7 +9,6 @@ import 'package:twonly/src/database/daos/contacts_dao.dart';
|
||||||
import 'package:twonly/src/database/tables/messages_table.dart';
|
import 'package:twonly/src/database/tables/messages_table.dart';
|
||||||
import 'package:twonly/src/database/twonly_database.dart';
|
import 'package:twonly/src/database/twonly_database.dart';
|
||||||
import 'package:twonly/src/model/json/message.dart';
|
import 'package:twonly/src/model/json/message.dart';
|
||||||
import 'package:twonly/src/model/protobuf/api/websocket/server_to_client.pb.dart';
|
|
||||||
import 'package:twonly/src/model/protobuf/push_notification/push_notification.pbserver.dart';
|
import 'package:twonly/src/model/protobuf/push_notification/push_notification.pbserver.dart';
|
||||||
import 'package:twonly/src/services/api/messages.dart';
|
import 'package:twonly/src/services/api/messages.dart';
|
||||||
import 'package:twonly/src/services/api/utils.dart';
|
import 'package:twonly/src/services/api/utils.dart';
|
||||||
|
|
@ -41,7 +38,11 @@ class _SearchUsernameView extends State<AddNewUserView> {
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
initStreams();
|
contactsStream = twonlyDB.contactsDao
|
||||||
|
.watchNotAcceptedContacts()
|
||||||
|
.listen((update) => setState(() {
|
||||||
|
contacts = update;
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|
@ -50,18 +51,9 @@ class _SearchUsernameView extends State<AddNewUserView> {
|
||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
void initStreams() {
|
|
||||||
contactsStream =
|
|
||||||
twonlyDB.contactsDao.watchNotAcceptedContacts().listen((update) {
|
|
||||||
setState(() {
|
|
||||||
contacts = update;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> _addNewUser(BuildContext context) async {
|
Future<void> _addNewUser(BuildContext context) async {
|
||||||
final user = await getUser();
|
final user = await getUser();
|
||||||
if (user == null || user.username == searchUserName.text) {
|
if (user == null || user.username == searchUserName.text || !mounted) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -69,70 +61,67 @@ class _SearchUsernameView extends State<AddNewUserView> {
|
||||||
_isLoading = true;
|
_isLoading = true;
|
||||||
});
|
});
|
||||||
|
|
||||||
final res = await apiService.getUserData(searchUserName.text);
|
final userdata = await apiService.getUserData(searchUserName.text);
|
||||||
|
if (!context.mounted) return;
|
||||||
|
|
||||||
if (!context.mounted) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (res.isSuccess) {
|
|
||||||
final addUser = await showAlertDialog(
|
|
||||||
context, context.lang.userFound, context.lang.userFoundBody);
|
|
||||||
if (!addUser || !context.mounted) {
|
|
||||||
setState(() {
|
|
||||||
_isLoading = false;
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
final added = await twonlyDB.contactsDao.insertContact(
|
|
||||||
ContactsCompanion(
|
|
||||||
username: Value(searchUserName.text),
|
|
||||||
userId: Value(res.value.userdata.userId.toInt() as int),
|
|
||||||
requested: const Value(false),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
if (added > 0) {
|
|
||||||
if (await createNewSignalSession(
|
|
||||||
res.value.userdata as Response_UserData)) {
|
|
||||||
// before notifying the other party, add
|
|
||||||
await setupNotificationWithUsers(
|
|
||||||
forceContact: res.value.userdata.userId.toInt() as int,
|
|
||||||
);
|
|
||||||
await encryptAndSendMessageAsync(
|
|
||||||
null,
|
|
||||||
res.value.userdata.userId.toInt() as int,
|
|
||||||
MessageJson(
|
|
||||||
kind: MessageKind.contactRequest,
|
|
||||||
timestamp: DateTime.now(),
|
|
||||||
content: MessageContent(),
|
|
||||||
),
|
|
||||||
pushNotification: PushNotification(kind: PushKind.contactRequest),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
await showAlertDialog(context, context.lang.searchUsernameNotFound,
|
|
||||||
context.lang.searchUsernameNotFoundBody(searchUserName.text));
|
|
||||||
}
|
|
||||||
setState(() {
|
setState(() {
|
||||||
_isLoading = false;
|
_isLoading = false;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (userdata == null) {
|
||||||
|
await showAlertDialog(context, context.lang.searchUsernameNotFound,
|
||||||
|
context.lang.searchUsernameNotFoundBody(searchUserName.text));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final addUser = await showAlertDialog(
|
||||||
|
context,
|
||||||
|
context.lang.userFound,
|
||||||
|
context.lang.userFoundBody,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!addUser || !context.mounted) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final added = await twonlyDB.contactsDao.insertContact(
|
||||||
|
ContactsCompanion(
|
||||||
|
username: Value(searchUserName.text),
|
||||||
|
userId: Value(userdata.userId.toInt()),
|
||||||
|
requested: const Value(false),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (added > 0) {
|
||||||
|
if (await createNewSignalSession(userdata)) {
|
||||||
|
// before notifying the other party, add
|
||||||
|
await setupNotificationWithUsers(
|
||||||
|
forceContact: userdata.userId.toInt(),
|
||||||
|
);
|
||||||
|
await encryptAndSendMessageAsync(
|
||||||
|
null,
|
||||||
|
userdata.userId.toInt(),
|
||||||
|
MessageJson(
|
||||||
|
kind: MessageKind.contactRequest,
|
||||||
|
timestamp: DateTime.now(),
|
||||||
|
content: MessageContent(),
|
||||||
|
),
|
||||||
|
pushNotification: PushNotification(kind: PushKind.contactRequest),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
InputDecoration getInputDecoration(String hintText) {
|
InputDecoration getInputDecoration(String hintText) {
|
||||||
final primaryColor =
|
|
||||||
Theme.of(context).colorScheme.primary; // Get the primary color
|
|
||||||
return InputDecoration(
|
return InputDecoration(
|
||||||
hintText: hintText,
|
hintText: hintText,
|
||||||
focusedBorder: OutlineInputBorder(
|
focusedBorder: OutlineInputBorder(
|
||||||
borderRadius: BorderRadius.circular(9),
|
borderRadius: BorderRadius.circular(9),
|
||||||
borderSide: BorderSide(color: primaryColor),
|
borderSide: BorderSide(color: context.color.primary),
|
||||||
),
|
),
|
||||||
enabledBorder: OutlineInputBorder(
|
enabledBorder: OutlineInputBorder(
|
||||||
borderRadius: BorderRadius.circular(8),
|
borderRadius: BorderRadius.circular(8),
|
||||||
borderSide: BorderSide(color: Theme.of(context).colorScheme.outline),
|
borderSide: BorderSide(color: context.color.outline),
|
||||||
),
|
),
|
||||||
contentPadding: const EdgeInsets.symmetric(vertical: 15, horizontal: 20),
|
contentPadding: const EdgeInsets.symmetric(vertical: 15, horizontal: 20),
|
||||||
);
|
);
|
||||||
|
|
@ -146,8 +135,7 @@ class _SearchUsernameView extends State<AddNewUserView> {
|
||||||
),
|
),
|
||||||
body: SafeArea(
|
body: SafeArea(
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding:
|
padding: const EdgeInsets.symmetric(vertical: 20, horizontal: 10),
|
||||||
const EdgeInsets.only(bottom: 20, left: 10, top: 20, right: 10),
|
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
Padding(
|
Padding(
|
||||||
|
|
@ -186,10 +174,7 @@ class _SearchUsernameView extends State<AddNewUserView> {
|
||||||
floatingActionButton: Padding(
|
floatingActionButton: Padding(
|
||||||
padding: const EdgeInsets.only(bottom: 30),
|
padding: const EdgeInsets.only(bottom: 30),
|
||||||
child: FloatingActionButton(
|
child: FloatingActionButton(
|
||||||
foregroundColor: Colors.white,
|
onPressed: _isLoading ? null : () async => _addNewUser(context),
|
||||||
onPressed: () {
|
|
||||||
if (!_isLoading) _addNewUser(context);
|
|
||||||
},
|
|
||||||
child: _isLoading
|
child: _isLoading
|
||||||
? const Center(child: CircularProgressIndicator())
|
? const Center(child: CircularProgressIndicator())
|
||||||
: const FaIcon(FontAwesomeIcons.magnifyingGlassPlus),
|
: const FaIcon(FontAwesomeIcons.magnifyingGlassPlus),
|
||||||
|
|
@ -199,17 +184,11 @@ class _SearchUsernameView extends State<AddNewUserView> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class ContactsListView extends StatefulWidget {
|
class ContactsListView extends StatelessWidget {
|
||||||
const ContactsListView(this.contacts, {super.key});
|
const ContactsListView(this.contacts, {super.key});
|
||||||
|
|
||||||
final List<Contact> contacts;
|
final List<Contact> contacts;
|
||||||
|
|
||||||
@override
|
List<Widget> sendRequestActions(BuildContext context, Contact contact) {
|
||||||
State<ContactsListView> createState() => _ContactsListViewState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _ContactsListViewState extends State<ContactsListView> {
|
|
||||||
List<Widget> sendRequestActions(Contact contact) {
|
|
||||||
return [
|
return [
|
||||||
Tooltip(
|
Tooltip(
|
||||||
message: context.lang.searchUserNameArchiveUserTooltip,
|
message: context.lang.searchUserNameArchiveUserTooltip,
|
||||||
|
|
@ -225,7 +204,7 @@ class _ContactsListViewState extends State<ContactsListView> {
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
List<Widget> requestedActions(Contact contact) {
|
List<Widget> requestedActions(BuildContext context, Contact contact) {
|
||||||
return [
|
return [
|
||||||
Tooltip(
|
Tooltip(
|
||||||
message: context.lang.searchUserNameBlockUserTooltip,
|
message: context.lang.searchUserNameBlockUserTooltip,
|
||||||
|
|
@ -272,9 +251,9 @@ class _ContactsListViewState extends State<ContactsListView> {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return ListView.builder(
|
return ListView.builder(
|
||||||
itemCount: widget.contacts.length,
|
itemCount: contacts.length,
|
||||||
itemBuilder: (context, index) {
|
itemBuilder: (context, index) {
|
||||||
final contact = widget.contacts[index];
|
final contact = contacts[index];
|
||||||
final displayName = getContactDisplayName(contact);
|
final displayName = getContactDisplayName(contact);
|
||||||
return ListTile(
|
return ListTile(
|
||||||
title: Text(displayName),
|
title: Text(displayName),
|
||||||
|
|
@ -282,8 +261,8 @@ class _ContactsListViewState extends State<ContactsListView> {
|
||||||
trailing: Row(
|
trailing: Row(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: contact.requested
|
children: contact.requested
|
||||||
? requestedActions(contact)
|
? requestedActions(context, contact)
|
||||||
: sendRequestActions(contact),
|
: sendRequestActions(context, contact),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -112,7 +112,10 @@ class HomeViewState extends State<HomeView> {
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<CameraController?> selectCamera(
|
Future<CameraController?> selectCamera(
|
||||||
int sCameraId, bool init, bool enableAudio) async {
|
int sCameraId,
|
||||||
|
bool init,
|
||||||
|
bool enableAudio,
|
||||||
|
) async {
|
||||||
final opts = await initializeCameraController(
|
final opts = await initializeCameraController(
|
||||||
selectedCameraDetails, sCameraId, init, enableAudio);
|
selectedCameraDetails, sCameraId, init, enableAudio);
|
||||||
if (opts != null) {
|
if (opts != null) {
|
||||||
|
|
@ -124,8 +127,14 @@ class HomeViewState extends State<HomeView> {
|
||||||
return cameraController;
|
return cameraController;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// same function also in camera_send_to_view
|
||||||
Future<void> toggleSelectedCamera() async {
|
Future<void> toggleSelectedCamera() async {
|
||||||
await cameraController?.dispose();
|
if (cameraController == null) return;
|
||||||
|
// do not allow switching camera when recording
|
||||||
|
if (cameraController!.value.isRecordingVideo == true) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
await cameraController!.dispose();
|
||||||
cameraController = null;
|
cameraController = null;
|
||||||
await selectCamera((selectedCameraDetails.cameraId + 1) % 2, false, false);
|
await selectCamera((selectedCameraDetails.cameraId + 1) % 2, false, false);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue