基础页面
This commit is contained in:
30
lib/utils/convert.dart
Normal file
30
lib/utils/convert.dart
Normal file
@@ -0,0 +1,30 @@
|
||||
import 'package:dart_date/dart_date.dart';
|
||||
|
||||
class Convert {
|
||||
/// 隐藏字符串中间位
|
||||
///
|
||||
/// * [str] 要处理的字符串
|
||||
/// * [start] 字符串从0开始保留位数
|
||||
/// * [end] 末尾保留的长度
|
||||
static String hideCenterStr(
|
||||
String str, {
|
||||
int start = 8,
|
||||
int end = 6,
|
||||
}) {
|
||||
if (str.length <= start + end) {
|
||||
return str;
|
||||
}
|
||||
return '${str.substring(0, start)}...${str.substring(str.length - end)}';
|
||||
}
|
||||
|
||||
/// 时间戳转日期
|
||||
///
|
||||
/// [timestamp] 要转换的时间戳
|
||||
/// [format] 日期格式
|
||||
static String timeFormat(
|
||||
int timestamp, {
|
||||
String format = 'yyyy-MM-dd HH:mm:ss',
|
||||
}) {
|
||||
return DateTime.fromMillisecondsSinceEpoch(timestamp * 1000).format(format);
|
||||
}
|
||||
}
|
||||
251
lib/utils/im_tools.dart
Normal file
251
lib/utils/im_tools.dart
Normal file
@@ -0,0 +1,251 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:azlistview/azlistview.dart';
|
||||
import 'package:chat/configs/app_colors.dart';
|
||||
import 'package:chat/models/im/custom_message_model.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:tencent_im_sdk_plugin/enum/group_change_info_type.dart';
|
||||
import 'package:tencent_im_sdk_plugin/enum/group_tips_elem_type.dart';
|
||||
import 'package:tencent_im_sdk_plugin/enum/message_elem_type.dart';
|
||||
import 'package:tencent_im_sdk_plugin/models/v2_tim_friend_info.dart';
|
||||
import 'package:tencent_im_sdk_plugin/models/v2_tim_friend_info_result.dart';
|
||||
import 'package:tencent_im_sdk_plugin/models/v2_tim_message.dart';
|
||||
|
||||
class ImTools {
|
||||
static String parseNicknameFromResult(V2TimFriendInfoResult? infoResult) {
|
||||
if (infoResult == null) {
|
||||
return '';
|
||||
}
|
||||
|
||||
if (infoResult.friendInfo!.friendRemark != null) {
|
||||
if (infoResult.friendInfo!.friendRemark! == '') {
|
||||
return infoResult.friendInfo!.userProfile!.nickName!;
|
||||
} else {
|
||||
return infoResult.friendInfo!.friendRemark!;
|
||||
}
|
||||
}
|
||||
|
||||
return infoResult.friendInfo!.userProfile!.nickName!;
|
||||
}
|
||||
|
||||
static String parseNicknameFromInfo(V2TimFriendInfo infoResult) {
|
||||
if (infoResult.friendRemark != '') {
|
||||
return infoResult.friendRemark!;
|
||||
}
|
||||
|
||||
return infoResult.userProfile!.nickName!;
|
||||
}
|
||||
|
||||
static parseMessage(V2TimMessage? message) {
|
||||
String text = '';
|
||||
switch (message?.elemType) {
|
||||
case MessageElemType.V2TIM_ELEM_TYPE_TEXT:
|
||||
text = message!.textElem!.text!;
|
||||
break;
|
||||
case MessageElemType.V2TIM_ELEM_TYPE_IMAGE:
|
||||
text = '[图片]';
|
||||
break;
|
||||
case MessageElemType.V2TIM_ELEM_TYPE_SOUND:
|
||||
text = '[语音]';
|
||||
break;
|
||||
case MessageElemType.V2TIM_ELEM_TYPE_VIDEO:
|
||||
text = '[视频]';
|
||||
break;
|
||||
case MessageElemType.V2TIM_ELEM_TYPE_FILE:
|
||||
text = '[文件]';
|
||||
break;
|
||||
case MessageElemType.V2TIM_ELEM_TYPE_LOCATION:
|
||||
text = '[位置]';
|
||||
break;
|
||||
case MessageElemType.V2TIM_ELEM_TYPE_FACE:
|
||||
text = '[表情]';
|
||||
break;
|
||||
case MessageElemType.V2TIM_ELEM_TYPE_MERGER:
|
||||
text = '[聊天记录]';
|
||||
break;
|
||||
case MessageElemType.V2TIM_ELEM_TYPE_CUSTOM:
|
||||
var data = json.decode(message!.customElem!.data!);
|
||||
|
||||
switch (data['businessID']) {
|
||||
case CustomMessageType.CALL:
|
||||
text = '通话';
|
||||
break;
|
||||
case CustomMessageType.DT_TRANSFER:
|
||||
text = '[转账]';
|
||||
break;
|
||||
case CustomMessageType.NAME_CARD:
|
||||
text = '[名片]';
|
||||
break;
|
||||
case CustomMessageType.GROUP_CARD:
|
||||
text = '[群名片]';
|
||||
break;
|
||||
case CustomMessageType.EVALUATION:
|
||||
text = '[评价]';
|
||||
break;
|
||||
default:
|
||||
text = '[${data['businessID']}]';
|
||||
}
|
||||
|
||||
break;
|
||||
case MessageElemType.V2TIM_ELEM_TYPE_GROUP_TIPS:
|
||||
switch (message?.groupTipsElem!.type) {
|
||||
case GroupTipsElemType.V2TIM_GROUP_TIPS_TYPE_JOIN:
|
||||
text = '加入群聊';
|
||||
break;
|
||||
case GroupTipsElemType.V2TIM_GROUP_TIPS_TYPE_INVITE:
|
||||
text = '邀请入群';
|
||||
break;
|
||||
case GroupTipsElemType.V2TIM_GROUP_TIPS_TYPE_QUIT:
|
||||
text = '退出群聊';
|
||||
break;
|
||||
case GroupTipsElemType.V2TIM_GROUP_TIPS_TYPE_KICKED:
|
||||
text = '踢出群聊';
|
||||
break;
|
||||
case GroupTipsElemType.V2TIM_GROUP_TIPS_TYPE_SET_ADMIN:
|
||||
text = '设置管理';
|
||||
break;
|
||||
case GroupTipsElemType.V2TIM_GROUP_TIPS_TYPE_CANCEL_ADMIN:
|
||||
text = '取消管理';
|
||||
break;
|
||||
case GroupTipsElemType.V2TIM_GROUP_TIPS_TYPE_GROUP_INFO_CHANGE:
|
||||
// (opMember 修改群资料:groupName & introduction & notification & faceUrl & owner & custom)
|
||||
switch (message!.groupTipsElem!.groupChangeInfoList![0]!.type) {
|
||||
case GroupChangeInfoType.V2TIM_GROUP_INFO_CHANGE_TYPE_NAME:
|
||||
text = '修改群名称';
|
||||
break;
|
||||
case GroupChangeInfoType
|
||||
.V2TIM_GROUP_INFO_CHANGE_TYPE_INTRODUCTION:
|
||||
text = '群简介修改';
|
||||
break;
|
||||
case GroupChangeInfoType
|
||||
.V2TIM_GROUP_INFO_CHANGE_TYPE_NOTIFICATION:
|
||||
text = '修改群公告';
|
||||
break;
|
||||
case GroupChangeInfoType.V2TIM_GROUP_INFO_CHANGE_TYPE_FACE_URL:
|
||||
text = '群头像修改';
|
||||
break;
|
||||
case GroupChangeInfoType.V2TIM_GROUP_INFO_CHANGE_TYPE_OWNER:
|
||||
text = '群主变更';
|
||||
break;
|
||||
case GroupChangeInfoType.V2TIM_GROUP_INFO_CHANGE_TYPE_CUSTOM:
|
||||
text = '群自定义字段变更';
|
||||
break;
|
||||
default:
|
||||
text = message.groupTipsElem!.groupChangeInfoList![0]!.type
|
||||
.toString();
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case GroupTipsElemType.V2TIM_GROUP_TIPS_TYPE_MEMBER_INFO_CHANGE:
|
||||
text = '群成员资料变更';
|
||||
break;
|
||||
default:
|
||||
text = message!.groupTipsElem!.type.toString();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
text = message!.elemType.toString();
|
||||
}
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
/// 右侧索引栏样式
|
||||
static const IndexBarOptions indexBarOptions = IndexBarOptions(
|
||||
needRebuild: true,
|
||||
ignoreDragCancel: true,
|
||||
downTextStyle: TextStyle(
|
||||
fontSize: 12,
|
||||
color: Colors.white,
|
||||
),
|
||||
downItemDecoration: BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
color: AppColors.primary,
|
||||
),
|
||||
indexHintWidth: 120 / 2,
|
||||
indexHintHeight: 100 / 2,
|
||||
indexHintDecoration: BoxDecoration(
|
||||
image: DecorationImage(
|
||||
image: AssetImage(
|
||||
'assets/chats/index_bar.png',
|
||||
),
|
||||
fit: BoxFit.contain,
|
||||
),
|
||||
),
|
||||
indexHintAlignment: Alignment.centerRight,
|
||||
indexHintChildAlignment: Alignment(
|
||||
-0.25,
|
||||
0.0,
|
||||
),
|
||||
indexHintOffset: Offset(
|
||||
-20,
|
||||
0,
|
||||
),
|
||||
);
|
||||
|
||||
/// 悬浮导航,显示ABCD~Z
|
||||
static Widget susItem(
|
||||
BuildContext context,
|
||||
String tag, {
|
||||
double susHeight = 40,
|
||||
}) {
|
||||
return Container(
|
||||
height: susHeight,
|
||||
width: MediaQuery.of(context).size.width,
|
||||
padding: const EdgeInsets.only(
|
||||
left: 16.0,
|
||||
),
|
||||
color: Colors.grey[200],
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Text(
|
||||
tag,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
static showTrtcMessage(String userID) {
|
||||
return showModalBottomSheet(
|
||||
context: Get.context!,
|
||||
isScrollControlled: true,
|
||||
backgroundColor: AppColors.white,
|
||||
shape: const RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.vertical(top: Radius.circular(8)),
|
||||
),
|
||||
builder: (context) {
|
||||
return Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
// PopMenuItem(
|
||||
// '语音通话',
|
||||
// onTap: () {
|
||||
// TimService.to.tuiCalling.call(userID, CallingScenes.Audio);
|
||||
// Get.back();
|
||||
// },
|
||||
// ),
|
||||
// const Divider(height: 0),
|
||||
// PopMenuItem(
|
||||
// '视频通话',
|
||||
// onTap: () {
|
||||
// TimService.to.tuiCalling.call(userID, CallingScenes.Video);
|
||||
// Get.back();
|
||||
// },
|
||||
// ),
|
||||
const Divider(height: 0),
|
||||
Container(
|
||||
height: 8,
|
||||
color: AppColors.page,
|
||||
),
|
||||
const Divider(height: 0),
|
||||
// PopMenuItem(
|
||||
// '取消',
|
||||
// onTap: () {
|
||||
// Get.back();
|
||||
// },
|
||||
// ),
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
121
lib/utils/request/http.dart
Normal file
121
lib/utils/request/http.dart
Normal file
@@ -0,0 +1,121 @@
|
||||
import 'package:chat/utils/request/http_request.dart';
|
||||
import 'package:dio/dio.dart';
|
||||
|
||||
class Http {
|
||||
/// 取消请求
|
||||
static void cancelRequests({
|
||||
required CancelToken token,
|
||||
}) {
|
||||
HttpRequest().cancelRequests(
|
||||
token: token,
|
||||
);
|
||||
}
|
||||
|
||||
/// GET 请求
|
||||
static Future<T> get<T>(
|
||||
String path, {
|
||||
Map<String, dynamic>? params,
|
||||
Options? options,
|
||||
CancelToken? cancelToken,
|
||||
ProgressCallback? onReceiveProgress,
|
||||
}) async {
|
||||
return await HttpRequest().request(
|
||||
path,
|
||||
method: HttpMethod.get,
|
||||
params: params,
|
||||
options: options,
|
||||
cancelToken: cancelToken,
|
||||
);
|
||||
}
|
||||
|
||||
/// POST 请求
|
||||
static Future<T> post<T>(
|
||||
String path, {
|
||||
Map<String, dynamic>? params,
|
||||
dynamic data,
|
||||
Options? options,
|
||||
CancelToken? cancelToken,
|
||||
ProgressCallback? onSendProgress,
|
||||
ProgressCallback? onReceiveProgress,
|
||||
}) async {
|
||||
return await HttpRequest().request(
|
||||
path,
|
||||
method: HttpMethod.post,
|
||||
params: params,
|
||||
data: data,
|
||||
options: options,
|
||||
cancelToken: cancelToken,
|
||||
onReceiveProgress: onReceiveProgress,
|
||||
);
|
||||
}
|
||||
|
||||
/// PUT
|
||||
static Future<T> put<T>(
|
||||
String path, {
|
||||
Map<String, dynamic>? params,
|
||||
dynamic data,
|
||||
Options? options,
|
||||
CancelToken? cancelToken,
|
||||
ProgressCallback? onSendProgress,
|
||||
ProgressCallback? onReceiveProgress,
|
||||
}) async {
|
||||
return await HttpRequest().request(
|
||||
path,
|
||||
method: HttpMethod.put,
|
||||
params: params,
|
||||
data: data,
|
||||
options: options,
|
||||
cancelToken: cancelToken,
|
||||
onSendProgress: onSendProgress,
|
||||
onReceiveProgress: onReceiveProgress,
|
||||
);
|
||||
}
|
||||
|
||||
/// DELETE
|
||||
static Future<T> delete<T>(
|
||||
String path, {
|
||||
Map<String, dynamic>? params,
|
||||
dynamic data,
|
||||
Options? options,
|
||||
CancelToken? cancelToken,
|
||||
ProgressCallback? onSendProgress,
|
||||
ProgressCallback? onReceiveProgress,
|
||||
}) async {
|
||||
return await HttpRequest().request(
|
||||
path,
|
||||
method: HttpMethod.delete,
|
||||
params: params,
|
||||
data: data,
|
||||
options: options,
|
||||
cancelToken: cancelToken,
|
||||
onSendProgress: onSendProgress,
|
||||
onReceiveProgress: onReceiveProgress,
|
||||
);
|
||||
}
|
||||
|
||||
/// 上传文件
|
||||
static Future<T> upload<T>(
|
||||
String path, {
|
||||
required String filePath,
|
||||
Map<String, dynamic>? params,
|
||||
Options? options,
|
||||
CancelToken? cancelToken,
|
||||
ProgressCallback? onSendProgress,
|
||||
ProgressCallback? onReceiveProgress,
|
||||
}) async {
|
||||
var formData = FormData.fromMap({
|
||||
'upload': await MultipartFile.fromFile(filePath),
|
||||
});
|
||||
|
||||
return await HttpRequest().request(
|
||||
path,
|
||||
method: HttpMethod.post,
|
||||
params: params,
|
||||
data: formData,
|
||||
options: options,
|
||||
cancelToken: cancelToken,
|
||||
onSendProgress: onSendProgress,
|
||||
onReceiveProgress: onReceiveProgress,
|
||||
);
|
||||
}
|
||||
}
|
||||
97
lib/utils/request/http_interceptor.dart
Normal file
97
lib/utils/request/http_interceptor.dart
Normal file
@@ -0,0 +1,97 @@
|
||||
import 'package:chat/services/auth_service.dart';
|
||||
import 'package:chat/utils/ui_tools.dart';
|
||||
import 'package:dio/dio.dart';
|
||||
|
||||
class HttpInterceptor extends Interceptor {
|
||||
@override
|
||||
void onRequest(
|
||||
RequestOptions options,
|
||||
RequestInterceptorHandler handler,
|
||||
) {
|
||||
// 头部添加token
|
||||
// options.headers['Authorization'] = AuthService.to.userToken;
|
||||
options.headers['Accept'] = 'application/json';
|
||||
|
||||
super.onRequest(
|
||||
options,
|
||||
handler,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void onResponse(
|
||||
Response response,
|
||||
ResponseInterceptorHandler handler,
|
||||
) {
|
||||
final apiStatusCode = response.data['status_code'];
|
||||
|
||||
if (apiStatusCode == 200) {
|
||||
response.data = response.data['data'];
|
||||
} else if (apiStatusCode == 401) {
|
||||
throw DioError(
|
||||
response: response,
|
||||
error: "登录超时",
|
||||
requestOptions: response.requestOptions,
|
||||
);
|
||||
} else if (apiStatusCode == 404) {
|
||||
throw DioError(
|
||||
response: response,
|
||||
error: "请求的接口不存在",
|
||||
requestOptions: response.requestOptions,
|
||||
);
|
||||
} else if (apiStatusCode == 0) {
|
||||
throw DioError(
|
||||
response: response,
|
||||
error: response.data['message'],
|
||||
requestOptions: response.requestOptions,
|
||||
);
|
||||
} else {
|
||||
throw DioError(
|
||||
response: response,
|
||||
error: response.data['message'],
|
||||
requestOptions: response.requestOptions,
|
||||
);
|
||||
}
|
||||
super.onResponse(
|
||||
response,
|
||||
handler,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void onError(
|
||||
DioError err,
|
||||
ErrorInterceptorHandler handler,
|
||||
) {
|
||||
switch (err.type) {
|
||||
// 连接服务器超时
|
||||
case DioErrorType.connectTimeout:
|
||||
UiTools.toast('网络传输超时');
|
||||
break;
|
||||
// 响应超时
|
||||
case DioErrorType.receiveTimeout:
|
||||
UiTools.toast('网络传输超时');
|
||||
break;
|
||||
// 发送超时
|
||||
case DioErrorType.sendTimeout:
|
||||
UiTools.toast('网络传输超时');
|
||||
break;
|
||||
// 请求取消
|
||||
case DioErrorType.cancel:
|
||||
break;
|
||||
// 404/503错误
|
||||
case DioErrorType.response:
|
||||
break;
|
||||
// other 其他错误类型
|
||||
case DioErrorType.other:
|
||||
if (err.response?.data['status_code'] == 401) {
|
||||
AuthService.to.logout();
|
||||
}
|
||||
break;
|
||||
}
|
||||
super.onError(
|
||||
err,
|
||||
handler,
|
||||
);
|
||||
}
|
||||
}
|
||||
5
lib/utils/request/http_options.dart
Normal file
5
lib/utils/request/http_options.dart
Normal file
@@ -0,0 +1,5 @@
|
||||
class HttpOptions {
|
||||
static const String baseUrl = 'http://api.gl.shangkelian.cn/api/';
|
||||
static const int connectTimeout = 15000;
|
||||
static const int receiveTimeout = 15000;
|
||||
}
|
||||
91
lib/utils/request/http_request.dart
Normal file
91
lib/utils/request/http_request.dart
Normal file
@@ -0,0 +1,91 @@
|
||||
import 'package:chat/utils/request/http_interceptor.dart';
|
||||
import 'package:chat/utils/request/http_options.dart';
|
||||
import 'package:dio/dio.dart';
|
||||
|
||||
enum HttpMethod {
|
||||
get,
|
||||
post,
|
||||
put,
|
||||
delete,
|
||||
patch,
|
||||
head,
|
||||
}
|
||||
|
||||
class HttpRequest {
|
||||
static HttpRequest? _instance;
|
||||
static Dio _dio = Dio();
|
||||
Dio get dio => _dio;
|
||||
|
||||
HttpRequest._internal() {
|
||||
_instance = this;
|
||||
_instance!._init();
|
||||
}
|
||||
|
||||
factory HttpRequest() => _instance ?? HttpRequest._internal();
|
||||
|
||||
static HttpRequest? getInstance() {
|
||||
return _instance ?? HttpRequest._internal();
|
||||
}
|
||||
|
||||
/// 取消请求token
|
||||
final CancelToken _cancelToken = CancelToken();
|
||||
|
||||
_init() {
|
||||
BaseOptions options = BaseOptions(
|
||||
baseUrl: HttpOptions.baseUrl,
|
||||
connectTimeout: HttpOptions.connectTimeout,
|
||||
receiveTimeout: HttpOptions.receiveTimeout,
|
||||
);
|
||||
_dio = Dio(options);
|
||||
|
||||
/// 添加拦截器
|
||||
_dio.interceptors.add(HttpInterceptor());
|
||||
}
|
||||
|
||||
/// 请求
|
||||
Future request(
|
||||
String path, {
|
||||
HttpMethod method = HttpMethod.get,
|
||||
Map<String, dynamic>? params,
|
||||
dynamic data,
|
||||
Options? options,
|
||||
CancelToken? cancelToken,
|
||||
ProgressCallback? onSendProgress,
|
||||
ProgressCallback? onReceiveProgress,
|
||||
}) async {
|
||||
const methodValues = {
|
||||
HttpMethod.get: 'get',
|
||||
HttpMethod.post: 'post',
|
||||
HttpMethod.put: 'put',
|
||||
HttpMethod.delete: 'delete',
|
||||
HttpMethod.patch: 'patch',
|
||||
HttpMethod.head: 'head'
|
||||
};
|
||||
|
||||
options ??= Options(method: methodValues[method]);
|
||||
|
||||
try {
|
||||
Response response = await _dio.request(
|
||||
path,
|
||||
data: data,
|
||||
queryParameters: params,
|
||||
cancelToken: cancelToken ?? _cancelToken,
|
||||
options: options,
|
||||
onSendProgress: onSendProgress,
|
||||
onReceiveProgress: onReceiveProgress,
|
||||
);
|
||||
// ignore: avoid_print
|
||||
print('请求地址:${response.requestOptions.uri}');
|
||||
// ignore: avoid_print
|
||||
print('响应数据:${response.data}');
|
||||
return response.data;
|
||||
} on DioError catch (e) {
|
||||
throw Exception(e.message);
|
||||
}
|
||||
}
|
||||
|
||||
/// 取消网络请求
|
||||
void cancelRequests({CancelToken? token}) {
|
||||
token ?? _cancelToken.cancel('CANCELED');
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user