From 931e9c0666e1fae488b8afab74039d3c14a2ab97 Mon Sep 17 00:00:00 2001 From: otsmr Date: Thu, 23 Jan 2025 20:46:52 +0100 Subject: [PATCH] new users and fix camera problem --- android/app/src/main/AndroidManifest.xml | 2 + android/app/src/profile/AndroidManifest.xml | 2 + lib/main.dart | 5 +- lib/src/app.dart | 18 +- lib/src/model/contacts_model.dart | 50 +++ lib/src/providers/api_provider.dart | 1 - lib/src/providers/db_provider.dart | 12 +- lib/src/signal/signal_helper.dart | 11 +- lib/src/utils.dart | 22 +- lib/src/views/_new_camera_preview_view.dart | 118 ------ lib/src/views/camera_preview_view.dart | 443 +++++--------------- lib/src/views/home_view.dart | 7 +- lib/src/views/new_message_view.dart | 63 ++- lib/src/views/permissions_view.dart | 2 +- pubspec.lock | 48 --- pubspec.yaml | 1 - 16 files changed, 214 insertions(+), 591 deletions(-) create mode 100644 lib/src/model/contacts_model.dart delete mode 100644 lib/src/views/_new_camera_preview_view.dart diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 4e9e3ee..f62872f 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -32,6 +32,8 @@ android:value="2" /> + + + + diff --git a/lib/main.dart b/lib/main.dart index 4e7b749..f358034 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,4 +1,3 @@ -import 'package:camera/camera.dart'; import 'package:twonly/src/providers/api_provider.dart'; import 'package:twonly/src/providers/db_provider.dart'; import 'package:flutter/material.dart'; @@ -30,8 +29,6 @@ void main() async { '${record.level.name}: twonly:${record.loggerName}: ${record.message}'); }); - var cameras = await availableCameras(); - // Create or open the database dbProvider = DbProvider(); await dbProvider.ready; @@ -54,5 +51,5 @@ void main() async { // Run the app and pass in the SettingsController. The app listens to the // SettingsController for changes, then passes it further down to the // SettingsView. - runApp(MyApp(settingsController: settingsController, cameras: cameras)); + runApp(MyApp(settingsController: settingsController)); } diff --git a/lib/src/app.dart b/lib/src/app.dart index 128b4ae..1bdab9a 100644 --- a/lib/src/app.dart +++ b/lib/src/app.dart @@ -1,4 +1,3 @@ -import 'package:camera/camera.dart'; import 'package:twonly/main.dart'; import 'views/home_view.dart'; import 'views/register_view.dart'; @@ -11,11 +10,9 @@ import 'settings/settings_controller.dart'; /// The Widget that configures your application. class MyApp extends StatefulWidget { - const MyApp( - {super.key, required this.settingsController, required this.cameras}); + const MyApp({super.key, required this.settingsController}); final SettingsController settingsController; - final List cameras; @override State createState() => _MyAppState(); @@ -106,8 +103,7 @@ class _MyAppState extends State { if (snapshot.hasData) { return snapshot.data! ? HomeView( - settingsController: widget.settingsController, - cameras: widget.cameras) + settingsController: widget.settingsController) : RegisterView( callbackOnSuccess: () { _isUserCreated = isUserCreated(); @@ -132,16 +128,6 @@ class _MyAppState extends State { borderRadius: BorderRadius.all( Radius.circular(10.0)), // Rounded top corners ), - // child: Padding( - // padding: const EdgeInsets.all( - // 8.0), // Padding around the child - // child: Center( - // child: Text( - // 'Not Connected', - // style: TextStyle(fontSize: 24), - // ), - // ), - // ), ), ), ], diff --git a/lib/src/model/contacts_model.dart b/lib/src/model/contacts_model.dart new file mode 100644 index 0000000..440ffff --- /dev/null +++ b/lib/src/model/contacts_model.dart @@ -0,0 +1,50 @@ +import 'dart:typed_data'; + +import 'package:cv/cv.dart'; +import 'package:twonly/main.dart'; + +class Contact { + Contact({required this.userId, required this.displayName}); + final Uint8List userId; + final String displayName; +} + +class DbContacts extends CvModelBase { + static const tableName = "contacts"; + + static const columnUserId = "contact_user_id"; + final userId = CvField(columnUserId); + + static const columnDisplayName = "display_name"; + final displayName = CvField(columnDisplayName); + + static const columnCreatedAt = "created_at"; + final createdAt = CvField(columnCreatedAt); + + static String getCreateTableString() { + return """ + CREATE TABLE $tableName ( + $columnUserId BINARY(16) NOT NULL PRIMARY KEY, + $columnDisplayName TEXT, + $columnCreatedAt DATETIME DEFAULT CURRENT_TIMESTAMP + ) + """; + } + + static Future> getUsers() async { + var users = await dbProvider.db!.query(tableName, + columns: [columnUserId, columnDisplayName, columnCreatedAt]); + if (users.isEmpty) return []; + + List parsedUsers = []; + for (int i = 0; i < users.length; i++) { + parsedUsers.add(Contact( + userId: users.cast()[i][columnUserId], + displayName: users.cast()[i][columnDisplayName])); + } + return parsedUsers; + } + + @override + List get fields => [userId, createdAt]; +} diff --git a/lib/src/providers/api_provider.dart b/lib/src/providers/api_provider.dart index 1f3ae1f..b8874da 100644 --- a/lib/src/providers/api_provider.dart +++ b/lib/src/providers/api_provider.dart @@ -9,7 +9,6 @@ import 'package:twonly/src/proto/api/client_to_server.pb.dart' as client; import 'package:twonly/src/proto/api/client_to_server.pbserver.dart'; import 'package:twonly/src/proto/api/error.pb.dart'; import 'package:twonly/src/proto/api/server_to_client.pb.dart' as server; -import 'package:twonly/src/proto/api/server_to_client.pbserver.dart'; import 'package:twonly/src/signal/signal_helper.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:twonly/src/utils.dart'; diff --git a/lib/src/providers/db_provider.dart b/lib/src/providers/db_provider.dart index 12f971d..8a3e068 100644 --- a/lib/src/providers/db_provider.dart +++ b/lib/src/providers/db_provider.dart @@ -1,7 +1,6 @@ import 'dart:async'; -import 'dart:io'; import 'dart:math'; -import 'package:logging/logging.dart'; +import 'package:twonly/src/model/contacts_model.dart'; import 'package:twonly/src/model/identity_key_store_model.dart'; import 'package:twonly/src/model/model_constants.dart'; import 'package:twonly/src/model/pre_key_model.dart'; @@ -67,6 +66,8 @@ class DbProvider { await db .execute('DROP TABLE If EXISTS ${DbSignalIdentityKeyStore.tableName}'); await db.execute(DbSignalIdentityKeyStore.getCreateTableString()); + await db.execute('DROP TABLE If EXISTS ${DbContacts.tableName}'); + await db.execute(DbContacts.getCreateTableString()); } Future open() async { @@ -74,7 +75,8 @@ class DbProvider { } Future remove() async { - await _createDb(db!); + await deleteDatabase(await fixPath(dbName)); + // await _createDb(db!); } Future fixPath(String path) async => path; @@ -82,8 +84,4 @@ class DbProvider { Future close() async { await db!.close(); } - - // Future deleteDb() async { - // await deleteDatabase(await fixPath(dbName)); - // } } diff --git a/lib/src/signal/signal_helper.dart b/lib/src/signal/signal_helper.dart index 7f8ccf3..a527040 100644 --- a/lib/src/signal/signal_helper.dart +++ b/lib/src/signal/signal_helper.dart @@ -2,6 +2,7 @@ import 'dart:convert'; import 'dart:developer'; import 'dart:typed_data'; import 'package:libsignal_protocol_dart/libsignal_protocol_dart.dart'; +import 'package:logging/logging.dart'; import 'package:twonly/src/model/signal_identity_json.dart'; import 'package:twonly/src/proto/api/server_to_client.pb.dart'; import 'package:twonly/src/utils.dart'; @@ -170,9 +171,13 @@ class SignalHelper { tempIdentityKey, ); - await sessionBuilder.processPreKeyBundle(preKeyBundle); - - return true; + try { + await sessionBuilder.processPreKeyBundle(preKeyBundle); + return true; + } catch (e) { + Logger("signal_helper").shout("Error: $e"); + return false; + } } static Future getSignalStore() async { diff --git a/lib/src/utils.dart b/lib/src/utils.dart index e0a4976..95a66bb 100644 --- a/lib/src/utils.dart +++ b/lib/src/utils.dart @@ -1,12 +1,10 @@ import 'dart:convert'; import 'dart:math'; import 'dart:typed_data'; -import 'dart:ui'; -import 'package:collection/collection.dart'; import 'package:flutter/material.dart'; -import 'package:libsignal_protocol_dart/libsignal_protocol_dart.dart'; import 'package:logging/logging.dart'; import 'package:twonly/main.dart'; +import 'package:twonly/src/model/contacts_model.dart'; import 'package:twonly/src/signal/signal_helper.dart'; import 'package:twonly/src/providers/api_provider.dart'; import 'package:flutter_secure_storage/flutter_secure_storage.dart'; @@ -88,18 +86,12 @@ Future addNewUser(String username) async { print(res.value); print(res.value.userdata.userId); - await SignalHelper.addNewContact(res.value.userdata); - - // final Map req = {}; - // req['identityKey'] = - // (await signalStore.getIdentityKeyPair()).getPublicKey().serialize(); - - // req['signedPreKey'] = { - // 'id': signedPreKey.id, - // 'signature': signedPreKey.signature, - // 'key': signedPreKey.getKeyPair().publicKey.serialize(), - // }; - + if (await SignalHelper.addNewContact(res.value.userdata)) { + await dbProvider.db!.insert(DbContacts.tableName, { + DbContacts.columnDisplayName: username, + DbContacts.columnUserId: res.value.userdata.userId + }); + } print("Add new user: ${res}"); } diff --git a/lib/src/views/_new_camera_preview_view.dart b/lib/src/views/_new_camera_preview_view.dart deleted file mode 100644 index 75ca240..0000000 --- a/lib/src/views/_new_camera_preview_view.dart +++ /dev/null @@ -1,118 +0,0 @@ -// import 'package:camera/camera.dart'; -// import 'camera_editor_view.dart'; -// import 'package:flutter/gestures.dart'; -import 'package:flutter/material.dart'; -import 'package:camerawesome/camerawesome_plugin.dart'; - -class CameraPreviewView extends StatelessWidget { - const CameraPreviewView({super.key}); - - @override - Widget build(BuildContext context) { - return const MaterialApp( - title: 'Custom CamerAwesome UI', - home: CameraPage(), - ); - } -} - -class CameraPage extends StatelessWidget { - const CameraPage({super.key}); - - @override - Widget build(BuildContext context) { - return Scaffold( - body: CameraAwesomeBuilder.awesome( - saveConfig: SaveConfig.photo(), - sensorConfig: SensorConfig.single( - sensor: Sensor.position(SensorPosition.back), - aspectRatio: CameraAspectRatios.ratio_1_1, - ), - previewFit: CameraPreviewFit.contain, - previewPadding: const EdgeInsets.only(left: 150, top: 100), - previewAlignment: Alignment.topRight, - // Buttons of CamerAwesome UI will use this theme - theme: AwesomeTheme( - bottomActionsBackgroundColor: Colors.cyan.withAlpha(150), - buttonTheme: AwesomeButtonTheme( - backgroundColor: Colors.cyan.withAlpha(150), - iconSize: 20, - foregroundColor: Colors.white, - padding: const EdgeInsets.all(16), - // Tap visual feedback (ripple, bounce...) - buttonBuilder: (child, onTap) { - return ClipOval( - child: Material( - color: Colors.transparent, - shape: const CircleBorder(), - child: InkWell( - splashColor: Colors.cyan, - highlightColor: Colors.cyan.withAlpha(150), - onTap: onTap, - child: child, - ), - ), - ); - }, - ), - ), - topActionsBuilder: (state) => AwesomeTopActions( - padding: EdgeInsets.zero, - state: state, - children: [ - Expanded( - child: AwesomeFilterWidget( - state: state, - filterListPosition: FilterListPosition.aboveButton, - filterListPadding: const EdgeInsets.only(top: 8), - ), - ), - ], - ), - middleContentBuilder: (state) { - return Column( - children: [ - const Spacer(), - Builder(builder: (context) { - return Container( - color: AwesomeThemeProvider.of(context) - .theme - .bottomActionsBackgroundColor, - child: const Align( - alignment: Alignment.bottomCenter, - child: Padding( - padding: EdgeInsets.only(bottom: 10, top: 10), - child: Text( - "Take your best shot!", - style: TextStyle( - color: Colors.white, - fontWeight: FontWeight.bold, - fontStyle: FontStyle.italic, - ), - ), - ), - ), - ); - }), - ], - ); - }, - bottomActionsBuilder: (state) => AwesomeBottomActions( - state: state, - left: AwesomeFlashButton( - state: state, - ), - right: AwesomeCameraSwitchButton( - state: state, - scale: 1.0, - onSwitchTap: (state) { - state.switchCameraSensor( - aspectRatio: state.sensorConfig.aspectRatio, - ); - }, - ), - ), - ), - ); - } -} diff --git a/lib/src/views/camera_preview_view.dart b/lib/src/views/camera_preview_view.dart index 3bd5fa2..75ca240 100644 --- a/lib/src/views/camera_preview_view.dart +++ b/lib/src/views/camera_preview_view.dart @@ -1,355 +1,118 @@ -import 'package:camera/camera.dart'; +// import 'package:camera/camera.dart'; +// import 'camera_editor_view.dart'; +// import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; -// import 'package:camerawesome/camerawesome_plugin.dart'; -import 'dart:math'; +import 'package:camerawesome/camerawesome_plugin.dart'; -class CameraPreviewView extends StatefulWidget { - const CameraPreviewView({ - super.key, - required this.cameras, - }); - - final List cameras; - static const routeName = '/camera_preview'; - - @override - CameraPreviewViewState createState() => CameraPreviewViewState(); -} - -class CameraPreviewViewState extends State { - late CameraController _controller; - late Future _initializeControllerFuture; - - int _selectedCameraIdx = 0; - - double _baseScaleFactor = 1.0; - double _basePanY = 0.0; - double _scaleFactor = 1; - double _minimumScaleFactor = 1; - - @override - void initState() { - super.initState(); - // To display the current output from the Camera, - // create a CameraController. - - // _controller = CameraController( - // // Get a specific camera from the list of available cameras. - // widget.cameras.first, - // // Define the resolution to use. - // ResolutionPreset.max, - // ); - - // _controller.initialize().then((_) { - // _controller.value = _controller.value.copyWith(previewSize: size); - // setState(() {}); - // }); - - // Next, initialize the controller. This returns a Future. - // _initializeControllerFuture = _controller.initialize(); - } - - Future updateController() async { - await _controller.setDescription(widget.cameras[_selectedCameraIdx]); - } - - @override - void dispose() { - // Dispose of the controller when the widget is disposed. - // _controller.dispose(); - super.dispose(); - } - - // function for cropping image - Future takePicture() async { - try { - await _initializeControllerFuture; - // final image = await _controller.takePicture(); - - if (!context.mounted) return; - // await Navigator.of(context).push( - // MaterialPageRoute( - // builder: (context) => CameraEditorView( - // imagePath: image.path, - // ), - // ), - // ); - } catch (e) { - // If an error occurs, log the error to the console. - print(e); - } - } - - List getImageSize(double height, double width) { - // https://github.com/flutter/flutter/issues/15953#issuecomment-855182376 - - final screenH = max(height, width); - final screenW = min(height, width); - - var ratioContainer = screenH / screenW; - - var tmp = _controller.value.previewSize!; - final previewH = max(tmp.height, tmp.width); - final previewW = min(tmp.height, tmp.width); - - var ratio = previewH / previewW; - var missing = ratioContainer - ratio; - - final maxHeight = screenH; - final maxWidth = screenH * 0.5625; - - _minimumScaleFactor = 1 + missing; - - return [maxHeight, maxWidth]; - } - - Future updateScaleFactor(double newScale) async { - var minFactor = await _controller.getMinZoomLevel(); - var maxFactor = await _controller.getMaxZoomLevel(); - if (newScale < minFactor) { - newScale = minFactor; - } - if (newScale > maxFactor) { - newScale = maxFactor; - } - - print(newScale); - if (newScale <= 1) { - await _controller.setZoomLevel(newScale); - } else { - //await _controller.setZoomLevel(1.0); - } - setState(() { - _scaleFactor = newScale; - }); - } +class CameraPreviewView extends StatelessWidget { + const CameraPreviewView({super.key}); @override Widget build(BuildContext context) { - return Container(); - var isFront = widget.cameras[_selectedCameraIdx].lensDirection == - CameraLensDirection.front; - // Fill this out in the next steps. - // You must wait until the controller is initialized before displaying the - // camera preview. Use a FutureBuilder to display a loading spinner until the - // controller has finished initializing. - return Scaffold( - body: GestureDetector( - onPanStart: (details) async { - if (_scaleFactor <= 1) { - await updateScaleFactor(1); - } - setState(() { - _basePanY = details.localPosition.dy; - _baseScaleFactor = _scaleFactor; - }); - }, - onPanUpdate: (details) async { - final diff = details.localPosition.dy - _basePanY; - final updateScale = diff / 50; - var tmp = _baseScaleFactor - updateScale; - if (tmp <= 1) tmp = 1.00001; - updateScaleFactor(tmp); - }, - // onScaleStart: (details) { - // _baseScaleFactor = _scaleFactor; - // }, - // onScaleUpdate: (details) async { - // // print(scale.scale); - // var scaleFactor = - // ((_baseScaleFactor * details.scale * 10).round() / 10); - // var maxFactor = await _controller.getMaxZoomLevel(); - // if (scaleFactor > maxFactor) scaleFactor = maxFactor; - // if (scaleFactor != _scaleFactor) { - // await updateScaleFactor(scaleFactor); - // } - // }, - onTap: () {}, - onDoubleTap: () { - setState(() { - _selectedCameraIdx = (_selectedCameraIdx + 1) % 2; - updateController(); - }); - }, - child: Padding( - padding: const EdgeInsets.only(top: 60, bottom: 40), - child: ClipRRect( - borderRadius: BorderRadius.circular(22), - child: FutureBuilder( - future: _initializeControllerFuture, - builder: (context, snapshot) { - if (snapshot.connectionState != ConnectionState.done) { - return const Center(child: CircularProgressIndicator()); - } - return Stack( - alignment: Alignment.bottomCenter, - children: [ - LayoutBuilder( - builder: - (BuildContext context, BoxConstraints constraints) { - var height = constraints.maxHeight; - var width = constraints.maxWidth; + return const MaterialApp( + title: 'Custom CamerAwesome UI', + home: CameraPage(), + ); + } +} - return OverflowBox( - maxHeight: getImageSize(height, width)[0], - maxWidth: getImageSize(height, width)[1], - child: Transform( - alignment: Alignment.center, - transform: Matrix4.rotationY(isFront ? pi : 0), - child: Transform.scale( - scale: _minimumScaleFactor + - (_scaleFactor > 1 ? _scaleFactor : 1) - - 1, - child: CameraPreview(_controller)), - ), - ); - }, - ), - Positioned( - bottom: 50, - child: Column( - children: [ - CameraZoomButtons( - key: widget.key, - isFront: isFront, - scaleFactor: _scaleFactor, - updateScaleFactor: updateScaleFactor, - controller: _controller, - ), - SizedBox(height: 10), - GestureDetector( - onTap: () async { - await takePicture(); - }, - onLongPress: () async {}, - child: Container( - height: 100, - width: 100, - clipBehavior: Clip.antiAliasWithSaveLayer, - padding: const EdgeInsets.all(2), - decoration: BoxDecoration( - shape: BoxShape.circle, - border: Border.all( - width: 7, - color: Colors.white, - ), - ), - ), - ), - ], +class CameraPage extends StatelessWidget { + const CameraPage({super.key}); + + @override + Widget build(BuildContext context) { + return Scaffold( + body: CameraAwesomeBuilder.awesome( + saveConfig: SaveConfig.photo(), + sensorConfig: SensorConfig.single( + sensor: Sensor.position(SensorPosition.back), + aspectRatio: CameraAspectRatios.ratio_1_1, + ), + previewFit: CameraPreviewFit.contain, + previewPadding: const EdgeInsets.only(left: 150, top: 100), + previewAlignment: Alignment.topRight, + // Buttons of CamerAwesome UI will use this theme + theme: AwesomeTheme( + bottomActionsBackgroundColor: Colors.cyan.withAlpha(150), + buttonTheme: AwesomeButtonTheme( + backgroundColor: Colors.cyan.withAlpha(150), + iconSize: 20, + foregroundColor: Colors.white, + padding: const EdgeInsets.all(16), + // Tap visual feedback (ripple, bounce...) + buttonBuilder: (child, onTap) { + return ClipOval( + child: Material( + color: Colors.transparent, + shape: const CircleBorder(), + child: InkWell( + splashColor: Colors.cyan, + highlightColor: Colors.cyan.withAlpha(150), + onTap: onTap, + child: child, + ), + ), + ); + }, + ), + ), + topActionsBuilder: (state) => AwesomeTopActions( + padding: EdgeInsets.zero, + state: state, + children: [ + Expanded( + child: AwesomeFilterWidget( + state: state, + filterListPosition: FilterListPosition.aboveButton, + filterListPadding: const EdgeInsets.only(top: 8), + ), + ), + ], + ), + middleContentBuilder: (state) { + return Column( + children: [ + const Spacer(), + Builder(builder: (context) { + return Container( + color: AwesomeThemeProvider.of(context) + .theme + .bottomActionsBackgroundColor, + child: const Align( + alignment: Alignment.bottomCenter, + child: Padding( + padding: EdgeInsets.only(bottom: 10, top: 10), + child: Text( + "Take your best shot!", + style: TextStyle( + color: Colors.white, + fontWeight: FontWeight.bold, + fontStyle: FontStyle.italic, + ), ), ), - ], + ), ); - }, - ), + }), + ], + ); + }, + bottomActionsBuilder: (state) => AwesomeBottomActions( + state: state, + left: AwesomeFlashButton( + state: state, + ), + right: AwesomeCameraSwitchButton( + state: state, + scale: 1.0, + onSwitchTap: (state) { + state.switchCameraSensor( + aspectRatio: state.sensorConfig.aspectRatio, + ); + }, ), ), ), ); } } - -class CameraZoomButtons extends StatefulWidget { - const CameraZoomButtons( - {super.key, - required this.isFront, - required this.controller, - required this.updateScaleFactor, - required this.scaleFactor}); - - final bool isFront; - final CameraController controller; - final double scaleFactor; - final Function updateScaleFactor; - - @override - State createState() => _CameraZoomButtonsState(); -} - -String beautifulZoomScale(double scale) { - var tmp = scale.toStringAsFixed(1); - if (tmp[0] == "0") { - tmp = tmp.substring(1, tmp.length); - } - return tmp; -} - -class _CameraZoomButtonsState extends State { - @override - Widget build(BuildContext context) { - final zoomButtonStyle = TextButton.styleFrom( - padding: EdgeInsets.zero, - foregroundColor: Colors.white, - minimumSize: Size(40, 40), - alignment: Alignment.center, - tapTargetSize: MaterialTapTargetSize.shrinkWrap); - - final zoomTextStyle = TextStyle(fontSize: 13); - return ClipRRect( - borderRadius: BorderRadius.circular(40.0), - child: Container( - color: const Color.fromARGB(90, 0, 0, 0), - child: Row( - children: widget.isFront - ? [] - : [ - TextButton( - style: zoomButtonStyle, - onPressed: () async { - var level = await widget.controller.getMinZoomLevel(); - widget.updateScaleFactor(level); - }, - child: FutureBuilder( - future: widget.controller.getMinZoomLevel(), - builder: (context, snap) { - if (snap.hasData) { - var minLevel = - beautifulZoomScale(snap.data!.toDouble()); - var currentLevel = - beautifulZoomScale(widget.scaleFactor); - return Text( - widget.scaleFactor < 1 - ? "${currentLevel}x" - : "${minLevel}x", - style: zoomTextStyle, - ); - } else { - return Text(""); - } - }), - ), - TextButton( - style: zoomButtonStyle, - onPressed: () { - widget.updateScaleFactor(1.0); - }, - child: Text( - widget.scaleFactor >= 1 - ? "${beautifulZoomScale(widget.scaleFactor)}x" - : "1.0x", - style: zoomTextStyle, - )), - TextButton( - style: zoomButtonStyle, - onPressed: () async { - var level = await widget.controller.getMaxZoomLevel(); - widget.updateScaleFactor(level); - }, - child: FutureBuilder( - future: widget.controller.getMaxZoomLevel(), - builder: (context, snap) { - if (snap.hasData) { - var maxLevel = snap.data?.toInt(); - return Text("${maxLevel}x", style: zoomTextStyle); - } else { - return Text(""); - } - }), - ) - ], - ), - ), - ); - } -} diff --git a/lib/src/views/home_view.dart b/lib/src/views/home_view.dart index 1c1fa69..84691d6 100644 --- a/lib/src/views/home_view.dart +++ b/lib/src/views/home_view.dart @@ -1,4 +1,3 @@ -import 'package:camera/camera.dart'; import 'camera_preview_view.dart'; import 'chat_list_view.dart'; import 'permissions_view.dart'; @@ -7,10 +6,8 @@ import '../settings/settings_controller.dart'; import 'package:flutter/material.dart'; class HomeView extends StatefulWidget { - const HomeView( - {super.key, required this.settingsController, required this.cameras}); + const HomeView({super.key, required this.settingsController}); final SettingsController settingsController; - final List cameras; @override State createState() => HomeViewState(); @@ -36,7 +33,7 @@ class HomeViewState extends State { }, children: [ ChatListView(), - CameraPreviewView(cameras: widget.cameras), + CameraPreviewView(), ProfileView(settingsController: widget.settingsController) ], ), diff --git a/lib/src/views/new_message_view.dart b/lib/src/views/new_message_view.dart index 01c6d44..3f3292f 100644 --- a/lib/src/views/new_message_view.dart +++ b/lib/src/views/new_message_view.dart @@ -1,6 +1,8 @@ import 'package:flutter/material.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; +import 'package:twonly/src/model/contacts_model.dart'; import 'package:twonly/src/utils.dart'; +import 'package:twonly/src/views/search_username_view.dart'; class NewMessageView extends StatefulWidget { const NewMessageView({super.key}); @@ -10,49 +12,42 @@ class NewMessageView extends StatefulWidget { } class _NewMessageView extends State { - final List _known_users = [ - "Alisa", - "Klaus", - "John", - "Emma", - "Michael", - "Sophia", - "James", - "Olivia", - "Liam", - "Ava", - "Noah", - "Isabella", - "Lucas", - "Mia", - "Ethan", - "Charlotte", - ]; - List _filteredUsers = []; + List _knownUsers = []; + List _filteredUsers = []; String _lastSearchQuery = ''; final TextEditingController searchUserName = TextEditingController(); @override void initState() { super.initState(); - // Initialize the filtered users with all known users - _filteredUsers = List.from(_known_users); + _loadUsers(); + } + + Future _loadUsers() async { + final users = await DbContacts.getUsers(); + setState(() { + _knownUsers = users; + _filteredUsers = List.from(_knownUsers); + }); } Future _filterUsers(String query) async { if (query.isEmpty) { - _filteredUsers = List.from(_known_users); + _filteredUsers = List.from(_knownUsers); return; } if (_lastSearchQuery.length < query.length) { - _filteredUsers = _known_users - .where((user) => user.toLowerCase().contains(query.toLowerCase())) + _filteredUsers = _knownUsers + .where((user) => + user.displayName.toLowerCase().contains(query.toLowerCase())) .toList(); } else { _filteredUsers = _filteredUsers - .where((user) => user.toLowerCase().contains(query.toLowerCase())) + .where((user) => + user.displayName.toLowerCase().contains(query.toLowerCase())) .toList(); } + _lastSearchQuery = query; } @override @@ -103,6 +98,11 @@ class _NewMessageView extends State { FilledButton( onPressed: () { // Handle Nach Nutzername suchen button press + Navigator.pushReplacement( + context, + MaterialPageRoute( + builder: (context) => SearchUsernameView()), + ); }, child: Text('Nach Nutzername suchen'), ), @@ -120,23 +120,22 @@ class _NewMessageView extends State { } class UserList extends StatelessWidget { - final List _known_users; - - UserList(this._known_users); + const UserList(this._knownUsers, {super.key}); + final List _knownUsers; @override Widget build(BuildContext context) { // Step 1: Sort the users alphabetically - _known_users.sort(); + _knownUsers.sort((a, b) => a.displayName.compareTo(b.displayName)); // Step 2: Group users by their initials Map> groupedUsers = {}; - for (var user in _known_users) { - String initial = user[0].toUpperCase(); + for (var user in _knownUsers) { + String initial = user.displayName[0].toUpperCase(); if (!groupedUsers.containsKey(initial)) { groupedUsers[initial] = []; } - groupedUsers[initial]!.add(user); + groupedUsers[initial]!.add(user.displayName); } // Step 3: Create a list of sections diff --git a/lib/src/views/permissions_view.dart b/lib/src/views/permissions_view.dart index b45403d..2ca84f3 100644 --- a/lib/src/views/permissions_view.dart +++ b/lib/src/views/permissions_view.dart @@ -61,7 +61,7 @@ class PermissionHandlerViewState extends State { crossAxisAlignment: CrossAxisAlignment.center, children: [ Text( - "Connect needs access to the camera and microphone for obvious reasons.", + "twonly needs access to the camera and microphone.", textAlign: TextAlign.center, ), SizedBox(height: 50), diff --git a/pubspec.lock b/pubspec.lock index 6273fab..612b9ad 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -126,46 +126,6 @@ packages: url: "https://pub.dev" source: hosted version: "8.9.3" - camera: - dependency: "direct main" - description: - name: camera - sha256: "26ff41045772153f222ffffecba711a206f670f5834d40ebf5eed3811692f167" - url: "https://pub.dev" - source: hosted - version: "0.11.0+2" - camera_android_camerax: - dependency: transitive - description: - name: camera_android_camerax - sha256: "7cc6adf1868bdcf4e63a56b24b41692dfbad2bec1cdceea451c77798f6a605c3" - url: "https://pub.dev" - source: hosted - version: "0.6.13" - camera_avfoundation: - dependency: transitive - description: - name: camera_avfoundation - sha256: "3f81ee3e88a79b0b010f0233d42625926299551b05d5dc995267a0b35bc33247" - url: "https://pub.dev" - source: hosted - version: "0.9.18" - camera_platform_interface: - dependency: transitive - description: - name: camera_platform_interface - sha256: "953e7baed3a7c8fae92f7200afeb2be503ff1a17c3b4e4ed7b76f008c2810a31" - url: "https://pub.dev" - source: hosted - version: "2.9.0" - camera_web: - dependency: transitive - description: - name: camera_web - sha256: "595f28c89d1fb62d77c73c633193755b781c6d2e0ebcd8dc25b763b514e6ba8f" - url: "https://pub.dev" - source: hosted - version: "0.3.5" camerawesome: dependency: "direct main" description: @@ -368,14 +328,6 @@ packages: description: flutter source: sdk version: "0.0.0" - flutter_plugin_android_lifecycle: - dependency: transitive - description: - name: flutter_plugin_android_lifecycle - sha256: "615a505aef59b151b46bbeef55b36ce2b6ed299d160c51d84281946f0aa0ce0e" - url: "https://pub.dev" - source: hosted - version: "2.0.24" flutter_secure_storage: dependency: "direct main" description: diff --git a/pubspec.yaml b/pubspec.yaml index 90345b0..900994e 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -10,7 +10,6 @@ environment: sdk: ^3.5.4 dependencies: - camera: ^0.11.0+2 camerawesome: ^2.1.0 collection: ^1.18.0 cv: ^1.1.3