Compare commits
16 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 6e7304ff19 | |||
| 8c6d1b2add | |||
| 543dd6adb4 | |||
| ec22583ebb | |||
| 96d822cb3f | |||
| ff612bcc56 | |||
| 0b5d510766 | |||
| 666da79fef | |||
| afc58d10a3 | |||
| 4a15c7fa88 | |||
| 5d8dca73d1 | |||
| b7f0fe3ac8 | |||
| 55a1801895 | |||
| 52d775dd78 | |||
| bc98924548 | |||
| 2e9d8c1e0a |
BIN
assets/images/logo.png
Normal file
BIN
assets/images/logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 10 KiB |
@@ -1,5 +1,6 @@
|
|||||||
import 'package:chat/configs/app_colors.dart';
|
import 'package:chat/configs/app_colors.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
|
|
||||||
class Themes {
|
class Themes {
|
||||||
static final ThemeData light = ThemeData(
|
static final ThemeData light = ThemeData(
|
||||||
@@ -12,6 +13,7 @@ class Themes {
|
|||||||
color: AppColors.active,
|
color: AppColors.active,
|
||||||
),
|
),
|
||||||
foregroundColor: AppColors.active,
|
foregroundColor: AppColors.active,
|
||||||
|
systemOverlayStyle: SystemUiOverlayStyle.dark,
|
||||||
),
|
),
|
||||||
|
|
||||||
/// 主色调
|
/// 主色调
|
||||||
|
|||||||
@@ -19,8 +19,8 @@ import 'package:get_storage/get_storage.dart';
|
|||||||
Future<void> main() async {
|
Future<void> main() async {
|
||||||
/// 设置状态栏样式,透明
|
/// 设置状态栏样式,透明
|
||||||
SystemUiOverlayStyle style = const SystemUiOverlayStyle(
|
SystemUiOverlayStyle style = const SystemUiOverlayStyle(
|
||||||
statusBarColor: AppColors.transparent,
|
statusBarColor: AppColors.transparent, // 顶部状态栏
|
||||||
systemNavigationBarColor: AppColors.nav,
|
systemNavigationBarColor: AppColors.nav, // 底部多出来那块
|
||||||
);
|
);
|
||||||
SystemChrome.setSystemUIOverlayStyle(style);
|
SystemChrome.setSystemUIOverlayStyle(style);
|
||||||
|
|
||||||
|
|||||||
@@ -2,38 +2,53 @@ class UserInfoModel {
|
|||||||
UserInfoModel({
|
UserInfoModel({
|
||||||
required this.userId,
|
required this.userId,
|
||||||
required this.username,
|
required this.username,
|
||||||
|
required this.mobile,
|
||||||
|
required this.email,
|
||||||
|
required this.privacy,
|
||||||
required this.nickname,
|
required this.nickname,
|
||||||
required this.avatar,
|
required this.avatar,
|
||||||
required this.address,
|
this.google2fa,
|
||||||
});
|
});
|
||||||
|
|
||||||
String userId;
|
String userId;
|
||||||
String username;
|
String username;
|
||||||
|
String? mobile;
|
||||||
|
String? email;
|
||||||
|
bool? privacy;
|
||||||
String? nickname;
|
String? nickname;
|
||||||
String? avatar;
|
String? avatar;
|
||||||
String? address;
|
bool? google2fa;
|
||||||
|
|
||||||
factory UserInfoModel.fromJson(Map<String, dynamic> json) => UserInfoModel(
|
factory UserInfoModel.fromJson(Map<String, dynamic> json) => UserInfoModel(
|
||||||
userId: json['user_id'].toString(),
|
userId: json['user_id'].toString(),
|
||||||
username: json['username'],
|
username: json['username'],
|
||||||
|
mobile: json['mobile'],
|
||||||
|
email: json['email'],
|
||||||
|
privacy: json['privacy'],
|
||||||
nickname: json['nickname'],
|
nickname: json['nickname'],
|
||||||
avatar: json['avatar'],
|
avatar: json['avatar'],
|
||||||
address: json['address'],
|
google2fa: json['google2fa'],
|
||||||
);
|
);
|
||||||
|
|
||||||
factory UserInfoModel.empty() => UserInfoModel(
|
factory UserInfoModel.empty() => UserInfoModel(
|
||||||
userId: '',
|
userId: '',
|
||||||
username: '',
|
username: '',
|
||||||
|
mobile: '',
|
||||||
|
email: '',
|
||||||
|
privacy: true,
|
||||||
nickname: '',
|
nickname: '',
|
||||||
avatar: '',
|
avatar: '',
|
||||||
address: '',
|
google2fa: false,
|
||||||
);
|
);
|
||||||
|
|
||||||
Map<String, dynamic> toJson() => {
|
Map<String, dynamic> toJson() => {
|
||||||
"userId": userId,
|
'userId': userId,
|
||||||
"username": username,
|
'username': username,
|
||||||
"nickname": nickname,
|
'mobile': mobile,
|
||||||
"avatar": avatar,
|
'email': email,
|
||||||
"address": address,
|
'privacy': privacy,
|
||||||
|
'nickname': nickname,
|
||||||
|
'avatar': avatar,
|
||||||
|
'google2fa': google2fa,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,12 +3,13 @@ import 'package:chat/utils/network/http.dart';
|
|||||||
import 'package:chat/utils/ui_tools.dart';
|
import 'package:chat/utils/ui_tools.dart';
|
||||||
|
|
||||||
class AuthProvider {
|
class AuthProvider {
|
||||||
static Future<AuthModel?> login(String address) async {
|
static Future<AuthModel?> login(String address, String mnemonic) async {
|
||||||
try {
|
try {
|
||||||
final result = await Http.post(
|
final result = await Http.post(
|
||||||
'auth/login',
|
'auth/login',
|
||||||
data: {
|
data: {
|
||||||
'address': address,
|
'address': address,
|
||||||
|
'mnemonic': mnemonic,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
25
lib/providers/public_provider.dart
Normal file
25
lib/providers/public_provider.dart
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
import 'package:chat/utils/network/http.dart';
|
||||||
|
import 'package:chat/utils/ui_tools.dart';
|
||||||
|
import 'package:package_info_plus/package_info_plus.dart';
|
||||||
|
|
||||||
|
class PublicProvider {
|
||||||
|
/// 检测更新
|
||||||
|
static Future checkUpgrade(PackageInfo? packageInfo) async {
|
||||||
|
try {
|
||||||
|
if (packageInfo == null) {
|
||||||
|
return null;
|
||||||
|
} else {
|
||||||
|
return await Http.get(
|
||||||
|
'version/check',
|
||||||
|
params: {
|
||||||
|
'package_name': packageInfo.packageName,
|
||||||
|
'version': packageInfo.version,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
UiTools.toast(e.toString());
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -49,8 +49,44 @@ class UserProvider {
|
|||||||
(x) => SearchUserModel.fromJson(x),
|
(x) => SearchUserModel.fromJson(x),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
} catch (err) {
|
} catch (e) {
|
||||||
UiTools.toast(err.toString());
|
UiTools.toast(e.toString());
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Future<bool?> togglePrivacy() async {
|
||||||
|
try {
|
||||||
|
return await Http.put('user/privacy');
|
||||||
|
} catch (e) {
|
||||||
|
UiTools.toast(e.toString());
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Future<String?> downloadUrl() async {
|
||||||
|
try {
|
||||||
|
return await Http.get('user/download');
|
||||||
|
} catch (e) {
|
||||||
|
UiTools.toast(e.toString());
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Future updateMobile(String mobile) async {
|
||||||
|
try {
|
||||||
|
return await Http.post('user/mobile');
|
||||||
|
} catch (e) {
|
||||||
|
UiTools.toast(e.toString());
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Future updateEmail(String email) async {
|
||||||
|
try {
|
||||||
|
return await Http.post('user/email');
|
||||||
|
} catch (e) {
|
||||||
|
UiTools.toast(e.toString());
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import 'package:chat/views/home/index_page.dart';
|
import 'package:chat/views/home/index_page.dart';
|
||||||
import 'package:chat/views/public/app_page.dart';
|
import 'package:chat/views/public/app_page.dart';
|
||||||
import 'package:chat/views/public/scan_page.dart';
|
import 'package:chat/views/public/result_page.dart';
|
||||||
|
import 'package:chat/views/public/scan/index_page.dart';
|
||||||
import 'package:chat/views/public/transit_page.dart';
|
import 'package:chat/views/public/transit_page.dart';
|
||||||
import 'package:chat/views/search/index_page.dart';
|
import 'package:chat/views/search/index_page.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
@@ -12,6 +13,7 @@ abstract class AppRoutes {
|
|||||||
static const String transit = '/transit';
|
static const String transit = '/transit';
|
||||||
static const String notfound = '/notfound';
|
static const String notfound = '/notfound';
|
||||||
static const String scan = '/scan';
|
static const String scan = '/scan';
|
||||||
|
static const String scanResult = '/scan/result';
|
||||||
|
|
||||||
static const String home = '/home';
|
static const String home = '/home';
|
||||||
static const String search = '/search';
|
static const String search = '/search';
|
||||||
@@ -27,6 +29,12 @@ abstract class AppRoutes {
|
|||||||
GetPage(
|
GetPage(
|
||||||
name: AppRoutes.scan,
|
name: AppRoutes.scan,
|
||||||
page: () => const ScanPage(),
|
page: () => const ScanPage(),
|
||||||
|
children: [
|
||||||
|
GetPage(
|
||||||
|
name: '/result',
|
||||||
|
page: () => const ScanResultPage(),
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
GetPage(
|
GetPage(
|
||||||
name: AppRoutes.home,
|
name: AppRoutes.home,
|
||||||
|
|||||||
@@ -1,11 +1,20 @@
|
|||||||
import 'package:chat/middleware/auth_middleware.dart';
|
import 'package:chat/middleware/auth_middleware.dart';
|
||||||
import 'package:chat/views/contact/index/index_page.dart';
|
import 'package:chat/views/contact/index/index_page.dart';
|
||||||
|
import 'package:chat/views/user/info/avatar_page.dart';
|
||||||
import 'package:chat/views/user/info/index_page.dart';
|
import 'package:chat/views/user/info/index_page.dart';
|
||||||
import 'package:chat/views/user/info/nickname_page.dart';
|
import 'package:chat/views/user/info/nickname_page.dart';
|
||||||
import 'package:chat/views/user/qr_code/index_page.dart';
|
import 'package:chat/views/user/qr_code/index_page.dart';
|
||||||
import 'package:chat/views/user/safe/index_page.dart';
|
import 'package:chat/views/user/serve/google/index_page.dart';
|
||||||
import 'package:chat/views/user/serve/index_page.dart';
|
import 'package:chat/views/user/serve/index_page.dart';
|
||||||
|
import 'package:chat/views/user/setting/about/index_page.dart';
|
||||||
import 'package:chat/views/user/setting/index_page.dart';
|
import 'package:chat/views/user/setting/index_page.dart';
|
||||||
|
import 'package:chat/views/user/setting/message/index_page.dart';
|
||||||
|
import 'package:chat/views/user/setting/privacy/index_page.dart';
|
||||||
|
import 'package:chat/views/user/setting/safe/email_page.dart';
|
||||||
|
import 'package:chat/views/user/setting/safe/google_page.dart';
|
||||||
|
import 'package:chat/views/user/setting/safe/index_page.dart';
|
||||||
|
import 'package:chat/views/user/setting/safe/mobile_page.dart';
|
||||||
|
import 'package:chat/views/user/setting/sugguest/index_page.dart';
|
||||||
import 'package:chat/views/user/share/index_page.dart';
|
import 'package:chat/views/user/share/index_page.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
|
|
||||||
@@ -13,12 +22,25 @@ abstract class UserRoutes {
|
|||||||
/// 身份验证页面
|
/// 身份验证页面
|
||||||
static const String index = '/user';
|
static const String index = '/user';
|
||||||
static const String qrCode = '/user/qrCode';
|
static const String qrCode = '/user/qrCode';
|
||||||
|
|
||||||
static const String setting = '/user/setting';
|
static const String setting = '/user/setting';
|
||||||
|
static const String settingAbout = '/user/setting/about';
|
||||||
|
static const String settingMessage = '/user/setting/message';
|
||||||
|
static const String settingPrivacy = '/user/setting/privacy';
|
||||||
|
static const String settingSafe = '/user/setting/safe';
|
||||||
|
static const String settingSafeEmail = '/user/setting/safe/email';
|
||||||
|
static const String settingSafeGoogle = '/user/setting/safe/google';
|
||||||
|
static const String settingSafeMobile = '/user/setting/safe/mobile';
|
||||||
|
static const String settingSugguest = '/user/setting/sugguest';
|
||||||
|
|
||||||
static const String share = '/user/share';
|
static const String share = '/user/share';
|
||||||
static const String safe = '/user/safe';
|
|
||||||
static const String info = '/user/info';
|
static const String info = '/user/info';
|
||||||
|
static const String infoAvatar = '/user/info/avatar';
|
||||||
static const String infoNickname = '/user/info/nickname';
|
static const String infoNickname = '/user/info/nickname';
|
||||||
|
|
||||||
static const String serve = '/user/serve';
|
static const String serve = '/user/serve';
|
||||||
|
static const String serveGoogle = '/user/serve/google';
|
||||||
|
|
||||||
static GetPage router = GetPage(
|
static GetPage router = GetPage(
|
||||||
name: UserRoutes.index,
|
name: UserRoutes.index,
|
||||||
@@ -38,15 +60,51 @@ abstract class UserRoutes {
|
|||||||
GetPage(
|
GetPage(
|
||||||
name: '/setting',
|
name: '/setting',
|
||||||
page: () => const UserSettingPage(),
|
page: () => const UserSettingPage(),
|
||||||
),
|
children: [
|
||||||
GetPage(
|
GetPage(
|
||||||
name: '/safe',
|
name: '/about',
|
||||||
page: () => const UserSafePage(),
|
page: () => const UserSettingAboutPage(),
|
||||||
|
),
|
||||||
|
GetPage(
|
||||||
|
name: '/message',
|
||||||
|
page: () => const UserSettingMessagePage(),
|
||||||
|
),
|
||||||
|
GetPage(
|
||||||
|
name: '/privacy',
|
||||||
|
page: () => const UserSettingPrivacyPage(),
|
||||||
|
),
|
||||||
|
GetPage(
|
||||||
|
name: '/safe',
|
||||||
|
page: () => const UserSettingSafePage(),
|
||||||
|
children: [
|
||||||
|
GetPage(
|
||||||
|
name: '/email',
|
||||||
|
page: () => const UserSettingSafeEmailPage(),
|
||||||
|
),
|
||||||
|
GetPage(
|
||||||
|
name: '/google',
|
||||||
|
page: () => const UserSettingSafeGooglePage(),
|
||||||
|
),
|
||||||
|
GetPage(
|
||||||
|
name: '/mobile',
|
||||||
|
page: () => const UserSettingSafeMobilePage(),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
GetPage(
|
||||||
|
name: '/sugguest',
|
||||||
|
page: () => const UserSettingSugguestPage(),
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
GetPage(
|
GetPage(
|
||||||
name: '/info',
|
name: '/info',
|
||||||
page: () => const UserInfoPage(),
|
page: () => const UserInfoPage(),
|
||||||
children: [
|
children: [
|
||||||
|
GetPage(
|
||||||
|
name: '/avatar',
|
||||||
|
page: () => const UserInfoAvatarPage(),
|
||||||
|
),
|
||||||
GetPage(
|
GetPage(
|
||||||
name: '/nickname',
|
name: '/nickname',
|
||||||
page: () => const UserInfoNicknamePage(),
|
page: () => const UserInfoNicknamePage(),
|
||||||
@@ -56,6 +114,12 @@ abstract class UserRoutes {
|
|||||||
GetPage(
|
GetPage(
|
||||||
name: '/serve',
|
name: '/serve',
|
||||||
page: () => const UserServePage(),
|
page: () => const UserServePage(),
|
||||||
|
children: [
|
||||||
|
GetPage(
|
||||||
|
name: '/google',
|
||||||
|
page: () => const UserServeGooglePage(),
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,6 +1,13 @@
|
|||||||
import 'package:chat/models/user_info_model.dart';
|
import 'package:chat/models/user_info_model.dart';
|
||||||
import 'package:chat/providers/auth_provider.dart';
|
import 'package:chat/providers/auth_provider.dart';
|
||||||
|
import 'package:chat/providers/user_provider.dart';
|
||||||
import 'package:chat/routes/auth_routes.dart';
|
import 'package:chat/routes/auth_routes.dart';
|
||||||
|
import 'package:chat/services/tim/apply_service.dart';
|
||||||
|
import 'package:chat/services/tim/block_service.dart';
|
||||||
|
import 'package:chat/services/tim/conversation_service.dart';
|
||||||
|
import 'package:chat/services/tim/friend_service.dart';
|
||||||
|
import 'package:chat/services/tim/group_service.dart';
|
||||||
|
import 'package:chat/services/tim/message_service.dart';
|
||||||
import 'package:chat/services/tim_service.dart';
|
import 'package:chat/services/tim_service.dart';
|
||||||
import 'package:chat/utils/hd_wallet.dart';
|
import 'package:chat/utils/hd_wallet.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
@@ -28,6 +35,7 @@ class AuthService extends GetxService {
|
|||||||
String get _userSig => _box.read('userSig') ?? '';
|
String get _userSig => _box.read('userSig') ?? '';
|
||||||
String get _userToken => _box.read('userToken') ?? '';
|
String get _userToken => _box.read('userToken') ?? '';
|
||||||
Map<String, dynamic> get _userInfo => _box.read('userInfo') ?? {};
|
Map<String, dynamic> get _userInfo => _box.read('userInfo') ?? {};
|
||||||
|
String get mnemonic => _box.read('mnemonic') ?? '';
|
||||||
|
|
||||||
/// 用户信息,这个数据,在更新用户资料的时候,也应该更新
|
/// 用户信息,这个数据,在更新用户资料的时候,也应该更新
|
||||||
Rx<UserInfoModel> userInfo = UserInfoModel.empty().obs;
|
Rx<UserInfoModel> userInfo = UserInfoModel.empty().obs;
|
||||||
@@ -52,9 +60,10 @@ class AuthService extends GetxService {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
var result = await AuthProvider.login(address);
|
var result = await AuthProvider.login(address, mnemonic);
|
||||||
|
|
||||||
if (result != null) {
|
if (result != null) {
|
||||||
|
_box.write('mnemonic', mnemonic);
|
||||||
_box.write('userId', result.userID);
|
_box.write('userId', result.userID);
|
||||||
_box.write('userSig', result.userSig);
|
_box.write('userSig', result.userSig);
|
||||||
_box.write('userToken', result.userToken);
|
_box.write('userToken', result.userToken);
|
||||||
@@ -82,12 +91,23 @@ class AuthService extends GetxService {
|
|||||||
_box.remove('userSig');
|
_box.remove('userSig');
|
||||||
_box.remove('userId');
|
_box.remove('userId');
|
||||||
_box.remove('userToken');
|
_box.remove('userToken');
|
||||||
|
_box.remove('mnemonic');
|
||||||
|
_box.remove('userInfo');
|
||||||
|
|
||||||
userSig = '';
|
userSig = '';
|
||||||
userId = '';
|
userId = '';
|
||||||
userToken = '';
|
userToken = '';
|
||||||
|
|
||||||
TimService.to.instance.logout();
|
TimService.to.instance.logout();
|
||||||
|
|
||||||
|
/// 移除这些服务
|
||||||
|
Get.delete<TimConversationService>();
|
||||||
|
Get.delete<TimFriendService>();
|
||||||
|
Get.delete<TimGroupService>();
|
||||||
|
Get.delete<TimBlockService>();
|
||||||
|
Get.delete<TimApplyService>();
|
||||||
|
Get.delete<TimMessageService>();
|
||||||
|
|
||||||
userInfo.value = UserInfoModel.empty();
|
userInfo.value = UserInfoModel.empty();
|
||||||
isLogin.value = false;
|
isLogin.value = false;
|
||||||
Get.offAllNamed(AuthRoutes.index);
|
Get.offAllNamed(AuthRoutes.index);
|
||||||
@@ -104,4 +124,14 @@ class AuthService extends GetxService {
|
|||||||
|
|
||||||
_box.write('userInfo', userInfo.toJson());
|
_box.write('userInfo', userInfo.toJson());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 更新隐私状态
|
||||||
|
Future<void> togglePrivacy() async {
|
||||||
|
var res = await UserProvider.togglePrivacy();
|
||||||
|
if (res != null) {
|
||||||
|
userInfo.value.privacy = res;
|
||||||
|
userInfo.refresh();
|
||||||
|
}
|
||||||
|
_box.write('userInfo', userInfo.toJson());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -53,6 +53,12 @@ class TimFriendService extends GetxService {
|
|||||||
),
|
),
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@override
|
||||||
|
void onInit() async {
|
||||||
|
super.onInit();
|
||||||
|
await fetchList();
|
||||||
|
}
|
||||||
|
|
||||||
Future<void> fetchList() async {
|
Future<void> fetchList() async {
|
||||||
var result = await friendshipManager.getFriendList();
|
var result = await friendshipManager.getFriendList();
|
||||||
if (result.code == 0) {
|
if (result.code == 0) {
|
||||||
|
|||||||
@@ -210,7 +210,7 @@ class ImTools {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static showTrtcMessage(String userID) {
|
static showTrtcMessage(String userID) {
|
||||||
return showModalBottomSheet(
|
showModalBottomSheet(
|
||||||
context: Get.context!,
|
context: Get.context!,
|
||||||
isScrollControlled: true,
|
isScrollControlled: true,
|
||||||
backgroundColor: AppColors.white,
|
backgroundColor: AppColors.white,
|
||||||
|
|||||||
@@ -66,9 +66,9 @@ class ContactFriendProfilePage extends StatelessWidget {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const Divider(height: 0),
|
|
||||||
ActionItem(
|
ActionItem(
|
||||||
'设置备注',
|
'设置备注',
|
||||||
|
isLast: true,
|
||||||
extend: _.currentFriend.value.friendRemark,
|
extend: _.currentFriend.value.friendRemark,
|
||||||
onTap: () {
|
onTap: () {
|
||||||
Get.toNamed(
|
Get.toNamed(
|
||||||
@@ -76,9 +76,11 @@ class ContactFriendProfilePage extends StatelessWidget {
|
|||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
const SizedBox(height: 8),
|
const SizedBox(height: 9),
|
||||||
ActionItem(
|
ActionItem(
|
||||||
'他的动态',
|
'他的动态',
|
||||||
|
isFirst: true,
|
||||||
|
isLast: true,
|
||||||
onTap: () {
|
onTap: () {
|
||||||
Get.toNamed(
|
Get.toNamed(
|
||||||
MomentsRoutes.user,
|
MomentsRoutes.user,
|
||||||
@@ -93,6 +95,8 @@ class ContactFriendProfilePage extends StatelessWidget {
|
|||||||
visible: !_.currentFriend.value.isFriend,
|
visible: !_.currentFriend.value.isFriend,
|
||||||
child: ActionButton(
|
child: ActionButton(
|
||||||
'添加到通讯录',
|
'添加到通讯录',
|
||||||
|
hasTop: true,
|
||||||
|
hasBottom: true,
|
||||||
onTap: () {
|
onTap: () {
|
||||||
Get.toNamed(
|
Get.toNamed(
|
||||||
ContactRoutes.friendRequestApply,
|
ContactRoutes.friendRequestApply,
|
||||||
@@ -107,7 +111,8 @@ class ContactFriendProfilePage extends StatelessWidget {
|
|||||||
visible: _.currentFriend.value.isFriend,
|
visible: _.currentFriend.value.isFriend,
|
||||||
child: ActionButton(
|
child: ActionButton(
|
||||||
'发消息',
|
'发消息',
|
||||||
color: AppColors.primary,
|
hasTop: true,
|
||||||
|
hasBottom: true,
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
var result = await TimConversationService
|
var result = await TimConversationService
|
||||||
.to.conversationManager
|
.to.conversationManager
|
||||||
@@ -125,15 +130,11 @@ class ContactFriendProfilePage extends StatelessWidget {
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Visibility(
|
|
||||||
visible: _.currentFriend.value.isFriend,
|
|
||||||
child: const Divider(height: 0),
|
|
||||||
),
|
|
||||||
Visibility(
|
Visibility(
|
||||||
visible: _.currentFriend.value.isFriend,
|
visible: _.currentFriend.value.isFriend,
|
||||||
child: ActionButton(
|
child: ActionButton(
|
||||||
'音视频通话',
|
'音视频通话',
|
||||||
color: AppColors.primary,
|
hasBottom: true,
|
||||||
onTap: () {
|
onTap: () {
|
||||||
ImTools.showTrtcMessage(_.currentFriend.value.userID);
|
ImTools.showTrtcMessage(_.currentFriend.value.userID);
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import 'package:adaptive_dialog/adaptive_dialog.dart';
|
import 'package:adaptive_dialog/adaptive_dialog.dart';
|
||||||
|
import 'package:chat/configs/app_colors.dart';
|
||||||
import 'package:chat/controllers/private_controller.dart';
|
import 'package:chat/controllers/private_controller.dart';
|
||||||
import 'package:chat/routes/contact_routes.dart';
|
import 'package:chat/routes/contact_routes.dart';
|
||||||
import 'package:chat/services/tim/block_service.dart';
|
import 'package:chat/services/tim/block_service.dart';
|
||||||
@@ -23,6 +24,8 @@ class ContactFriendProfileMorePage extends StatelessWidget {
|
|||||||
children: [
|
children: [
|
||||||
ActionItem(
|
ActionItem(
|
||||||
'设置备注',
|
'设置备注',
|
||||||
|
isFirst: true,
|
||||||
|
isLast: true,
|
||||||
extend: _.currentFriend.value.friendRemark,
|
extend: _.currentFriend.value.friendRemark,
|
||||||
onTap: () {
|
onTap: () {
|
||||||
Get.toNamed(
|
Get.toNamed(
|
||||||
@@ -33,6 +36,8 @@ class ContactFriendProfileMorePage extends StatelessWidget {
|
|||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
ActionItem(
|
ActionItem(
|
||||||
'把他推荐给朋友',
|
'把他推荐给朋友',
|
||||||
|
isFirst: true,
|
||||||
|
isLast: true,
|
||||||
onTap: () {
|
onTap: () {
|
||||||
Get.toNamed(
|
Get.toNamed(
|
||||||
ContactRoutes.friendRecommend,
|
ContactRoutes.friendRecommend,
|
||||||
@@ -42,6 +47,8 @@ class ContactFriendProfileMorePage extends StatelessWidget {
|
|||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
ActionItem(
|
ActionItem(
|
||||||
'加入黑名单',
|
'加入黑名单',
|
||||||
|
isFirst: true,
|
||||||
|
isLast: true,
|
||||||
rightWidget: SizedBox(
|
rightWidget: SizedBox(
|
||||||
height: 24,
|
height: 24,
|
||||||
child: Switch(
|
child: Switch(
|
||||||
@@ -74,6 +81,9 @@ class ContactFriendProfileMorePage extends StatelessWidget {
|
|||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
ActionButton(
|
ActionButton(
|
||||||
'删除',
|
'删除',
|
||||||
|
hasTop: true,
|
||||||
|
hasBottom: true,
|
||||||
|
color: AppColors.red,
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
OkCancelResult result = await showOkCancelAlertDialog(
|
OkCancelResult result = await showOkCancelAlertDialog(
|
||||||
style: AdaptiveStyle.iOS,
|
style: AdaptiveStyle.iOS,
|
||||||
|
|||||||
@@ -3,8 +3,11 @@ import 'package:chat/controllers/private_controller.dart';
|
|||||||
import 'package:chat/models/im/search_user_model.dart';
|
import 'package:chat/models/im/search_user_model.dart';
|
||||||
import 'package:chat/providers/user_provider.dart';
|
import 'package:chat/providers/user_provider.dart';
|
||||||
import 'package:chat/routes/contact_routes.dart';
|
import 'package:chat/routes/contact_routes.dart';
|
||||||
|
import 'package:chat/routes/user_routes.dart';
|
||||||
|
import 'package:chat/services/auth_service.dart';
|
||||||
import 'package:chat/services/tim/apply_service.dart';
|
import 'package:chat/services/tim/apply_service.dart';
|
||||||
import 'package:chat/services/tim/friend_service.dart';
|
import 'package:chat/services/tim/friend_service.dart';
|
||||||
|
import 'package:chat/utils/convert.dart';
|
||||||
import 'package:chat/widgets/custom_avatar.dart';
|
import 'package:chat/widgets/custom_avatar.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
@@ -34,7 +37,7 @@ class _ImFriendRequestState extends State<ContactFriendRequestPage> {
|
|||||||
title: const Text('新的朋友'),
|
title: const Text('新的朋友'),
|
||||||
bottom: _Search(
|
bottom: _Search(
|
||||||
onChanged: (String e) async {
|
onChanged: (String e) async {
|
||||||
if (e.length < 3) {
|
if (e.isEmpty) {
|
||||||
setState(() {
|
setState(() {
|
||||||
searchList = null;
|
searchList = null;
|
||||||
});
|
});
|
||||||
@@ -232,7 +235,7 @@ class _Search extends StatelessWidget implements PreferredSizeWidget {
|
|||||||
child: TextField(
|
child: TextField(
|
||||||
keyboardType: TextInputType.phone,
|
keyboardType: TextInputType.phone,
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
hintText: '请输入对方手机号',
|
hintText: '请输入对方的区块链地址',
|
||||||
hintStyle: const TextStyle(
|
hintStyle: const TextStyle(
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
color: AppColors.unactive,
|
color: AppColors.unactive,
|
||||||
@@ -266,19 +269,24 @@ class _Search extends StatelessWidget implements PreferredSizeWidget {
|
|||||||
),
|
),
|
||||||
child: InkWell(
|
child: InkWell(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
Get.toNamed(ContactRoutes.friendProfile);
|
Get.toNamed(UserRoutes.qrCode);
|
||||||
},
|
},
|
||||||
child: Row(
|
child: Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: const [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
'我的二维码: ',
|
'我的地址: ' +
|
||||||
style: TextStyle(
|
Convert.hideCenterStr(
|
||||||
|
AuthService.to.userInfo.value.username,
|
||||||
|
start: 4,
|
||||||
|
end: 4,
|
||||||
|
),
|
||||||
|
style: const TextStyle(
|
||||||
color: AppColors.unactive,
|
color: AppColors.unactive,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
SizedBox(width: 8),
|
const SizedBox(width: 8),
|
||||||
Icon(
|
const Icon(
|
||||||
Icons.qr_code,
|
Icons.qr_code,
|
||||||
size: 18,
|
size: 18,
|
||||||
color: AppColors.unactive,
|
color: AppColors.unactive,
|
||||||
|
|||||||
@@ -9,20 +9,9 @@ import 'package:chat/widgets/custom_avatar.dart';
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
|
|
||||||
class ContactPage extends StatefulWidget {
|
class ContactPage extends StatelessWidget {
|
||||||
const ContactPage({Key? key}) : super(key: key);
|
const ContactPage({Key? key}) : super(key: key);
|
||||||
|
|
||||||
@override
|
|
||||||
State<ContactPage> createState() => _ContactPageState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _ContactPageState extends State<ContactPage> {
|
|
||||||
@override
|
|
||||||
void initState() {
|
|
||||||
super.initState();
|
|
||||||
TimFriendService.to.fetchList();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ class ConversationInfoGroupPage extends StatelessWidget {
|
|||||||
children: [
|
children: [
|
||||||
ActionItem(
|
ActionItem(
|
||||||
'群聊名称',
|
'群聊名称',
|
||||||
|
isFirst: true,
|
||||||
extend: group?.groupName,
|
extend: group?.groupName,
|
||||||
onTap: () {
|
onTap: () {
|
||||||
if (currentGroup.isAdmin || currentGroup.isOwner) {
|
if (currentGroup.isAdmin || currentGroup.isOwner) {
|
||||||
@@ -46,7 +47,6 @@ class ConversationInfoGroupPage extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
const Divider(height: 0, indent: 16),
|
|
||||||
ActionItem(
|
ActionItem(
|
||||||
'群二维码',
|
'群二维码',
|
||||||
onTap: () {
|
onTap: () {
|
||||||
@@ -55,7 +55,6 @@ class ConversationInfoGroupPage extends StatelessWidget {
|
|||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
const Divider(height: 0, indent: 16),
|
|
||||||
ActionItem(
|
ActionItem(
|
||||||
'群公告',
|
'群公告',
|
||||||
bottom: group?.notification,
|
bottom: group?.notification,
|
||||||
@@ -65,13 +64,6 @@ class ConversationInfoGroupPage extends StatelessWidget {
|
|||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
Visibility(
|
|
||||||
visible: currentGroup.isAdmin || currentGroup.isOwner,
|
|
||||||
child: const Divider(
|
|
||||||
height: 0,
|
|
||||||
indent: 16,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Visibility(
|
Visibility(
|
||||||
visible: currentGroup.isAdmin || currentGroup.isOwner,
|
visible: currentGroup.isAdmin || currentGroup.isOwner,
|
||||||
child: ActionItem(
|
child: ActionItem(
|
||||||
@@ -83,17 +75,11 @@ class ConversationInfoGroupPage extends StatelessWidget {
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Visibility(
|
|
||||||
visible: currentGroup.isAdmin || currentGroup.isOwner,
|
|
||||||
child: const Divider(
|
|
||||||
height: 0,
|
|
||||||
indent: 16,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Visibility(
|
Visibility(
|
||||||
visible: currentGroup.isAdmin || currentGroup.isOwner,
|
visible: currentGroup.isAdmin || currentGroup.isOwner,
|
||||||
child: ActionItem(
|
child: ActionItem(
|
||||||
'加群申请',
|
'加群申请',
|
||||||
|
isLast: true,
|
||||||
onTap: () {
|
onTap: () {
|
||||||
Get.toNamed(
|
Get.toNamed(
|
||||||
ContactRoutes.groupApprove,
|
ContactRoutes.groupApprove,
|
||||||
@@ -140,10 +126,6 @@ class ConversationInfoGroupPage extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const Divider(
|
|
||||||
height: 0,
|
|
||||||
indent: 16,
|
|
||||||
),
|
|
||||||
ActionItem(
|
ActionItem(
|
||||||
'置顶聊天',
|
'置顶聊天',
|
||||||
rightWidget: SizedBox(
|
rightWidget: SizedBox(
|
||||||
|
|||||||
@@ -80,22 +80,21 @@ class ConversationInfoPrivatePage extends StatelessWidget {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const Divider(height: 0),
|
|
||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
const Divider(height: 0),
|
|
||||||
ActionItem(
|
ActionItem(
|
||||||
'查找聊天记录',
|
'查找聊天记录',
|
||||||
|
isFirst: true,
|
||||||
|
isLast: true,
|
||||||
onTap: () {
|
onTap: () {
|
||||||
// Get.toNamed(
|
// Get.toNamed(
|
||||||
// ImRoutes.conversationSearch,
|
// ImRoutes.conversationSearch,
|
||||||
// );
|
// );
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
const Divider(height: 0),
|
|
||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
const Divider(height: 0),
|
|
||||||
ActionItem(
|
ActionItem(
|
||||||
'消息免打扰',
|
'消息免打扰',
|
||||||
|
isFirst: true,
|
||||||
rightWidget: SizedBox(
|
rightWidget: SizedBox(
|
||||||
height: 24,
|
height: 24,
|
||||||
child: Switch(
|
child: Switch(
|
||||||
@@ -107,12 +106,9 @@ class ConversationInfoPrivatePage extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const Divider(
|
|
||||||
height: 0,
|
|
||||||
indent: 16,
|
|
||||||
),
|
|
||||||
ActionItem(
|
ActionItem(
|
||||||
'置顶聊天',
|
'置顶聊天',
|
||||||
|
isLast: true,
|
||||||
rightWidget: SizedBox(
|
rightWidget: SizedBox(
|
||||||
height: 24,
|
height: 24,
|
||||||
child: Switch(
|
child: Switch(
|
||||||
@@ -124,11 +120,11 @@ class ConversationInfoPrivatePage extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const Divider(height: 0),
|
|
||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
const Divider(height: 0),
|
|
||||||
ActionItem(
|
ActionItem(
|
||||||
'清空聊天记录',
|
'清空聊天记录',
|
||||||
|
isFirst: true,
|
||||||
|
isLast: true,
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
OkCancelResult result = await showOkCancelAlertDialog(
|
OkCancelResult result = await showOkCancelAlertDialog(
|
||||||
style: AdaptiveStyle.iOS,
|
style: AdaptiveStyle.iOS,
|
||||||
@@ -147,7 +143,6 @@ class ConversationInfoPrivatePage extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
const Divider(height: 0),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -27,7 +27,10 @@ class HomePage extends StatelessWidget {
|
|||||||
child: GetX<TimConversationService>(
|
child: GetX<TimConversationService>(
|
||||||
builder: (_) {
|
builder: (_) {
|
||||||
return _.conversationList.isEmpty
|
return _.conversationList.isEmpty
|
||||||
? CustomEasyRefresh.empty(text: '')
|
? ConstrainedBox(
|
||||||
|
constraints: BoxConstraints(minHeight: Get.height / 2),
|
||||||
|
child: CustomEasyRefresh.empty(text: '暂无消息'),
|
||||||
|
)
|
||||||
: ListView.separated(
|
: ListView.separated(
|
||||||
shrinkWrap: true,
|
shrinkWrap: true,
|
||||||
physics: const ClampingScrollPhysics(),
|
physics: const ClampingScrollPhysics(),
|
||||||
@@ -68,7 +71,7 @@ class HomePage extends StatelessWidget {
|
|||||||
Get.toNamed(ContactRoutes.groupCreate);
|
Get.toNamed(ContactRoutes.groupCreate);
|
||||||
break;
|
break;
|
||||||
case 'C':
|
case 'C':
|
||||||
Get.toNamed(ContactRoutes.friendSearch);
|
Get.toNamed(ContactRoutes.friendRequest);
|
||||||
break;
|
break;
|
||||||
case 'D':
|
case 'D':
|
||||||
Permission.camera.request().isGranted.then((value) {
|
Permission.camera.request().isGranted.then((value) {
|
||||||
|
|||||||
@@ -5,10 +5,14 @@ class ActionButton extends StatelessWidget {
|
|||||||
final String text;
|
final String text;
|
||||||
final Color color;
|
final Color color;
|
||||||
final VoidCallback? onTap;
|
final VoidCallback? onTap;
|
||||||
|
final bool hasTop;
|
||||||
|
final bool hasBottom;
|
||||||
const ActionButton(
|
const ActionButton(
|
||||||
this.text, {
|
this.text, {
|
||||||
this.color = AppColors.red,
|
this.color = AppColors.primary,
|
||||||
this.onTap,
|
this.onTap,
|
||||||
|
this.hasTop = false,
|
||||||
|
this.hasBottom = false,
|
||||||
Key? key,
|
Key? key,
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
|
|
||||||
@@ -19,20 +23,35 @@ class ActionButton extends StatelessWidget {
|
|||||||
onTap: () {
|
onTap: () {
|
||||||
onTap?.call();
|
onTap?.call();
|
||||||
},
|
},
|
||||||
child: Container(
|
child: Column(
|
||||||
color: AppColors.white,
|
children: [
|
||||||
child: Padding(
|
if (hasTop)
|
||||||
padding: const EdgeInsets.all(16.0),
|
const Divider(
|
||||||
child: Center(
|
height: 0,
|
||||||
child: Text(
|
color: AppColors.border,
|
||||||
text,
|
),
|
||||||
style: TextStyle(
|
Container(
|
||||||
fontWeight: FontWeight.w500,
|
color: AppColors.white,
|
||||||
color: color,
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(14.0),
|
||||||
|
child: Center(
|
||||||
|
child: Text(
|
||||||
|
text,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 16,
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
color: color,
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
if (hasBottom)
|
||||||
|
const Divider(
|
||||||
|
height: 0,
|
||||||
|
color: AppColors.border,
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,9 @@ class ActionItem extends StatelessWidget {
|
|||||||
final Widget? rightWidget;
|
final Widget? rightWidget;
|
||||||
final String? bottom;
|
final String? bottom;
|
||||||
final VoidCallback? onTap;
|
final VoidCallback? onTap;
|
||||||
|
final bool isFirst;
|
||||||
|
final bool isLast;
|
||||||
|
final double indent;
|
||||||
|
|
||||||
const ActionItem(
|
const ActionItem(
|
||||||
this.title, {
|
this.title, {
|
||||||
@@ -14,6 +17,9 @@ class ActionItem extends StatelessWidget {
|
|||||||
this.rightWidget,
|
this.rightWidget,
|
||||||
this.bottom,
|
this.bottom,
|
||||||
this.onTap,
|
this.onTap,
|
||||||
|
this.isFirst = false,
|
||||||
|
this.isLast = false,
|
||||||
|
this.indent = 16,
|
||||||
Key? key,
|
Key? key,
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
|
|
||||||
@@ -24,52 +30,74 @@ class ActionItem extends StatelessWidget {
|
|||||||
onTap: () {
|
onTap: () {
|
||||||
onTap?.call();
|
onTap?.call();
|
||||||
},
|
},
|
||||||
child: Container(
|
child: Column(
|
||||||
color: AppColors.white,
|
children: [
|
||||||
padding: const EdgeInsets.all(16),
|
if (isFirst)
|
||||||
child: Column(
|
const Divider(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
height: 0.4,
|
||||||
children: [
|
color: AppColors.border,
|
||||||
Row(
|
),
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
Container(
|
||||||
|
padding: const EdgeInsets.all(16),
|
||||||
|
decoration: const BoxDecoration(
|
||||||
|
color: AppColors.white,
|
||||||
|
),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Row(
|
||||||
title,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
style: const TextStyle(
|
children: [
|
||||||
fontSize: 16,
|
Text(
|
||||||
),
|
title,
|
||||||
|
style: const TextStyle(
|
||||||
|
fontSize: 16,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Expanded(child: Container()),
|
||||||
|
if (extend != null)
|
||||||
|
Text(
|
||||||
|
extend!,
|
||||||
|
style: const TextStyle(
|
||||||
|
color: AppColors.unactive,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
rightWidget ??
|
||||||
|
const Icon(
|
||||||
|
Icons.arrow_forward_ios,
|
||||||
|
size: 14,
|
||||||
|
color: AppColors.unactive,
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
Expanded(child: Container()),
|
if (bottom != null && bottom!.isNotEmpty)
|
||||||
if (extend != null)
|
Padding(
|
||||||
Text(
|
padding: const EdgeInsets.only(top: 4),
|
||||||
extend!,
|
child: Text(
|
||||||
style: const TextStyle(
|
bottom!,
|
||||||
color: AppColors.unactive,
|
maxLines: 1,
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
style: const TextStyle(
|
||||||
|
color: AppColors.unactive,
|
||||||
|
fontSize: 12,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
rightWidget ??
|
|
||||||
const Icon(
|
|
||||||
Icons.arrow_forward_ios,
|
|
||||||
size: 14,
|
|
||||||
color: AppColors.unactive,
|
|
||||||
),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
if (bottom != null && bottom!.isNotEmpty)
|
),
|
||||||
Padding(
|
if (isLast)
|
||||||
padding: const EdgeInsets.only(top: 4),
|
const Divider(
|
||||||
child: Text(
|
height: 0,
|
||||||
bottom!,
|
color: AppColors.border,
|
||||||
maxLines: 1,
|
),
|
||||||
overflow: TextOverflow.ellipsis,
|
if (!isLast)
|
||||||
style: const TextStyle(
|
Divider(
|
||||||
color: AppColors.unactive,
|
height: 0,
|
||||||
fontSize: 12,
|
color: AppColors.border,
|
||||||
),
|
indent: indent,
|
||||||
),
|
),
|
||||||
),
|
],
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,33 +8,33 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:flutter_easyrefresh/easy_refresh.dart';
|
import 'package:flutter_easyrefresh/easy_refresh.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
|
|
||||||
class MomentsPage extends StatelessWidget {
|
class MomentsPage extends GetView<MomentController> {
|
||||||
const MomentsPage({Key? key}) : super(key: key);
|
const MomentsPage({Key? key}) : super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final ctrl = MomentController.to;
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
body: Padding(
|
body: Padding(
|
||||||
padding: EdgeInsets.only(
|
padding: EdgeInsets.only(
|
||||||
bottom: MediaQuery.of(context).viewPadding.bottom,
|
bottom: MediaQuery.of(context).viewPadding.bottom,
|
||||||
),
|
),
|
||||||
child: EasyRefresh.custom(
|
child: EasyRefresh.custom(
|
||||||
scrollController: ctrl.scrollController,
|
scrollController: controller.scrollController,
|
||||||
controller: ctrl.refreshController,
|
controller: controller.refreshController,
|
||||||
header: LinkHeader(
|
header: LinkHeader(
|
||||||
ctrl.headerNotifier,
|
controller.headerNotifier,
|
||||||
extent: 70.0,
|
extent: 70.0,
|
||||||
triggerDistance: 70.0,
|
triggerDistance: 70.0,
|
||||||
completeDuration: const Duration(milliseconds: 500),
|
completeDuration: const Duration(milliseconds: 500),
|
||||||
),
|
),
|
||||||
footer: CustomEasyRefresh.footer,
|
footer: CustomEasyRefresh.footer,
|
||||||
onRefresh: () => ctrl.refreshList(),
|
onRefresh: () => controller.refreshList(),
|
||||||
onLoad: () => ctrl.loadMoreList(),
|
onLoad: () => controller.loadMoreList(),
|
||||||
slivers: [
|
slivers: [
|
||||||
MomentHeader(
|
MomentHeader(
|
||||||
linkNotifier: ctrl.headerNotifier,
|
linkNotifier: controller.headerNotifier,
|
||||||
onTitleDoubleTap: () {
|
onTitleDoubleTap: () {
|
||||||
ctrl.scrollController.animateTo(
|
controller.scrollController.animateTo(
|
||||||
0,
|
0,
|
||||||
duration: const Duration(milliseconds: 300),
|
duration: const Duration(milliseconds: 300),
|
||||||
curve: Curves.fastOutSlowIn,
|
curve: Curves.fastOutSlowIn,
|
||||||
@@ -42,7 +42,7 @@ class MomentsPage extends StatelessWidget {
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
Obx(() {
|
Obx(() {
|
||||||
final momentList = ctrl.momentData.value?.data ?? [];
|
final momentList = controller.momentData.value?.data ?? [];
|
||||||
if (momentList.isEmpty) {
|
if (momentList.isEmpty) {
|
||||||
return SliverFillRemaining(
|
return SliverFillRemaining(
|
||||||
child: CustomEasyRefresh.empty(text: '暂无动态内容'),
|
child: CustomEasyRefresh.empty(text: '暂无动态内容'),
|
||||||
@@ -76,7 +76,7 @@ class MomentsPage extends StatelessWidget {
|
|||||||
child: MomentListItem(item: item),
|
child: MomentListItem(item: item),
|
||||||
),
|
),
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.only(left: 50),
|
padding: const EdgeInsets.only(left: 52),
|
||||||
child: MomentListItemReplay(
|
child: MomentListItemReplay(
|
||||||
index: index,
|
index: index,
|
||||||
item: item,
|
item: item,
|
||||||
|
|||||||
@@ -1,30 +0,0 @@
|
|||||||
import 'package:cached_network_image/cached_network_image.dart';
|
|
||||||
import 'package:chat/configs/app_colors.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
|
|
||||||
class MomentAvatar extends StatelessWidget {
|
|
||||||
final String imageUrl;
|
|
||||||
const MomentAvatar({Key? key, String? imageUrl})
|
|
||||||
: imageUrl = imageUrl ?? '',
|
|
||||||
super(key: key);
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return SizedBox(
|
|
||||||
width: 40,
|
|
||||||
height: 40,
|
|
||||||
child: DecoratedBox(
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
borderRadius: const BorderRadius.all(Radius.circular(4)),
|
|
||||||
color: AppColors.white,
|
|
||||||
image: imageUrl.isNotEmpty
|
|
||||||
? DecorationImage(
|
|
||||||
image: CachedNetworkImageProvider(imageUrl),
|
|
||||||
fit: BoxFit.cover,
|
|
||||||
)
|
|
||||||
: null,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -5,7 +5,6 @@ import 'package:chat/routes/moments_routes.dart';
|
|||||||
import 'package:chat/services/auth_service.dart';
|
import 'package:chat/services/auth_service.dart';
|
||||||
import 'package:chat/widgets/custom_avatar.dart';
|
import 'package:chat/widgets/custom_avatar.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
|
||||||
import 'package:flutter_easyrefresh/easy_refresh.dart';
|
import 'package:flutter_easyrefresh/easy_refresh.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
|
|
||||||
@@ -21,7 +20,7 @@ class MomentHeader extends StatelessWidget {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return SliverAppBar(
|
return SliverAppBar(
|
||||||
systemOverlayStyle: SystemUiOverlayStyle.light,
|
// systemOverlayStyle: SystemUiOverlayStyle.light,
|
||||||
pinned: true,
|
pinned: true,
|
||||||
expandedHeight: 260,
|
expandedHeight: 260,
|
||||||
backgroundColor: AppColors.primary,
|
backgroundColor: AppColors.primary,
|
||||||
@@ -80,8 +79,9 @@ class _HeaderBackground extends StatelessWidget {
|
|||||||
Positioned.fill(
|
Positioned.fill(
|
||||||
bottom: 32,
|
bottom: 32,
|
||||||
child: GestureDetector(
|
child: GestureDetector(
|
||||||
|
onLongPress: () {},
|
||||||
child: Image.asset(
|
child: Image.asset(
|
||||||
'assets/backgrounds/moment_2.jpg',
|
'assets/backgrounds/moment_3.jpg',
|
||||||
fit: BoxFit.cover,
|
fit: BoxFit.cover,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import 'package:chat/controllers/moment_controller.dart';
|
|||||||
import 'package:chat/models/moment/moment_model.dart';
|
import 'package:chat/models/moment/moment_model.dart';
|
||||||
import 'package:chat/views/moments/index/widgets/future_button.dart';
|
import 'package:chat/views/moments/index/widgets/future_button.dart';
|
||||||
import 'package:chat/views/moments/index/widgets/grid_media.dart';
|
import 'package:chat/views/moments/index/widgets/grid_media.dart';
|
||||||
import 'package:chat/views/moments/index/widgets/moment_avatar.dart';
|
import 'package:chat/widgets/custom_avatar.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
|
|
||||||
@@ -46,7 +46,7 @@ class MomentListItem extends StatelessWidget {
|
|||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
MomentAvatar(imageUrl: item.user?.avatar),
|
CustomAvatar(item.user?.avatar),
|
||||||
const SizedBox(width: 10),
|
const SizedBox(width: 10),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Column(
|
child: Column(
|
||||||
|
|||||||
48
lib/views/public/result_page.dart
Normal file
48
lib/views/public/result_page.dart
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
import 'package:chat/configs/app_colors.dart';
|
||||||
|
import 'package:chat/utils/ui_tools.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
|
import 'package:get/get.dart';
|
||||||
|
|
||||||
|
class ScanResultPage extends StatelessWidget {
|
||||||
|
const ScanResultPage({Key? key}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
String content = Get.arguments;
|
||||||
|
return Scaffold(
|
||||||
|
backgroundColor: AppColors.white,
|
||||||
|
appBar: AppBar(
|
||||||
|
title: const Text('扫码结果'),
|
||||||
|
actions: [
|
||||||
|
TextButton(
|
||||||
|
onPressed: () {
|
||||||
|
Clipboard.setData(
|
||||||
|
ClipboardData(
|
||||||
|
text: content,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
UiTools.toast('复制成功');
|
||||||
|
},
|
||||||
|
child: const Text('复制结果'),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
body: ListView(
|
||||||
|
padding: const EdgeInsets.symmetric(
|
||||||
|
horizontal: 16,
|
||||||
|
vertical: 8,
|
||||||
|
),
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
content,
|
||||||
|
style: const TextStyle(
|
||||||
|
height: 1.5,
|
||||||
|
fontSize: 16,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
144
lib/views/public/scan/index_page.dart
Normal file
144
lib/views/public/scan/index_page.dart
Normal file
@@ -0,0 +1,144 @@
|
|||||||
|
import 'package:chat/configs/app_colors.dart';
|
||||||
|
import 'package:chat/routes/app_routes.dart';
|
||||||
|
import 'package:chat/routes/user_routes.dart';
|
||||||
|
import 'package:chat/utils/ui_tools.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:get/get.dart';
|
||||||
|
import 'package:scan/scan.dart';
|
||||||
|
import 'package:wechat_assets_picker/wechat_assets_picker.dart';
|
||||||
|
|
||||||
|
class ScanPage extends StatefulWidget {
|
||||||
|
const ScanPage({Key? key}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
_ScanPageState createState() => _ScanPageState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _ScanPageState extends State<ScanPage> {
|
||||||
|
final ScanController _scanController = ScanController();
|
||||||
|
|
||||||
|
bool flashState = false;
|
||||||
|
|
||||||
|
/// 统一处理扫码结果,可能是扫码的,也可能是相册的
|
||||||
|
void parseScanResult(String str) {
|
||||||
|
List<String> split = str.split('|');
|
||||||
|
|
||||||
|
switch (split.first) {
|
||||||
|
case 'TRANSFER':
|
||||||
|
break;
|
||||||
|
case 'BEFRIEND':
|
||||||
|
break;
|
||||||
|
case 'JOINGROUP':
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
Get.offNamed(
|
||||||
|
AppRoutes.scanResult,
|
||||||
|
arguments: str,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Stack(
|
||||||
|
children: [
|
||||||
|
ScanView(
|
||||||
|
controller: _scanController,
|
||||||
|
scanAreaScale: 0.7,
|
||||||
|
scanLineColor: AppColors.primary,
|
||||||
|
onCapture: (String data) {
|
||||||
|
parseScanResult(data);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
AppBar(
|
||||||
|
backgroundColor: AppColors.transparent,
|
||||||
|
foregroundColor: AppColors.white,
|
||||||
|
),
|
||||||
|
Positioned(
|
||||||
|
left: 16,
|
||||||
|
right: 16,
|
||||||
|
bottom: 32,
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||||
|
children: [
|
||||||
|
_actionItem(
|
||||||
|
'我的',
|
||||||
|
Icons.qr_code,
|
||||||
|
() {
|
||||||
|
Get.toNamed(UserRoutes.qrCode);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
_actionItem(
|
||||||
|
'手电筒',
|
||||||
|
flashState ? Icons.flash_on : Icons.flash_off,
|
||||||
|
() {
|
||||||
|
setState(() {
|
||||||
|
_scanController.toggleTorchMode();
|
||||||
|
flashState = !flashState;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
),
|
||||||
|
_actionItem(
|
||||||
|
'相册',
|
||||||
|
Icons.image,
|
||||||
|
() async {
|
||||||
|
final result = await AssetPicker.pickAssets(
|
||||||
|
Get.context!,
|
||||||
|
pickerConfig: const AssetPickerConfig(
|
||||||
|
maxAssets: 1,
|
||||||
|
requestType: RequestType.image,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (result == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var text = await Scan.parse((await result.first.file)!.path);
|
||||||
|
|
||||||
|
if (text == null) {
|
||||||
|
UiTools.toast('二维码识别失败');
|
||||||
|
}
|
||||||
|
|
||||||
|
parseScanResult(text!);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _actionItem(String text, IconData icon, VoidCallback onTap) {
|
||||||
|
return InkWell(
|
||||||
|
onTap: () {
|
||||||
|
onTap.call();
|
||||||
|
},
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
padding: const EdgeInsets.all(8),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: AppColors.white.withOpacity(0.4),
|
||||||
|
borderRadius: BorderRadius.circular(32),
|
||||||
|
),
|
||||||
|
child: Icon(
|
||||||
|
icon,
|
||||||
|
color: AppColors.white,
|
||||||
|
size: 24,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 4),
|
||||||
|
Text(
|
||||||
|
text,
|
||||||
|
style: const TextStyle(
|
||||||
|
color: AppColors.white,
|
||||||
|
fontSize: 12,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
|
|
||||||
class ScanPage extends StatefulWidget {
|
|
||||||
const ScanPage({Key? key}) : super(key: key);
|
|
||||||
|
|
||||||
@override
|
|
||||||
_ScanPageState createState() => _ScanPageState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _ScanPageState extends State<ScanPage> {
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Container();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,72 +1,43 @@
|
|||||||
import 'package:chat/configs/app_colors.dart';
|
|
||||||
import 'package:chat/routes/user_routes.dart';
|
import 'package:chat/routes/user_routes.dart';
|
||||||
import 'package:chat/views/home/widgets/action_item.dart';
|
import 'package:chat/views/home/widgets/action_item.dart';
|
||||||
import 'package:chat/views/user/index/widgets/user_top_bar.dart';
|
import 'package:chat/views/user/index/widgets/user_top_bar.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
|
|
||||||
class UserPage extends StatefulWidget {
|
class UserPage extends StatelessWidget {
|
||||||
const UserPage({Key? key}) : super(key: key);
|
const UserPage({Key? key}) : super(key: key);
|
||||||
|
|
||||||
@override
|
|
||||||
_UserPageState createState() => _UserPageState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _UserPageState extends State<UserPage> {
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return SafeArea(
|
return Scaffold(
|
||||||
child: Scaffold(
|
body: Column(
|
||||||
body: Column(
|
children: [
|
||||||
children: [
|
const UserTopBar(),
|
||||||
const UserTopBar(),
|
const SizedBox(height: 8),
|
||||||
const Divider(
|
ActionItem(
|
||||||
height: 0,
|
'服务',
|
||||||
color: AppColors.border,
|
isFirst: true,
|
||||||
),
|
isLast: true,
|
||||||
const SizedBox(height: 8),
|
onTap: () {
|
||||||
const Divider(
|
Get.toNamed(UserRoutes.serve);
|
||||||
height: 0,
|
},
|
||||||
color: AppColors.border,
|
),
|
||||||
),
|
const SizedBox(height: 8),
|
||||||
ActionItem(
|
ActionItem(
|
||||||
'服务',
|
'分享邀请',
|
||||||
onTap: () {
|
isFirst: true,
|
||||||
Get.toNamed(UserRoutes.serve);
|
onTap: () {
|
||||||
},
|
Get.toNamed(UserRoutes.share);
|
||||||
),
|
},
|
||||||
const Divider(
|
),
|
||||||
height: 0,
|
ActionItem(
|
||||||
color: AppColors.border,
|
'设置',
|
||||||
),
|
isLast: true,
|
||||||
const SizedBox(height: 8),
|
onTap: () {
|
||||||
const Divider(
|
Get.toNamed(UserRoutes.setting);
|
||||||
height: 0,
|
},
|
||||||
color: AppColors.border,
|
),
|
||||||
),
|
],
|
||||||
ActionItem(
|
|
||||||
'分享邀请',
|
|
||||||
onTap: () {
|
|
||||||
Get.toNamed(UserRoutes.share);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
const Divider(
|
|
||||||
height: 0,
|
|
||||||
color: AppColors.border,
|
|
||||||
indent: 16,
|
|
||||||
),
|
|
||||||
ActionItem(
|
|
||||||
'设置',
|
|
||||||
onTap: () {
|
|
||||||
Get.toNamed(UserRoutes.setting);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
const Divider(
|
|
||||||
height: 0,
|
|
||||||
color: AppColors.border,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,99 +11,113 @@ import 'package:get/get.dart';
|
|||||||
class UserTopBar extends StatelessWidget {
|
class UserTopBar extends StatelessWidget {
|
||||||
const UserTopBar({Key? key}) : super(key: key);
|
const UserTopBar({Key? key}) : super(key: key);
|
||||||
|
|
||||||
|
final double paddingTop = 96;
|
||||||
|
final double paddingBottom = 24;
|
||||||
|
final double avatarHeight = 64;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Container(
|
return Column(
|
||||||
color: AppColors.white,
|
children: [
|
||||||
padding: const EdgeInsets.only(
|
Container(
|
||||||
left: 24,
|
color: AppColors.white,
|
||||||
top: 48,
|
padding: EdgeInsets.only(
|
||||||
right: 24,
|
left: 24,
|
||||||
bottom: 24,
|
top: paddingTop,
|
||||||
),
|
right: 24,
|
||||||
height: 64 + 48 + 24,
|
bottom: paddingBottom,
|
||||||
child: GetX<AuthService>(builder: (_) {
|
),
|
||||||
return Row(
|
height: avatarHeight + paddingTop + paddingBottom,
|
||||||
crossAxisAlignment: CrossAxisAlignment.end,
|
child: GetX<AuthService>(
|
||||||
children: [
|
builder: (_) {
|
||||||
InkWell(
|
return Row(
|
||||||
onTap: () {
|
crossAxisAlignment: CrossAxisAlignment.end,
|
||||||
Get.toNamed(UserRoutes.info);
|
children: [
|
||||||
},
|
InkWell(
|
||||||
child: CustomAvatar(
|
onTap: () {
|
||||||
_.userInfo.value.avatar,
|
Get.toNamed(UserRoutes.info);
|
||||||
size: 64,
|
},
|
||||||
),
|
child: CustomAvatar(
|
||||||
),
|
_.userInfo.value.avatar,
|
||||||
const SizedBox(width: 16),
|
size: avatarHeight,
|
||||||
Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
||||||
children: [
|
|
||||||
InkWell(
|
|
||||||
onTap: () {
|
|
||||||
Get.toNamed(UserRoutes.info);
|
|
||||||
},
|
|
||||||
child: Text(
|
|
||||||
_.userInfo.value.nickname ?? '',
|
|
||||||
style: const TextStyle(
|
|
||||||
fontSize: 22,
|
|
||||||
fontWeight: FontWeight.w400,
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
const SizedBox(width: 16),
|
||||||
Row(
|
Column(
|
||||||
children: [
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
Text(
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
Convert.hideCenterStr(_.userInfo.value.address ?? ''),
|
children: [
|
||||||
style: const TextStyle(
|
InkWell(
|
||||||
color: AppColors.unactive,
|
onTap: () {
|
||||||
),
|
Get.toNamed(UserRoutes.info);
|
||||||
),
|
},
|
||||||
const SizedBox(width: 4),
|
child: Text(
|
||||||
InkWell(
|
_.userInfo.value.nickname ?? '',
|
||||||
onTap: () {
|
style: const TextStyle(
|
||||||
Clipboard.setData(
|
fontSize: 22,
|
||||||
ClipboardData(
|
fontWeight: FontWeight.w400,
|
||||||
text: _.userInfo.value.address,
|
|
||||||
),
|
),
|
||||||
);
|
),
|
||||||
UiTools.toast('地址复制成功');
|
|
||||||
},
|
|
||||||
child: const Icon(
|
|
||||||
Icons.copy,
|
|
||||||
size: 12,
|
|
||||||
color: AppColors.unactive,
|
|
||||||
),
|
),
|
||||||
),
|
Row(
|
||||||
],
|
children: [
|
||||||
),
|
Text(
|
||||||
],
|
Convert.hideCenterStr(_.userInfo.value.username),
|
||||||
),
|
style: const TextStyle(
|
||||||
Expanded(child: Container()),
|
color: AppColors.unactive,
|
||||||
InkWell(
|
),
|
||||||
onTap: () {
|
),
|
||||||
Get.toNamed(UserRoutes.qrCode);
|
const SizedBox(width: 4),
|
||||||
},
|
InkWell(
|
||||||
child: Row(
|
onTap: () {
|
||||||
children: const [
|
Clipboard.setData(
|
||||||
Icon(
|
ClipboardData(
|
||||||
Icons.qr_code,
|
text: _.userInfo.value.username,
|
||||||
size: 18,
|
),
|
||||||
color: AppColors.unactive,
|
);
|
||||||
|
UiTools.toast('地址复制成功');
|
||||||
|
},
|
||||||
|
child: const Icon(
|
||||||
|
Icons.copy,
|
||||||
|
size: 12,
|
||||||
|
color: AppColors.unactive,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
SizedBox(width: 8),
|
Expanded(child: Container()),
|
||||||
Icon(
|
InkWell(
|
||||||
Icons.arrow_forward_ios,
|
onTap: () {
|
||||||
size: 16,
|
Get.toNamed(UserRoutes.qrCode);
|
||||||
color: AppColors.unactive,
|
},
|
||||||
|
child: Row(
|
||||||
|
children: const [
|
||||||
|
Icon(
|
||||||
|
Icons.qr_code,
|
||||||
|
size: 18,
|
||||||
|
color: AppColors.unactive,
|
||||||
|
),
|
||||||
|
SizedBox(width: 8),
|
||||||
|
Icon(
|
||||||
|
Icons.arrow_forward_ios,
|
||||||
|
size: 16,
|
||||||
|
color: AppColors.unactive,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
);
|
||||||
),
|
},
|
||||||
],
|
),
|
||||||
);
|
),
|
||||||
}),
|
const Divider(
|
||||||
|
height: 0,
|
||||||
|
color: AppColors.border,
|
||||||
|
),
|
||||||
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
127
lib/views/user/info/avatar_page.dart
Normal file
127
lib/views/user/info/avatar_page.dart
Normal file
@@ -0,0 +1,127 @@
|
|||||||
|
import 'package:chat/configs/app_colors.dart';
|
||||||
|
import 'package:chat/controllers/user_controller.dart';
|
||||||
|
import 'package:chat/services/auth_service.dart';
|
||||||
|
import 'package:chat/views/home/widgets/pop_menu_item.dart';
|
||||||
|
import 'package:chat/widgets/custom_avatar.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
|
import 'package:get/get.dart';
|
||||||
|
import 'package:image_cropper/image_cropper.dart';
|
||||||
|
import 'package:wechat_assets_picker/wechat_assets_picker.dart';
|
||||||
|
|
||||||
|
class UserInfoAvatarPage extends StatelessWidget {
|
||||||
|
const UserInfoAvatarPage({Key? key}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
backgroundColor: AppColors.black,
|
||||||
|
appBar: AppBar(
|
||||||
|
title: const Text(
|
||||||
|
'头像',
|
||||||
|
style: TextStyle(
|
||||||
|
color: AppColors.white,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
backgroundColor: AppColors.transparent,
|
||||||
|
foregroundColor: AppColors.white,
|
||||||
|
systemOverlayStyle: SystemUiOverlayStyle.light,
|
||||||
|
actions: [
|
||||||
|
IconButton(
|
||||||
|
onPressed: _showMenu,
|
||||||
|
icon: const Icon(Icons.more_horiz),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
body: Center(
|
||||||
|
child: GetX<AuthService>(
|
||||||
|
builder: (_) {
|
||||||
|
return CustomAvatar(
|
||||||
|
_.userInfo.value.avatar,
|
||||||
|
size: Get.width,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _showMenu() async {
|
||||||
|
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: _pickImage,
|
||||||
|
),
|
||||||
|
const Divider(height: 0),
|
||||||
|
Container(
|
||||||
|
color: AppColors.page,
|
||||||
|
height: 8,
|
||||||
|
),
|
||||||
|
const Divider(height: 0),
|
||||||
|
PopMenuItem(
|
||||||
|
'取消',
|
||||||
|
onTap: () {
|
||||||
|
Get.back();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future _pickImage() async {
|
||||||
|
Get.back();
|
||||||
|
final result = await AssetPicker.pickAssets(
|
||||||
|
Get.context!,
|
||||||
|
pickerConfig: const AssetPickerConfig(
|
||||||
|
maxAssets: 1,
|
||||||
|
textDelegate: AssetPickerTextDelegate(),
|
||||||
|
requestType: RequestType.image,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (result == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_cropImage((await result.first.file)!.path);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _cropImage(String imagePath) async {
|
||||||
|
CroppedFile? croppedFile = await ImageCropper().cropImage(
|
||||||
|
sourcePath: imagePath,
|
||||||
|
maxHeight: 512,
|
||||||
|
maxWidth: 512,
|
||||||
|
compressQuality: 90,
|
||||||
|
aspectRatio: const CropAspectRatio(
|
||||||
|
ratioX: 1,
|
||||||
|
ratioY: 1,
|
||||||
|
),
|
||||||
|
compressFormat: ImageCompressFormat.jpg,
|
||||||
|
uiSettings: [
|
||||||
|
IOSUiSettings(
|
||||||
|
title: '头像剪裁',
|
||||||
|
doneButtonTitle: '完成',
|
||||||
|
cancelButtonTitle: '取消',
|
||||||
|
),
|
||||||
|
AndroidUiSettings(
|
||||||
|
toolbarTitle: '头像剪裁',
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
if (croppedFile != null) {
|
||||||
|
UserController.to.uploadAvatar(croppedFile.path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,12 +1,9 @@
|
|||||||
import 'package:chat/controllers/user_controller.dart';
|
|
||||||
import 'package:chat/routes/user_routes.dart';
|
import 'package:chat/routes/user_routes.dart';
|
||||||
import 'package:chat/services/auth_service.dart';
|
import 'package:chat/services/auth_service.dart';
|
||||||
import 'package:chat/views/user/widgets/link_action_item.dart';
|
import 'package:chat/views/user/widgets/link_action_item.dart';
|
||||||
import 'package:chat/widgets/custom_avatar.dart';
|
import 'package:chat/widgets/custom_avatar.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:image_cropper/image_cropper.dart';
|
|
||||||
import 'package:wechat_assets_picker/wechat_assets_picker.dart';
|
|
||||||
|
|
||||||
class UserInfoPage extends StatefulWidget {
|
class UserInfoPage extends StatefulWidget {
|
||||||
const UserInfoPage({Key? key}) : super(key: key);
|
const UserInfoPage({Key? key}) : super(key: key);
|
||||||
@@ -24,79 +21,36 @@ class _UserInfoPageState extends State<UserInfoPage> {
|
|||||||
),
|
),
|
||||||
body: GetX<AuthService>(
|
body: GetX<AuthService>(
|
||||||
builder: (_) {
|
builder: (_) {
|
||||||
return SafeArea(
|
return Column(
|
||||||
child: Column(
|
children: [
|
||||||
children: [
|
LinkActionItem(
|
||||||
LinkActionItem(
|
title: '头像',
|
||||||
title: '头像',
|
onTap: () async {
|
||||||
onTap: () async {
|
Get.toNamed(UserRoutes.infoAvatar);
|
||||||
final result = await AssetPicker.pickAssets(
|
},
|
||||||
Get.context!,
|
isLink: true,
|
||||||
pickerConfig: const AssetPickerConfig(
|
trailing: CustomAvatar(
|
||||||
maxAssets: 1,
|
_.userInfo.value.avatar,
|
||||||
textDelegate: AssetPickerTextDelegate(),
|
size: 52,
|
||||||
requestType: RequestType.image,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
if (result == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
_cropImage((await result.first.file)!.path);
|
|
||||||
},
|
|
||||||
isLink: true,
|
|
||||||
trailing: CustomAvatar(
|
|
||||||
_.userInfo.value.avatar,
|
|
||||||
size: 52,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
LinkActionItem(
|
),
|
||||||
title: '昵称',
|
LinkActionItem(
|
||||||
trailing: Text(_.userInfo.value.nickname!),
|
title: '昵称',
|
||||||
isLink: true,
|
trailing: Text(_.userInfo.value.nickname!),
|
||||||
onTap: () {
|
isLink: true,
|
||||||
Get.toNamed(
|
onTap: () {
|
||||||
UserRoutes.infoNickname,
|
Get.toNamed(
|
||||||
arguments: {
|
UserRoutes.infoNickname,
|
||||||
'nickname': _.userInfo.value.nickname,
|
arguments: {
|
||||||
},
|
'nickname': _.userInfo.value.nickname,
|
||||||
);
|
},
|
||||||
},
|
);
|
||||||
),
|
},
|
||||||
Expanded(child: Container()),
|
),
|
||||||
],
|
],
|
||||||
),
|
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _cropImage(String imagePath) async {
|
|
||||||
CroppedFile? croppedFile = await ImageCropper().cropImage(
|
|
||||||
sourcePath: imagePath,
|
|
||||||
maxHeight: 128,
|
|
||||||
maxWidth: 128,
|
|
||||||
compressQuality: 100,
|
|
||||||
aspectRatio: const CropAspectRatio(
|
|
||||||
ratioX: 1,
|
|
||||||
ratioY: 1,
|
|
||||||
),
|
|
||||||
compressFormat: ImageCompressFormat.jpg,
|
|
||||||
uiSettings: [
|
|
||||||
IOSUiSettings(
|
|
||||||
title: '头像剪裁',
|
|
||||||
doneButtonTitle: '完成',
|
|
||||||
cancelButtonTitle: '取消',
|
|
||||||
),
|
|
||||||
AndroidUiSettings(
|
|
||||||
toolbarTitle: '头像剪裁',
|
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
if (croppedFile != null) {
|
|
||||||
UserController.to.uploadAvatar(croppedFile.path);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import 'package:chat/configs/app_colors.dart';
|
import 'package:chat/configs/app_colors.dart';
|
||||||
|
import 'package:chat/services/auth_service.dart';
|
||||||
import 'package:chat/views/home/widgets/pop_menu_item.dart';
|
import 'package:chat/views/home/widgets/pop_menu_item.dart';
|
||||||
import 'package:chat/views/public/scan_page.dart';
|
import 'package:chat/views/public/scan/index_page.dart';
|
||||||
import 'package:chat/widgets/custom_avatar.dart';
|
import 'package:chat/widgets/custom_avatar.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
@@ -43,34 +44,28 @@ class _UserQrCodePageState extends State<UserQrCodePage> {
|
|||||||
Row(
|
Row(
|
||||||
children: [
|
children: [
|
||||||
CustomAvatar(
|
CustomAvatar(
|
||||||
'',
|
AuthService.to.userInfo.value.avatar,
|
||||||
size: 64,
|
size: 64,
|
||||||
radius: 6,
|
radius: 6,
|
||||||
),
|
),
|
||||||
const SizedBox(width: 8),
|
const SizedBox(width: 16),
|
||||||
Column(
|
Text(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
AuthService.to.userInfo.value.nickname ?? '',
|
||||||
children: const [
|
style: const TextStyle(
|
||||||
Text(
|
fontSize: 24,
|
||||||
'Jason',
|
),
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 20,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
SizedBox(height: 8),
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
const SizedBox(height: 32),
|
const SizedBox(height: 32),
|
||||||
QrImage(
|
QrImage(
|
||||||
data: 'BEFRIEND|5',
|
data: 'BEFRIEND|${AuthService.to.userInfo.value.username}',
|
||||||
version: 3,
|
version: 3,
|
||||||
size: Get.width * 0.8,
|
size: Get.width * 0.8,
|
||||||
),
|
),
|
||||||
const SizedBox(height: 32),
|
const SizedBox(height: 32),
|
||||||
const Text(
|
const Text(
|
||||||
'扫一扫上面的二维码,加我共力好友',
|
'扫一扫上面的二维码,加我ZH-CHAT好友',
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: AppColors.unactive,
|
color: AppColors.unactive,
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -1,20 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
|
|
||||||
class UserSafePage extends StatefulWidget {
|
|
||||||
const UserSafePage({Key? key}) : super(key: key);
|
|
||||||
|
|
||||||
@override
|
|
||||||
State<UserSafePage> createState() => _UserSafePageState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _UserSafePageState extends State<UserSafePage> {
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Scaffold(
|
|
||||||
appBar: AppBar(
|
|
||||||
title: const Text('安全设置'),
|
|
||||||
),
|
|
||||||
body: Container(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
60
lib/views/user/serve/google/index_page.dart
Normal file
60
lib/views/user/serve/google/index_page.dart
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:otp/otp.dart';
|
||||||
|
|
||||||
|
class UserServeGooglePage extends StatefulWidget {
|
||||||
|
const UserServeGooglePage({Key? key}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<UserServeGooglePage> createState() => _UserServeGooglePageState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _UserServeGooglePageState extends State<UserServeGooglePage> {
|
||||||
|
String code = '000000';
|
||||||
|
String secret = 'T4UM3VPYXPALF7M5';
|
||||||
|
int remaining = 0;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
getCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
void getCode() {
|
||||||
|
setState(() {
|
||||||
|
remaining = OTP.remainingSeconds();
|
||||||
|
|
||||||
|
code = OTP.generateTOTPCodeString(
|
||||||
|
secret,
|
||||||
|
DateTime.now().millisecondsSinceEpoch,
|
||||||
|
algorithm: Algorithm.SHA1,
|
||||||
|
isGoogle: true,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
title: const Text('谷歌验证器'),
|
||||||
|
),
|
||||||
|
body: Column(
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
code,
|
||||||
|
style: const TextStyle(
|
||||||
|
fontSize: 32,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Text(remaining.toString()),
|
||||||
|
ElevatedButton(
|
||||||
|
onPressed: () {
|
||||||
|
getCode();
|
||||||
|
},
|
||||||
|
child: const Text('刷新密码'),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,7 @@
|
|||||||
|
import 'package:chat/routes/app_routes.dart';
|
||||||
|
import 'package:chat/views/home/widgets/action_item.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:get/get.dart';
|
||||||
|
|
||||||
class UserServePage extends StatefulWidget {
|
class UserServePage extends StatefulWidget {
|
||||||
const UserServePage({Key? key}) : super(key: key);
|
const UserServePage({Key? key}) : super(key: key);
|
||||||
@@ -14,7 +17,25 @@ class _UserServePageState extends State<UserServePage> {
|
|||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: const Text('服务'),
|
title: const Text('服务'),
|
||||||
),
|
),
|
||||||
body: Container(),
|
body: Column(
|
||||||
|
children: [
|
||||||
|
// ActionItem(
|
||||||
|
// '谷歌验证器',
|
||||||
|
// isFirst: true,
|
||||||
|
// onTap: () {
|
||||||
|
// Get.toNamed(UserRoutes.serveGoogle);
|
||||||
|
// },
|
||||||
|
// ),
|
||||||
|
ActionItem(
|
||||||
|
'扫一扫',
|
||||||
|
isFirst: true,
|
||||||
|
isLast: true,
|
||||||
|
onTap: () {
|
||||||
|
Get.toNamed(AppRoutes.scan);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
20
lib/views/user/setting/about/index_page.dart
Normal file
20
lib/views/user/setting/about/index_page.dart
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class UserSettingAboutPage extends StatefulWidget {
|
||||||
|
const UserSettingAboutPage({Key? key}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
_UserSettingAboutPageState createState() => _UserSettingAboutPageState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _UserSettingAboutPageState extends State<UserSettingAboutPage> {
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
title: const Text('关于ZH-CHAT'),
|
||||||
|
),
|
||||||
|
body: Container(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,10 +1,13 @@
|
|||||||
|
import 'package:adaptive_dialog/adaptive_dialog.dart';
|
||||||
import 'package:chat/configs/app_colors.dart';
|
import 'package:chat/configs/app_colors.dart';
|
||||||
|
import 'package:chat/providers/public_provider.dart';
|
||||||
import 'package:chat/routes/user_routes.dart';
|
import 'package:chat/routes/user_routes.dart';
|
||||||
import 'package:chat/services/auth_service.dart';
|
import 'package:chat/services/auth_service.dart';
|
||||||
import 'package:chat/views/home/widgets/action_button.dart';
|
import 'package:chat/views/home/widgets/action_button.dart';
|
||||||
import 'package:chat/views/home/widgets/action_item.dart';
|
import 'package:chat/views/home/widgets/action_item.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
|
import 'package:package_info_plus/package_info_plus.dart';
|
||||||
|
|
||||||
class UserSettingPage extends StatefulWidget {
|
class UserSettingPage extends StatefulWidget {
|
||||||
const UserSettingPage({Key? key}) : super(key: key);
|
const UserSettingPage({Key? key}) : super(key: key);
|
||||||
@@ -14,6 +17,18 @@ class UserSettingPage extends StatefulWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class _UserSettingPageState extends State<UserSettingPage> {
|
class _UserSettingPageState extends State<UserSettingPage> {
|
||||||
|
PackageInfo? packageInfo;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
PackageInfo.fromPlatform().then((value) {
|
||||||
|
setState(() {
|
||||||
|
packageInfo = value;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
@@ -24,89 +39,72 @@ class _UserSettingPageState extends State<UserSettingPage> {
|
|||||||
children: [
|
children: [
|
||||||
ActionItem(
|
ActionItem(
|
||||||
'账号与安全',
|
'账号与安全',
|
||||||
|
isFirst: true,
|
||||||
|
isLast: true,
|
||||||
onTap: () {
|
onTap: () {
|
||||||
Get.toNamed(UserRoutes.safe);
|
Get.toNamed(UserRoutes.settingSafe);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
const Divider(
|
|
||||||
height: 0,
|
|
||||||
color: AppColors.border,
|
|
||||||
),
|
|
||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
const Divider(
|
|
||||||
height: 0,
|
|
||||||
color: AppColors.border,
|
|
||||||
),
|
|
||||||
ActionItem(
|
ActionItem(
|
||||||
'新消息通知',
|
'新消息通知',
|
||||||
|
isFirst: true,
|
||||||
onTap: () {
|
onTap: () {
|
||||||
Get.toNamed(UserRoutes.safe);
|
Get.toNamed(UserRoutes.settingMessage);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
const Divider(
|
|
||||||
height: 0,
|
|
||||||
color: AppColors.border,
|
|
||||||
indent: 16,
|
|
||||||
),
|
|
||||||
ActionItem(
|
ActionItem(
|
||||||
'隐私权限',
|
'隐私权限',
|
||||||
|
isLast: true,
|
||||||
onTap: () {
|
onTap: () {
|
||||||
Get.toNamed(UserRoutes.safe);
|
Get.toNamed(UserRoutes.settingPrivacy);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
const Divider(
|
|
||||||
height: 0,
|
|
||||||
color: AppColors.border,
|
|
||||||
),
|
|
||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
ActionItem(
|
ActionItem(
|
||||||
'关于ZH-CHAT',
|
'关于ZH-CHAT',
|
||||||
|
isFirst: true,
|
||||||
onTap: () {
|
onTap: () {
|
||||||
Get.toNamed(UserRoutes.safe);
|
Get.toNamed(UserRoutes.settingAbout);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
const Divider(
|
|
||||||
height: 0,
|
|
||||||
color: AppColors.border,
|
|
||||||
indent: 16,
|
|
||||||
),
|
|
||||||
ActionItem(
|
ActionItem(
|
||||||
'帮助与反馈',
|
'帮助与反馈',
|
||||||
onTap: () {
|
onTap: () {
|
||||||
Get.toNamed(UserRoutes.safe);
|
Get.toNamed(UserRoutes.settingSugguest);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
const Divider(
|
|
||||||
height: 0,
|
|
||||||
color: AppColors.border,
|
|
||||||
),
|
|
||||||
ActionItem(
|
ActionItem(
|
||||||
'版本更新',
|
'版本更新',
|
||||||
onTap: () {
|
extend: packageInfo?.version,
|
||||||
Get.toNamed(UserRoutes.safe);
|
isFirst: true,
|
||||||
|
isLast: true,
|
||||||
|
onTap: () async {
|
||||||
|
PublicProvider.checkUpgrade(packageInfo);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
const Divider(
|
|
||||||
height: 0,
|
|
||||||
color: AppColors.border,
|
|
||||||
),
|
|
||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
const Divider(
|
|
||||||
height: 0,
|
|
||||||
color: AppColors.border,
|
|
||||||
),
|
|
||||||
ActionButton(
|
ActionButton(
|
||||||
'退出',
|
'退出',
|
||||||
color: AppColors.primary,
|
hasTop: true,
|
||||||
|
hasBottom: true,
|
||||||
|
color: AppColors.red,
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
AuthService.to.logout();
|
OkCancelResult result = await showOkCancelAlertDialog(
|
||||||
|
style: AdaptiveStyle.iOS,
|
||||||
|
context: context,
|
||||||
|
title: '退出登录',
|
||||||
|
message: '确认您已备份助记词并保存好了么?退出登录后助记词将无法导出。',
|
||||||
|
okLabel: '确定',
|
||||||
|
cancelLabel: '取消',
|
||||||
|
defaultType: OkCancelAlertDefaultType.cancel,
|
||||||
|
);
|
||||||
|
if (result == OkCancelResult.ok) {
|
||||||
|
AuthService.to.logout();
|
||||||
|
}
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
const Divider(
|
|
||||||
height: 0,
|
|
||||||
color: AppColors.border,
|
|
||||||
),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
20
lib/views/user/setting/message/index_page.dart
Normal file
20
lib/views/user/setting/message/index_page.dart
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class UserSettingMessagePage extends StatefulWidget {
|
||||||
|
const UserSettingMessagePage({Key? key}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
_UserSettingMessagePageState createState() => _UserSettingMessagePageState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _UserSettingMessagePageState extends State<UserSettingMessagePage> {
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
title: const Text('新消息与通知'),
|
||||||
|
),
|
||||||
|
body: Container(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
40
lib/views/user/setting/privacy/index_page.dart
Normal file
40
lib/views/user/setting/privacy/index_page.dart
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
import 'package:chat/configs/app_colors.dart';
|
||||||
|
import 'package:chat/services/auth_service.dart';
|
||||||
|
import 'package:chat/views/user/widgets/link_action_item.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:get/get_state_manager/get_state_manager.dart';
|
||||||
|
|
||||||
|
class UserSettingPrivacyPage extends StatelessWidget {
|
||||||
|
const UserSettingPrivacyPage({Key? key}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
title: const Text('隐私权限'),
|
||||||
|
),
|
||||||
|
body: Column(
|
||||||
|
children: [
|
||||||
|
const Divider(
|
||||||
|
height: 0,
|
||||||
|
color: AppColors.border,
|
||||||
|
),
|
||||||
|
GetX<AuthService>(
|
||||||
|
builder: (_) {
|
||||||
|
return LinkActionItem(
|
||||||
|
title: '允许通过搜索添加我为好友',
|
||||||
|
trailing: Switch(
|
||||||
|
value: _.userInfo.value.privacy ?? true,
|
||||||
|
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
|
||||||
|
onChanged: (e) {
|
||||||
|
_.togglePrivacy();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
15
lib/views/user/setting/safe/email_page.dart
Normal file
15
lib/views/user/setting/safe/email_page.dart
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class UserSettingSafeEmailPage extends StatelessWidget {
|
||||||
|
const UserSettingSafeEmailPage({Key? key}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
title: const Text('绑定邮箱'),
|
||||||
|
),
|
||||||
|
body: Container(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
15
lib/views/user/setting/safe/google_page.dart
Normal file
15
lib/views/user/setting/safe/google_page.dart
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class UserSettingSafeGooglePage extends StatelessWidget {
|
||||||
|
const UserSettingSafeGooglePage({Key? key}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
title: const Text('UserSettingSafeGooglePage'),
|
||||||
|
),
|
||||||
|
body: Container(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
110
lib/views/user/setting/safe/index_page.dart
Normal file
110
lib/views/user/setting/safe/index_page.dart
Normal file
@@ -0,0 +1,110 @@
|
|||||||
|
import 'package:chat/configs/app_colors.dart';
|
||||||
|
import 'package:chat/routes/user_routes.dart';
|
||||||
|
import 'package:chat/services/auth_service.dart';
|
||||||
|
import 'package:chat/utils/ui_tools.dart';
|
||||||
|
import 'package:chat/views/home/widgets/action_item.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
|
import 'package:get/get.dart';
|
||||||
|
|
||||||
|
class UserSettingSafePage extends StatefulWidget {
|
||||||
|
const UserSettingSafePage({Key? key}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<UserSettingSafePage> createState() => _UserSettingSafePageState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _UserSettingSafePageState extends State<UserSettingSafePage> {
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
title: const Text('安全设置'),
|
||||||
|
),
|
||||||
|
body: GetX<AuthService>(builder: (_) {
|
||||||
|
return Column(
|
||||||
|
children: [
|
||||||
|
ActionItem(
|
||||||
|
'导出助记词',
|
||||||
|
isFirst: true,
|
||||||
|
isLast: true,
|
||||||
|
onTap: _showMnemonic,
|
||||||
|
),
|
||||||
|
const SizedBox(height: 8),
|
||||||
|
ActionItem(
|
||||||
|
'绑定手机',
|
||||||
|
extend: _.userInfo.value.mobile ?? '未绑定',
|
||||||
|
isFirst: true,
|
||||||
|
onTap: () {
|
||||||
|
Get.toNamed(UserRoutes.settingSafeMobile);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
ActionItem(
|
||||||
|
'绑定邮箱',
|
||||||
|
extend: _.userInfo.value.email ?? '未绑定',
|
||||||
|
isLast: true,
|
||||||
|
onTap: () {
|
||||||
|
Get.toNamed(UserRoutes.settingSafeEmail);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
const SizedBox(height: 8),
|
||||||
|
ActionItem(
|
||||||
|
'开启两步验证',
|
||||||
|
extend: (_.userInfo.value.google2fa ?? false) ? '已开启' : '未开启',
|
||||||
|
isFirst: true,
|
||||||
|
isLast: true,
|
||||||
|
onTap: () {
|
||||||
|
Get.toNamed(UserRoutes.settingSafeGoogle);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _showMnemonic() {
|
||||||
|
showModalBottomSheet(
|
||||||
|
context: context,
|
||||||
|
isScrollControlled: true,
|
||||||
|
backgroundColor: AppColors.white,
|
||||||
|
shape: const RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.vertical(top: Radius.circular(8)),
|
||||||
|
),
|
||||||
|
builder: (context) {
|
||||||
|
return Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
const SizedBox(height: 16),
|
||||||
|
const Text('您的助记词'),
|
||||||
|
Container(
|
||||||
|
padding: const EdgeInsets.all(32),
|
||||||
|
child: Text(
|
||||||
|
AuthService.to.mnemonic,
|
||||||
|
style: const TextStyle(
|
||||||
|
fontSize: 20,
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
wordSpacing: 6,
|
||||||
|
height: 2,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
ElevatedButton(
|
||||||
|
onPressed: () {
|
||||||
|
Clipboard.setData(
|
||||||
|
ClipboardData(
|
||||||
|
text: AuthService.to.mnemonic,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
UiTools.toast('复制成功');
|
||||||
|
Get.back();
|
||||||
|
},
|
||||||
|
child: const Text('复制'),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 16),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
17
lib/views/user/setting/safe/mobile_page.dart
Normal file
17
lib/views/user/setting/safe/mobile_page.dart
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class UserSettingSafeMobilePage extends StatelessWidget {
|
||||||
|
const UserSettingSafeMobilePage({Key? key}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
title: const Text('绑定手机'),
|
||||||
|
),
|
||||||
|
body: Column(
|
||||||
|
children: const [],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
21
lib/views/user/setting/sugguest/index_page.dart
Normal file
21
lib/views/user/setting/sugguest/index_page.dart
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
class UserSettingSugguestPage extends StatefulWidget {
|
||||||
|
const UserSettingSugguestPage({Key? key}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
_UserSettingSugguestPageState createState() =>
|
||||||
|
_UserSettingSugguestPageState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _UserSettingSugguestPageState extends State<UserSettingSugguestPage> {
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
title: const Text('帮助与反馈'),
|
||||||
|
),
|
||||||
|
body: Container(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,8 @@
|
|||||||
|
import 'package:chat/configs/app_colors.dart';
|
||||||
|
import 'package:chat/providers/user_provider.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:get/get.dart';
|
||||||
|
import 'package:qr_flutter/qr_flutter.dart';
|
||||||
|
|
||||||
class UserSharePage extends StatefulWidget {
|
class UserSharePage extends StatefulWidget {
|
||||||
const UserSharePage({Key? key}) : super(key: key);
|
const UserSharePage({Key? key}) : super(key: key);
|
||||||
@@ -14,7 +18,33 @@ class _UserSharePageState extends State<UserSharePage> {
|
|||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: const Text('分享邀请'),
|
title: const Text('分享邀请'),
|
||||||
),
|
),
|
||||||
body: Container(),
|
body: FutureBuilder(
|
||||||
|
future: UserProvider.downloadUrl(),
|
||||||
|
builder: (context, AsyncSnapshot<String?> data) {
|
||||||
|
return data.data != null
|
||||||
|
? Center(
|
||||||
|
child: Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: AppColors.white,
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
),
|
||||||
|
padding: const EdgeInsets.all(16),
|
||||||
|
child: Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
QrImage(
|
||||||
|
data: '${data.data}',
|
||||||
|
size: Get.width * 0.8,
|
||||||
|
),
|
||||||
|
const Text('扫一扫上面的二维码,下载ZH-CHAT'),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
: Container();
|
||||||
|
},
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,7 +35,6 @@ class CustomEasyRefresh {
|
|||||||
double size = 156.0,
|
double size = 156.0,
|
||||||
}) {
|
}) {
|
||||||
return Column(
|
return Column(
|
||||||
mainAxisSize: MainAxisSize.max,
|
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
@@ -43,6 +42,9 @@ class CustomEasyRefresh {
|
|||||||
'assets/images/empty/im_emptyIcon_2.png',
|
'assets/images/empty/im_emptyIcon_2.png',
|
||||||
width: size,
|
width: size,
|
||||||
),
|
),
|
||||||
|
const SizedBox(
|
||||||
|
height: 16,
|
||||||
|
),
|
||||||
Text(
|
Text(
|
||||||
text,
|
text,
|
||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
|
|||||||
91
pubspec.lock
91
pubspec.lock
@@ -28,7 +28,7 @@ packages:
|
|||||||
name: asn1lib
|
name: asn1lib
|
||||||
url: "https://pub.flutter-io.cn"
|
url: "https://pub.flutter-io.cn"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.2.0"
|
version: "1.3.0"
|
||||||
async:
|
async:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -43,6 +43,13 @@ packages:
|
|||||||
url: "https://pub.flutter-io.cn"
|
url: "https://pub.flutter-io.cn"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.0"
|
version: "2.0.0"
|
||||||
|
base32:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: base32
|
||||||
|
url: "https://pub.flutter-io.cn"
|
||||||
|
source: hosted
|
||||||
|
version: "2.1.3"
|
||||||
bip32:
|
bip32:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@@ -121,7 +128,7 @@ packages:
|
|||||||
name: camera_platform_interface
|
name: camera_platform_interface
|
||||||
url: "https://pub.flutter-io.cn"
|
url: "https://pub.flutter-io.cn"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.2.2"
|
version: "2.3.0"
|
||||||
camera_web:
|
camera_web:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -206,13 +213,6 @@ packages:
|
|||||||
url: "https://pub.flutter-io.cn"
|
url: "https://pub.flutter-io.cn"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.1.1"
|
version: "1.1.1"
|
||||||
device_info_plus:
|
|
||||||
dependency: "direct main"
|
|
||||||
description:
|
|
||||||
name: device_info_plus
|
|
||||||
url: "https://pub.flutter-io.cn"
|
|
||||||
source: hosted
|
|
||||||
version: "0.0.1"
|
|
||||||
dio:
|
dio:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@@ -336,7 +336,7 @@ packages:
|
|||||||
name: flutter_plugin_record_plus
|
name: flutter_plugin_record_plus
|
||||||
url: "https://pub.flutter-io.cn"
|
url: "https://pub.flutter-io.cn"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.0.11"
|
version: "0.0.15"
|
||||||
flutter_spinkit:
|
flutter_spinkit:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@@ -437,21 +437,21 @@ packages:
|
|||||||
name: image_cropper
|
name: image_cropper
|
||||||
url: "https://pub.flutter-io.cn"
|
url: "https://pub.flutter-io.cn"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.0.0"
|
version: "3.0.1"
|
||||||
image_cropper_for_web:
|
image_cropper_for_web:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: image_cropper_for_web
|
name: image_cropper_for_web
|
||||||
url: "https://pub.flutter-io.cn"
|
url: "https://pub.flutter-io.cn"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.2"
|
version: "1.0.3"
|
||||||
image_cropper_platform_interface:
|
image_cropper_platform_interface:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: image_cropper_platform_interface
|
name: image_cropper_platform_interface
|
||||||
url: "https://pub.flutter-io.cn"
|
url: "https://pub.flutter-io.cn"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.0.2"
|
version: "3.0.3"
|
||||||
intersperse:
|
intersperse:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -487,6 +487,13 @@ packages:
|
|||||||
url: "https://pub.flutter-io.cn"
|
url: "https://pub.flutter-io.cn"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.1"
|
version: "1.0.1"
|
||||||
|
logging:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: logging
|
||||||
|
url: "https://pub.flutter-io.cn"
|
||||||
|
source: hosted
|
||||||
|
version: "1.1.0"
|
||||||
lpinyin:
|
lpinyin:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@@ -543,13 +550,55 @@ packages:
|
|||||||
url: "https://pub.flutter-io.cn"
|
url: "https://pub.flutter-io.cn"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.2.1"
|
version: "3.2.1"
|
||||||
|
otp:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: otp
|
||||||
|
url: "https://pub.flutter-io.cn"
|
||||||
|
source: hosted
|
||||||
|
version: "3.1.3"
|
||||||
package_info_plus:
|
package_info_plus:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: package_info_plus
|
name: package_info_plus
|
||||||
url: "https://pub.flutter-io.cn"
|
url: "https://pub.flutter-io.cn"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.0.1"
|
version: "1.4.2"
|
||||||
|
package_info_plus_linux:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: package_info_plus_linux
|
||||||
|
url: "https://pub.flutter-io.cn"
|
||||||
|
source: hosted
|
||||||
|
version: "1.0.5"
|
||||||
|
package_info_plus_macos:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: package_info_plus_macos
|
||||||
|
url: "https://pub.flutter-io.cn"
|
||||||
|
source: hosted
|
||||||
|
version: "1.3.0"
|
||||||
|
package_info_plus_platform_interface:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: package_info_plus_platform_interface
|
||||||
|
url: "https://pub.flutter-io.cn"
|
||||||
|
source: hosted
|
||||||
|
version: "1.0.2"
|
||||||
|
package_info_plus_web:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: package_info_plus_web
|
||||||
|
url: "https://pub.flutter-io.cn"
|
||||||
|
source: hosted
|
||||||
|
version: "1.0.6"
|
||||||
|
package_info_plus_windows:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: package_info_plus_windows
|
||||||
|
url: "https://pub.flutter-io.cn"
|
||||||
|
source: hosted
|
||||||
|
version: "1.0.5"
|
||||||
path:
|
path:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -570,7 +619,7 @@ packages:
|
|||||||
name: path_provider_android
|
name: path_provider_android
|
||||||
url: "https://pub.flutter-io.cn"
|
url: "https://pub.flutter-io.cn"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.20"
|
version: "2.0.21"
|
||||||
path_provider_ios:
|
path_provider_ios:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -738,7 +787,7 @@ packages:
|
|||||||
name: rxdart
|
name: rxdart
|
||||||
url: "https://pub.flutter-io.cn"
|
url: "https://pub.flutter-io.cn"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.27.5"
|
version: "0.27.6"
|
||||||
scan:
|
scan:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@@ -792,7 +841,7 @@ packages:
|
|||||||
name: sqflite_common
|
name: sqflite_common
|
||||||
url: "https://pub.flutter-io.cn"
|
url: "https://pub.flutter-io.cn"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.3.0"
|
version: "2.4.0"
|
||||||
stack_trace:
|
stack_trace:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -813,7 +862,7 @@ packages:
|
|||||||
name: stream_transform
|
name: stream_transform
|
||||||
url: "https://pub.flutter-io.cn"
|
url: "https://pub.flutter-io.cn"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.1"
|
version: "2.1.0"
|
||||||
string_scanner:
|
string_scanner:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -834,14 +883,14 @@ packages:
|
|||||||
name: tencent_im_sdk_plugin
|
name: tencent_im_sdk_plugin
|
||||||
url: "https://pub.flutter-io.cn"
|
url: "https://pub.flutter-io.cn"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "4.1.9"
|
version: "4.2.0"
|
||||||
tencent_im_sdk_plugin_platform_interface:
|
tencent_im_sdk_plugin_platform_interface:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: tencent_im_sdk_plugin_platform_interface
|
name: tencent_im_sdk_plugin_platform_interface
|
||||||
url: "https://pub.flutter-io.cn"
|
url: "https://pub.flutter-io.cn"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.3.5"
|
version: "0.3.6"
|
||||||
term_glyph:
|
term_glyph:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -883,7 +932,7 @@ packages:
|
|||||||
name: uuid
|
name: uuid
|
||||||
url: "https://pub.flutter-io.cn"
|
url: "https://pub.flutter-io.cn"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.0.6"
|
version: "3.0.7"
|
||||||
vector_math:
|
vector_math:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|||||||
@@ -16,8 +16,6 @@ dependencies:
|
|||||||
lpinyin: ^2.0.3
|
lpinyin: ^2.0.3
|
||||||
vibration: ^1.7.6
|
vibration: ^1.7.6
|
||||||
scan: ^1.6.0
|
scan: ^1.6.0
|
||||||
package_info_plus: ^0.0.1
|
|
||||||
device_info_plus: ^0.0.1
|
|
||||||
flutter_easyrefresh: ^2.2.2
|
flutter_easyrefresh: ^2.2.2
|
||||||
cached_network_image: ^3.2.0
|
cached_network_image: ^3.2.0
|
||||||
flutter_spinkit: ^5.1.0
|
flutter_spinkit: ^5.1.0
|
||||||
@@ -52,6 +50,9 @@ dependencies:
|
|||||||
wechat_camera_picker: ^3.5.0+1
|
wechat_camera_picker: ^3.5.0+1
|
||||||
filesize: ^2.0.1
|
filesize: ^2.0.1
|
||||||
file_picker: ^4.6.1
|
file_picker: ^4.6.1
|
||||||
|
otp: ^3.1.1
|
||||||
|
package_info_plus: ^1.4.2
|
||||||
|
package_info_plus_web: ^1.0.6
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
|
|||||||
Reference in New Issue
Block a user