基础页面

This commit is contained in:
2022-10-20 14:21:39 +08:00
parent 49ad269c2b
commit 42ba10ec61
62 changed files with 5132 additions and 54 deletions

30
lib/utils/convert.dart Normal file
View 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
View 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
View 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,
);
}
}

View 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,
);
}
}

View 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;
}

View 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');
}
}