From bb1160ad18e5fe708d81876d12dd449a59b05366 Mon Sep 17 00:00:00 2001 From: Cxx0822 <1556464090@qq.com> Date: Thu, 18 Jun 2026 14:20:37 +0800 Subject: [PATCH] =?UTF-8?q?feat:=E5=A2=9E=E5=8A=A0=E6=B6=88=E6=81=AF?= =?UTF-8?q?=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/models/ImMessage.dart | 19 ++++++++ lib/pages/chat_page.dart | 85 +++++++++++++++++++---------------- lib/pages/contacts_page.dart | 4 ++ lib/pages/login.dart | 7 ++- lib/pages/messages_page.dart | 10 +---- lib/services/dio_service.dart | 2 +- pubspec.yaml | 2 +- 7 files changed, 76 insertions(+), 53 deletions(-) diff --git a/lib/models/ImMessage.dart b/lib/models/ImMessage.dart index ca0abd6..ad63b9c 100644 --- a/lib/models/ImMessage.dart +++ b/lib/models/ImMessage.dart @@ -1,3 +1,5 @@ +import 'dart:convert'; + class ImMessage { final String type; final String from; @@ -11,10 +13,27 @@ class ImMessage { required this.content, }); + factory ImMessage.fromJsonString(String json) { + return ImMessage.fromJson(jsonDecode(json)); + } + + factory ImMessage.fromJson(Map json) { + return ImMessage( + type: json['type'], + from: json['from'], + to: json['to'], + content: json['content'], + ); + } + Map toJson() => { 'type': type, 'from': from, 'to': to, 'content': content, }; + + String toJsonString() { + return jsonEncode(toJson()); + } } \ No newline at end of file diff --git a/lib/pages/chat_page.dart b/lib/pages/chat_page.dart index ae2b52a..8cfba56 100644 --- a/lib/pages/chat_page.dart +++ b/lib/pages/chat_page.dart @@ -1,5 +1,3 @@ -import 'dart:convert'; - import 'package:flutter/material.dart'; import 'package:liquid_glass_widgets/liquid_glass_widgets.dart'; import 'package:sweet_chat_app/models/ImMessage.dart'; @@ -15,11 +13,13 @@ class ChatMessage { } class ChatPage extends StatefulWidget { + final int contractId; final String contactName; final String avatarUrl; const ChatPage({ super.key, + required this.contractId, required this.contactName, required this.avatarUrl, }); @@ -32,48 +32,46 @@ class _ChatPageState extends State { final TextEditingController _controller = TextEditingController(); final ScrollController _scrollController = ScrollController(); + late int userId; late List _messages; @override void initState() { super.initState(); - _messages = [ - // ChatMessage(text: '在吗?', isMe: false, avatar: widget.avatarUrl), - // ChatMessage(text: '在的,怎么啦 😊', isMe: true), - // ChatMessage(text: '今晚一起吃饭吗?', isMe: false, avatar: widget.avatarUrl), - ]; + _messages = []; - final userId = SpUtil.getInt('userId') ?? 0; + userId = SpUtil.getInt('userId') ?? 0; final online = ImMessage( type: "ONLINE", from: userId.toString(), - to: '', + to: 'SYSTEM', content: '', ); - - WebSocketService().connect('ws://192.168.31.108:5050?userId=$userId'); - WebSocketService().send(jsonEncode(online.toJson())); - WebSocketService().messages.listen((msg) { - print('收到消息: $msg'); + WebSocketService().connect('ws://172.29.100.146:5050?userId=$userId'); + WebSocketService().send(online.toJsonString()); + + WebSocketService().messages.listen((wsMsg) { + final ImMessage imMsg = ImMessage.fromJsonString(wsMsg); setState(() { - _messages.add(ChatMessage(text: msg, isMe: false, avatar: widget.avatarUrl)); + if (imMsg.type.contains('CHAT')) { + _messages.add( + ChatMessage( + text: imMsg.content, + isMe: userId.toString() == imMsg.from, + avatar: widget.avatarUrl, + ), + ); + } }); - - _controller.clear(); - Future.delayed(const Duration(milliseconds: 100), () { - _scrollController.animateTo( - _scrollController.position.maxScrollExtent, - duration: const Duration(milliseconds: 300), - curve: Curves.easeOut, - ); - }); + _controller.clear(); + scrollToBottom(); }); } - + @override void dispose() { super.dispose(); @@ -84,19 +82,13 @@ class _ChatPageState extends State { final text = _controller.text.trim(); if (text.isEmpty) return; - setState(() { - _messages.add(ChatMessage(text: text, isMe: true)); - }); - - _controller.clear(); - - Future.delayed(const Duration(milliseconds: 100), () { - _scrollController.animateTo( - _scrollController.position.maxScrollExtent, - duration: const Duration(milliseconds: 300), - curve: Curves.easeOut, - ); - }); + final chat = ImMessage( + type: "CHAT_PRIVATE", + from: userId.toString(), + to: widget.contractId.toString(), + content: text, + ); + WebSocketService().send(chat.toJsonString()); } Widget _buildAvatar(String? url) { @@ -167,7 +159,11 @@ class _ChatPageState extends State { children: [ if (!msg.isMe) _buildAvatar(msg.avatar), Flexible( - child: GlassCard( + child: Container( + decoration: BoxDecoration( + color: msg.isMe ? Color(0xFF2FA951): Color(0xFF030816), + borderRadius: BorderRadius.circular(12), + ), padding: const EdgeInsets.symmetric( horizontal: 12, vertical: 10, @@ -199,6 +195,7 @@ class _ChatPageState extends State { controller: _controller, onSubmitted: (_) => _sendMessage(), style: const TextStyle(color: Colors.white), + cursorColor: Colors.white, decoration: const InputDecoration( hintText: '输入消息...', hintStyle: TextStyle(color: Colors.white), @@ -215,4 +212,14 @@ class _ChatPageState extends State { ), ); } + + void scrollToBottom() { + Future.delayed(const Duration(milliseconds: 100), () { + _scrollController.animateTo( + _scrollController.position.maxScrollExtent, + duration: const Duration(milliseconds: 300), + curve: Curves.easeOut, + ); + }); + } } diff --git a/lib/pages/contacts_page.dart b/lib/pages/contacts_page.dart index ee356d3..5bf9804 100644 --- a/lib/pages/contacts_page.dart +++ b/lib/pages/contacts_page.dart @@ -8,12 +8,14 @@ import 'package:sweet_chat_app/utils/SpUtil.dart'; import 'chat_page.dart'; class ContactInfo extends ISuspensionBean { + final int id; final String name; final String avatar; String? tagIndex; String? namePinyin; ContactInfo({ + required this.id, required this.name, required this.avatar, this.tagIndex, @@ -58,6 +60,7 @@ class _ContactsPageState extends State { final tag = pinyin.substring(0, 1).toUpperCase(); return ContactInfo( + id: user.id, name: user.nickname, avatar: user.avatarUrl, tagIndex: RegExp(r'^[A-Z]$').hasMatch(tag) ? tag : '#', @@ -163,6 +166,7 @@ class _ContactsPageState extends State { MaterialPageRoute( builder: (_) => ChatPage( + contractId: contact.id, contactName: contact.name, avatarUrl: contact.avatar, ), diff --git a/lib/pages/login.dart b/lib/pages/login.dart index 42eecd2..58f947a 100644 --- a/lib/pages/login.dart +++ b/lib/pages/login.dart @@ -3,9 +3,6 @@ import 'package:fluttertoast/fluttertoast.dart'; import 'package:liquid_glass_widgets/liquid_glass_widgets.dart'; import 'package:sweet_chat_app/apis/auth_api.dart'; import 'package:sweet_chat_app/utils/SpUtil.dart'; -import 'package:web_socket_channel/web_socket_channel.dart'; - -import '../services/webSocket_service.dart'; import 'home_page.dart'; class LoginPage extends StatefulWidget { @@ -71,10 +68,11 @@ class _LoginPageState extends State { ), const SizedBox(height: 24), - // 邮箱 + // 用户名 TextField( controller: _usernameController, style: const TextStyle(color: Colors.white), + cursorColor: Colors.white, decoration: InputDecoration( hintText: '请输入用户名', hintStyle: TextStyle(color: Colors.white70), @@ -94,6 +92,7 @@ class _LoginPageState extends State { controller: _passwordController, obscureText: true, style: const TextStyle(color: Colors.white), + cursorColor: Colors.white, decoration: InputDecoration( hintText: '请输入密码', hintStyle: TextStyle(color: Colors.white70), diff --git a/lib/pages/messages_page.dart b/lib/pages/messages_page.dart index bcee81b..5ba2e31 100644 --- a/lib/pages/messages_page.dart +++ b/lib/pages/messages_page.dart @@ -79,6 +79,7 @@ class MessagePage extends StatelessWidget { MaterialPageRoute( builder: (_) => const ChatPage( + contractId: 0, contactName: '张三', avatarUrl: 'https://picsum.photos/id/1012/200', ), @@ -125,11 +126,4 @@ class Message { }); } -List _messages = [ - Message( - avatar: 'https://picsum.photos/id/1012/200', - name: '小刘', - lastMsg: '今晚一起吃饭吗?', - time: '12:30', - ), -]; +List _messages = []; diff --git a/lib/services/dio_service.dart b/lib/services/dio_service.dart index 42dee09..0091cf7 100644 --- a/lib/services/dio_service.dart +++ b/lib/services/dio_service.dart @@ -1,7 +1,7 @@ import 'package:dio/dio.dart'; final dioService = Dio(BaseOptions( - baseUrl: 'http://192.168.31.108:2836/api', + baseUrl: 'http://172.29.100.146:2836/api', connectTimeout: Duration(seconds: 10), headers: {'Content-Type': 'application/json'}, )); \ No newline at end of file diff --git a/pubspec.yaml b/pubspec.yaml index eabed6d..65d3b38 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1 +1 @@ -name: sweet_chat_app description: "A new Flutter project." # The following line prevents the package from being accidentally published to # pub.dev using `flutter pub publish`. This is preferred for private packages. publish_to: 'none' # Remove this line if you wish to publish to pub.dev # The following defines the version and build number for your application. # A version number is three numbers separated by dots, like 1.2.43 # followed by an optional build number separated by a +. # Both the version and the builder number may be overridden in flutter # build by specifying --build-name and --build-number, respectively. # In Android, build-name is used as versionName while build-number used as versionCode. # Read more about Android versioning at https://developer.android.com/studio/publish/versioning # In iOS, build-name is used as CFBundleShortVersionString while build-number is used as CFBundleVersion. # Read more about iOS versioning at # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html # In Windows, build-name is used as the major, minor, and patch parts # of the product and file versions while build-number is used as the build suffix. version: 1.0.0+1 environment: sdk: ^3.7.0 # Dependencies specify other packages that your package needs in order to work. # To automatically upgrade your package dependencies to the latest versions # consider running `flutter pub upgrade --major-versions`. Alternatively, # dependencies can be manually updated by changing the version numbers below to # the latest version available on pub.dev. To see which dependencies have newer # versions available, run `flutter pub outdated`. dependencies: flutter: sdk: flutter # The following adds the Cupertino Icons font to your application. # Use with the CupertinoIcons class for iOS style icons. cupertino_icons: ^1.0.8 liquid_glass_widgets: ^0.16.1 azlistview: ^2.0.0 lpinyin: ^2.0.3 web_socket_channel: ^3.0.3 dio: ^5.7.0 json_annotation: ^4.9.0 fluttertoast: ^8.2.4 shared_preferences: ^2.5.5 dev_dependencies: flutter_test: sdk: flutter build_runner: ^2.4.8 json_serializable: ^6.8.0 flutter_lints: ^5.0.0 # For information on the generic Dart part of this file, see the # following page: https://dart.dev/tools/pub/pubspec # The following section is specific to Flutter packages. flutter: # The following line ensures that the Material Icons font is # included with your application, so that you can use the icons in # the material Icons class. uses-material-design: true # To add assets to your application, add an assets section, like this: # assets: # - images/a_dot_burr.jpeg # - images/a_dot_ham.jpeg # An image asset can refer to one or more resolution-specific "variants", see # https://flutter.dev/to/resolution-aware-images # For details regarding adding assets from package dependencies, see # https://flutter.dev/to/asset-from-package # To add custom fonts to your application, add a fonts section here, # in this "flutter" section. Each entry in this list should have a # "family" key with the font family name, and a "fonts" key with a # list giving the asset and other descriptors for the font. For # example: # fonts: # - family: Schyler # fonts: # - asset: fonts/Schyler-Regular.ttf # - asset: fonts/Schyler-Italic.ttf # style: italic # - family: Trajan Pro # fonts: # - asset: fonts/TrajanPro.ttf # - asset: fonts/TrajanPro_Bold.ttf # weight: 700 # # For details regarding fonts from package dependencies, # see https://flutter.dev/to/font-from-package \ No newline at end of file +name: sweet_chat_app description: "A new Flutter project." # The following line prevents the package from being accidentally published to # pub.dev using `flutter pub publish`. This is preferred for private packages. publish_to: 'none' # Remove this line if you wish to publish to pub.dev # The following defines the version and build number for your application. # A version number is three numbers separated by dots, like 1.2.43 # followed by an optional build number separated by a +. # Both the version and the builder number may be overridden in flutter # build by specifying --build-name and --build-number, respectively. # In Android, build-name is used as versionName while build-number used as versionCode. # Read more about Android versioning at https://developer.android.com/studio/publish/versioning # In iOS, build-name is used as CFBundleShortVersionString while build-number is used as CFBundleVersion. # Read more about iOS versioning at # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html # In Windows, build-name is used as the major, minor, and patch parts # of the product and file versions while build-number is used as the build suffix. version: 1.0.0+1 environment: sdk: ^3.7.0 # Dependencies specify other packages that your package needs in order to work. # To automatically upgrade your package dependencies to the latest versions # consider running `flutter pub upgrade --major-versions`. Alternatively, # dependencies can be manually updated by changing the version numbers below to # the latest version available on pub.dev. To see which dependencies have newer # versions available, run `flutter pub outdated`. dependencies: flutter: sdk: flutter # The following adds the Cupertino Icons font to your application. # Use with the CupertinoIcons class for iOS style icons. cupertino_icons: ^1.0.8 liquid_glass_widgets: ^0.16.1 azlistview: ^2.0.0 lpinyin: ^2.0.3 web_socket_channel: ^3.0.3 dio: ^5.7.0 json_annotation: ^4.9.0 fluttertoast: ^8.2.4 shared_preferences: ^2.5.5 dev_dependencies: flutter_test: sdk: flutter build_runner: ^2.4.8 json_serializable: ^6.8.0 flutter_lints: ^5.0.0 # For information on the generic Dart part of this file, see the # following page: https://dart.dev/tools/pub/pubspec # The following section is specific to Flutter packages. flutter: # The following line ensures that the Material Icons font is # included with your application, so that you can use the icons in # the material Icons class. uses-material-design: true # To add assets to your application, add an assets section, like this: # assets: # - images/a_dot_burr.jpeg # - images/a_dot_ham.jpeg # An image asset can refer to one or more resolution-specific "variants", see # https://flutter.dev/to/resolution-aware-images # For details regarding adding assets from package dependencies, see # https://flutter.dev/to/asset-from-package # To add custom fonts to your application, add a fonts section here, # in this "flutter" section. Each entry in this list should have a # "family" key with the font family name, and a "fonts" key with a # list giving the asset and other descriptors for the font. For # example: # fonts: # - family: Schyler # fonts: # - asset: fonts/Schyler-Regular.ttf # - asset: fonts/Schyler-Italic.ttf # style: italic # - family: Trajan Pro # fonts: # - asset: fonts/TrajanPro.ttf # - asset: fonts/TrajanPro_Bold.ttf # weight: 700 # # For details regarding fonts from package dependencies, # see https://flutter.dev/to/font-from-package \ No newline at end of file