Merge branch 'feature' of gitea.haiyihy.com:hy/chatapp3-flutter into feature

# Conflicts:
#	android/app/src/main/kotlin/com/org/yumiparty/GiftMp4VideoPlatformView.kt
#	ios/Runner.xcodeproj/project.pbxproj
#	pubspec.lock
#	pubspec.yaml
This commit is contained in:
zhx 2026-07-04 01:44:30 +08:00
commit 247e58e4b8
41 changed files with 1787 additions and 1216 deletions

View File

@ -1,5 +1,5 @@
# Uncomment this line to define a global platform for your project
# platform :ios, '13.0'
platform :ios, '13.0'
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
@ -64,7 +64,7 @@ post_install do |installer|
## 6. 禁用 Siri/助手 (NSSiriUsageDescription)
'PERMISSION_ASSISTANT=0',
## 7. 用 媒体库 (NSAppleMusicUsageDescription)
## 7. 用 媒体库 (NSAppleMusicUsageDescription)
'PERMISSION_MEDIA_LIBRARY=1',
## 8. 禁用 蓝牙 (如果你没用到蓝牙,建议也关掉)

View File

@ -11,11 +11,47 @@ PODS:
- GoogleUtilities/Environment (~> 8.0)
- GoogleUtilities/UserDefaults (~> 8.0)
- PromisesObjC (~> 2.4)
- audio_session (0.0.1):
- Flutter
- audioplayers_darwin (0.0.1):
- Flutter
- FlutterMacOS
- device_info_plus (0.0.1):
- Flutter
- DKImagePickerController/Core (4.3.9):
- DKImagePickerController/ImageDataManager
- DKImagePickerController/Resource
- DKImagePickerController/ImageDataManager (4.3.9)
- DKImagePickerController/PhotoGallery (4.3.9):
- DKImagePickerController/Core
- DKPhotoGallery
- DKImagePickerController/Resource (4.3.9)
- DKPhotoGallery (0.0.19):
- DKPhotoGallery/Core (= 0.0.19)
- DKPhotoGallery/Model (= 0.0.19)
- DKPhotoGallery/Preview (= 0.0.19)
- DKPhotoGallery/Resource (= 0.0.19)
- SDWebImage
- SwiftyGif
- DKPhotoGallery/Core (0.0.19):
- DKPhotoGallery/Model
- DKPhotoGallery/Preview
- SDWebImage
- SwiftyGif
- DKPhotoGallery/Model (0.0.19):
- SDWebImage
- SwiftyGif
- DKPhotoGallery/Preview (0.0.19):
- DKPhotoGallery/Model
- DKPhotoGallery/Resource
- SDWebImage
- SwiftyGif
- DKPhotoGallery/Resource (0.0.19):
- SDWebImage
- SwiftyGif
- file_picker (0.0.1):
- DKImagePickerController/PhotoGallery
- Flutter
- Firebase/Auth (11.15.0):
- Firebase/CoreOnly
- FirebaseAuth (~> 11.15.0)
@ -141,6 +177,9 @@ PODS:
- in_app_purchase_storekit (0.0.1):
- Flutter
- FlutterMacOS
- just_audio (0.0.1):
- Flutter
- FlutterMacOS
- libpag (4.5.52)
- libwebp (1.5.0):
- libwebp/demux (= 1.5.0)
@ -170,6 +209,9 @@ PODS:
- pag (0.0.1):
- Flutter
- libpag
- path_provider_foundation (0.0.1):
- Flutter
- FlutterMacOS
- permission_handler_apple (9.3.0):
- Flutter
- PromisesObjC (2.4.0)
@ -191,6 +233,7 @@ PODS:
- Flutter
- FlutterMacOS
- SwiftyBeaver (1.9.5)
- SwiftyGif (5.4.5)
- tancent_vap (0.0.1):
- Flutter
- tencent_cloud_chat_sdk (8.0.0):
@ -223,8 +266,10 @@ PODS:
DEPENDENCIES:
- app_links (from `.symlinks/plugins/app_links/ios`)
- audio_session (from `.symlinks/plugins/audio_session/ios`)
- audioplayers_darwin (from `.symlinks/plugins/audioplayers_darwin/darwin`)
- device_info_plus (from `.symlinks/plugins/device_info_plus/ios`)
- file_picker (from `.symlinks/plugins/file_picker/ios`)
- firebase_auth (from `.symlinks/plugins/firebase_auth/ios`)
- firebase_core (from `.symlinks/plugins/firebase_core/ios`)
- firebase_crashlytics (from `.symlinks/plugins/firebase_crashlytics/ios`)
@ -235,9 +280,11 @@ DEPENDENCIES:
- image_cropper (from `.symlinks/plugins/image_cropper/ios`)
- image_picker_ios (from `.symlinks/plugins/image_picker_ios/ios`)
- in_app_purchase_storekit (from `.symlinks/plugins/in_app_purchase_storekit/darwin`)
- just_audio (from `.symlinks/plugins/just_audio/darwin`)
- on_audio_query_ios (from `.symlinks/plugins/on_audio_query_ios/ios`)
- package_info_plus (from `.symlinks/plugins/package_info_plus/ios`)
- pag (from `.symlinks/plugins/pag/ios`)
- path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`)
- permission_handler_apple (from `.symlinks/plugins/permission_handler_apple/ios`)
- shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`)
- sign_in_with_apple (from `.symlinks/plugins/sign_in_with_apple/ios`)
@ -255,6 +302,8 @@ SPEC REPOS:
trunk:
- AppAuth
- AppCheckCore
- DKImagePickerController
- DKPhotoGallery
- Firebase
- FirebaseAppCheckInterop
- FirebaseAuth
@ -282,6 +331,7 @@ SPEC REPOS:
- SDWebImage
- SDWebImageWebPCoder
- SwiftyBeaver
- SwiftyGif
- TOCropViewController
- TXCustomBeautyProcesserPlugin
- TXIMSDK_Plus_iOS_XCFramework
@ -290,10 +340,14 @@ SPEC REPOS:
EXTERNAL SOURCES:
app_links:
:path: ".symlinks/plugins/app_links/ios"
audio_session:
:path: ".symlinks/plugins/audio_session/ios"
audioplayers_darwin:
:path: ".symlinks/plugins/audioplayers_darwin/darwin"
device_info_plus:
:path: ".symlinks/plugins/device_info_plus/ios"
file_picker:
:path: ".symlinks/plugins/file_picker/ios"
firebase_auth:
:path: ".symlinks/plugins/firebase_auth/ios"
firebase_core:
@ -314,12 +368,16 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/image_picker_ios/ios"
in_app_purchase_storekit:
:path: ".symlinks/plugins/in_app_purchase_storekit/darwin"
just_audio:
:path: ".symlinks/plugins/just_audio/darwin"
on_audio_query_ios:
:path: ".symlinks/plugins/on_audio_query_ios/ios"
package_info_plus:
:path: ".symlinks/plugins/package_info_plus/ios"
pag:
:path: ".symlinks/plugins/pag/ios"
path_provider_foundation:
:path: ".symlinks/plugins/path_provider_foundation/darwin"
permission_handler_apple:
:path: ".symlinks/plugins/permission_handler_apple/ios"
shared_preferences_foundation:
@ -349,8 +407,12 @@ SPEC CHECKSUMS:
app_links: 3dbc685f76b1693c66a6d9dd1e9ab6f73d97dc0a
AppAuth: d4f13a8fe0baf391b2108511793e4b479691fb73
AppCheckCore: cc8fd0a3a230ddd401f326489c99990b013f0c4f
audio_session: 9bb7f6c970f21241b19f5a3658097ae459681ba0
audioplayers_darwin: 835ced6edd4c9fc8ebb0a7cc9e294a91d99917d5
device_info_plus: 71ffc6ab7634ade6267c7a93088ed7e4f74e5896
DKImagePickerController: 946cec48c7873164274ecc4624d19e3da4c1ef3c
DKPhotoGallery: b3834fecb755ee09a593d7c9e389d8b5d6deed60
file_picker: a0560bc09d61de87f12d246fc47d2119e6ef37be
Firebase: d99ac19b909cd2c548339c2241ecd0d1599ab02e
firebase_auth: 50af8366c87bb88c80ebeae62eb60189c7246b9b
firebase_core: 995454a784ff288be5689b796deb9e9fa3601818
@ -378,6 +440,7 @@ SPEC CHECKSUMS:
image_cropper: 655b3ba703c9e15e3111e79151624d6154288774
image_picker_ios: e0ece4aa2a75771a7de3fa735d26d90817041326
in_app_purchase_storekit: 22cca7d08eebca9babdf4d07d0baccb73325d3c8
just_audio: 4e391f57b79cad2b0674030a00453ca5ce817eed
libpag: 98742fad4b3ac2a2ee31e383d2483495fb9a5fb4
libwebp: 02b23773aedb6ff1fd38cec7a77b81414c6842a8
Mantle: c5aa8794a29a022dfbbfc9799af95f477a69b62d
@ -385,6 +448,7 @@ SPEC CHECKSUMS:
on_audio_query_ios: 28a780e2d0d85d92d500ba6e12c6c8167022b2fa
package_info_plus: af8e2ca6888548050f16fa2f1938db7b5a5df499
pag: f01aa9017ab0e04a83ba4a20d6070a50f0ac9da8
path_provider_foundation: 080d55be775b7414fd5a5ef3ac137b97b097e564
permission_handler_apple: 4ed2196e43d0651e8ff7ca3483a069d469701f2d
PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47
PromisesSwift: 9d77319bbe72ebf6d872900551f7eeba9bce2851
@ -395,6 +459,7 @@ SPEC CHECKSUMS:
sign_in_with_apple: c5dcc141574c8c54d5ac99dd2163c0c72ad22418
sqflite_darwin: 20b2a3a3b70e43edae938624ce550a3cbf66a3d0
SwiftyBeaver: 84069991dd5dca07d7069100985badaca7f0ce82
SwiftyGif: 706c60cf65fa2bc5ee0313beece843c8eb8194d4
tancent_vap: fa8ad93814a9f950514a7074c662d2c937084c68
tencent_cloud_chat_sdk: 55e5fffe20f6b7937a26a674ccccb639563a9790
tencent_rtc_sdk: f77558b6b436a149d378557c2a837f73c09061bc
@ -408,6 +473,6 @@ SPEC CHECKSUMS:
wakelock_plus: e29112ab3ef0b318e58cfa5c32326458be66b556
webview_flutter_wkwebview: 8ebf4fded22593026f7dbff1fbff31ea98573c8d
PODFILE CHECKSUM: a6f49a93e5f85201a2efdadcd7cf184b0e310894
PODFILE CHECKSUM: b724feb0f01aec7228c34cc4763485e911aa9322
COCOAPODS: 1.16.2

View File

@ -524,7 +524,7 @@
CODE_SIGN_ENTITLEMENTS = Runner/RunnerRelease.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 150;
CURRENT_PROJECT_VERSION = 1631;
DEVELOPMENT_TEAM = S9YG87C297;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
@ -533,7 +533,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 1.5.0;
MARKETING_VERSION = 1.6.3;
PRODUCT_BUNDLE_IDENTIFIER = com.org.yumiparty;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
@ -715,7 +715,7 @@
CODE_SIGN_ENTITLEMENTS = Runner/RunnerDebug.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 150;
CURRENT_PROJECT_VERSION = 1631;
DEVELOPMENT_TEAM = S9YG87C297;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
@ -724,7 +724,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 1.5.0;
MARKETING_VERSION = 1.6.3;
PRODUCT_BUNDLE_IDENTIFIER = com.org.yumiparty;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
@ -744,7 +744,7 @@
CODE_SIGN_ENTITLEMENTS = Runner/RunnerRelease.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 150;
CURRENT_PROJECT_VERSION = 1631;
DEVELOPMENT_TEAM = S9YG87C297;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
@ -753,7 +753,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 1.5.0;
MARKETING_VERSION = 1.6.3;
PRODUCT_BUNDLE_IDENTIFIER = com.org.yumiparty;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 MiB

After

Width:  |  Height:  |  Size: 1.8 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.6 KiB

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.7 KiB

After

Width:  |  Height:  |  Size: 8.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.1 KiB

After

Width:  |  Height:  |  Size: 7.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.6 KiB

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.9 KiB

After

Width:  |  Height:  |  Size: 6.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.8 KiB

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 76 KiB

After

Width:  |  Height:  |  Size: 67 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 50 KiB

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 57 KiB

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 67 KiB

After

Width:  |  Height:  |  Size: 58 KiB

View File

@ -163,6 +163,7 @@ private final class GiftMp4AlphaVideoView: UIView {
imageView.isOpaque = false
imageView.backgroundColor = .clear
imageView.contentMode = .scaleAspectFit
imageView.clipsToBounds = true
addSubview(imageView)
}
@ -191,6 +192,7 @@ private final class GiftMp4AlphaVideoView: UIView {
fileURL: url,
cacheKey: source.cacheKey
)
imageView.contentMode = sourceLayout.hasAlphaMask ? .scaleAspectFit : .scaleAspectFill
let item = AVPlayerItem(asset: asset)
let output = AVPlayerItemVideoOutput(pixelBufferAttributes: [

View File

@ -106,7 +106,7 @@ class _SCEditProfilePageState extends State<SCEditProfilePage> {
if (success) {
userProvider?.updateUserAvatar(url);
}
});
}, allowGif: true);
},
),
SizedBox(height: 15.w),
@ -559,24 +559,6 @@ class _SCEditProfilePageState extends State<SCEditProfilePage> {
return primary ?? fallback;
}
bool _isBrokenLocalMediaUrl(String? url) {
return (url ?? "").contains("/external/oss/local/");
}
String? _preferUsableAvatar(String? primary, String? fallback) {
if (primary != null &&
primary.isNotEmpty &&
!_isBrokenLocalMediaUrl(primary)) {
return primary;
}
if (fallback != null &&
fallback.isNotEmpty &&
!_isBrokenLocalMediaUrl(fallback)) {
return fallback;
}
return _preferNonEmpty(primary, fallback);
}
num? _preferNonZero(num? primary, num? fallback) {
if (primary != null && primary != 0) {
return primary;
@ -661,10 +643,6 @@ class _SCEditProfilePageState extends State<SCEditProfilePage> {
if (submittedProfile != null) {
final mergedProfile = (user.userProfile ?? SocialChatUserProfile())
.copyWith(
userAvatar: _preferUsableAvatar(
user.userProfile?.userAvatar,
submittedProfile.userAvatar,
),
userNickname: _preferNonEmpty(
user.userProfile?.userNickname,
submittedProfile.userNickname,

View File

@ -228,7 +228,7 @@ class _GiftPageState extends State<GiftPage> with TickerProviderStateMixin {
Provider.of<SCAppGeneralManager>(
context,
listen: false,
).giftList(includeCustomized: false);
).giftList(includeCustomized: true);
Provider.of<SCAppGeneralManager>(context, listen: false).giftActivityList();
unawaited(
Provider.of<SCAppGeneralManager>(
@ -325,7 +325,6 @@ class _GiftPageState extends State<GiftPage> with TickerProviderStateMixin {
final availableTypes =
ref.giftByTab.entries
.where((entry) => entry.value.isNotEmpty)
.where((entry) => entry.key != "CUSTOMIZED")
.where((entry) => entry.key != _backpackGiftTab)
.map((entry) => entry.key)
.toList();

View File

@ -558,31 +558,37 @@ class _SwipeDeleteTileState extends State<_SwipeDeleteTile> {
duration: const Duration(milliseconds: 160),
curve: Curves.easeOutCubic,
transform: Matrix4.translationValues(_dragOffset, 0, 0),
child: Row(
children: [
SizedBox(width: constraints.maxWidth, child: widget.child),
SizedBox(
width: actionWidth,
height: 56.w,
child: GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: widget.onDelete,
child: Container(
margin: EdgeInsetsDirectional.only(start: 4.w),
decoration: BoxDecoration(
color: const Color(0xFFE64A4A),
borderRadius: BorderRadius.circular(8.w),
),
alignment: Alignment.center,
child: Image.asset(
"sc_images/room/sc_music_material_delete.png",
width: 22.w,
height: 22.w,
child: SizedBox(
width: constraints.maxWidth + actionWidth,
child: Row(
children: [
SizedBox(
width: constraints.maxWidth,
child: widget.child,
),
SizedBox(
width: actionWidth,
height: 56.w,
child: GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: widget.onDelete,
child: Container(
margin: EdgeInsetsDirectional.only(start: 4.w),
decoration: BoxDecoration(
color: const Color(0xFFE64A4A),
borderRadius: BorderRadius.circular(8.w),
),
alignment: Alignment.center,
child: Image.asset(
"sc_images/room/sc_music_material_delete.png",
width: 22.w,
height: 22.w,
),
),
),
),
),
],
],
),
),
),
),

View File

@ -322,9 +322,11 @@ class _VoiceRoomPageState extends State<VoiceRoomPage>
OverlayManager().removeRoom(roomId: currentRoomId);
SCRoomEffectScheduler().clearDeferredTasks(reason: 'voice_room_suspend');
SCGiftVapSvgaManager().stopPlayback();
unawaited(
Provider.of<RoomMusicManager>(context, listen: false).stopForRoomExit(),
);
if (!SCFloatIchart().isShow()) {
unawaited(
Provider.of<RoomMusicManager>(context, listen: false).stopForRoomExit(),
);
}
}
Widget _buildRoomStartupLayer() {

View File

@ -98,21 +98,6 @@ class _EditUserInfoPage2State extends State<EditUserInfoPage2>
return primary ?? fallback;
}
bool _isBrokenLocalMediaUrl(String? url) {
return (url ?? "").contains("/external/oss/local/");
}
String? _preferUsableAvatar(String? primary, String? fallback) {
if ((primary ?? "").trim().isNotEmpty && !_isBrokenLocalMediaUrl(primary)) {
return primary;
}
if ((fallback ?? "").trim().isNotEmpty &&
!_isBrokenLocalMediaUrl(fallback)) {
return fallback;
}
return _preferNonEmpty(primary, fallback);
}
DateTime? _birthdayFromProfile([SocialChatUserProfile? profile]) {
final targetProfile =
profile ?? AccountStorage().getCurrentUser()?.userProfile;
@ -209,7 +194,7 @@ class _EditUserInfoPage2State extends State<EditUserInfoPage2>
}
void _syncLocalProfileState(SocialChatUserProfile profile) {
userCover = _preferUsableAvatar(profile.userAvatar, userCover);
userCover = profile.userAvatar;
nickName = profile.userNickname ?? nickName;
autograph = profile.autograph ?? autograph;
hobby = profile.hobby ?? hobby;
@ -293,11 +278,9 @@ class _EditUserInfoPage2State extends State<EditUserInfoPage2>
String url,
) {
if (success) {
userCover = url;
setState(() {});
submitAvatarOnly();
submit(userAvatarValue: url);
}
});
}, allowGif: true);
},
),
SizedBox(height: 3.w),
@ -464,13 +447,6 @@ class _EditUserInfoPage2State extends State<EditUserInfoPage2>
return eighteenYearsAgo;
}
void submitAvatarOnly() {
if ((userCover ?? "").trim().isEmpty) {
return;
}
submit(userAvatarValue: userCover);
}
void submit({
Object? userAvatarValue = _noChange,
Object? userNicknameValue = _noChange,
@ -538,12 +514,6 @@ class _EditUserInfoPage2State extends State<EditUserInfoPage2>
countryId: selectedCountry?.id,
);
final mergedProfile = updatedProfile.copyWith(
userAvatar: _preferUsableAvatar(
updatedProfile.userAvatar,
identical(userAvatarValue, _noChange)
? userCover
: userAvatarValue as String?,
),
userNickname: _preferNonEmpty(
updatedProfile.userNickname,
identical(userNicknameValue, _noChange)

View File

@ -887,6 +887,8 @@ class _PersonDetailPageState extends State<PersonDetailPage> with RouteAware {
width: ScreenUtil().screenWidth,
height: 300.w,
fit: BoxFit.cover,
gifFit: BoxFit.cover,
gifAlignment: Alignment.topCenter,
),
);
}).toList(),
@ -2024,6 +2026,7 @@ class _PersonDetailPageState extends State<PersonDetailPage> with RouteAware {
},
aspectRatio: ScreenUtil().screenWidth / 300.w,
backOriginalFile: false,
allowGif: true,
);
}
@ -2040,19 +2043,8 @@ class _PersonDetailPageState extends State<PersonDetailPage> with RouteAware {
final updatedProfile = await SCAccountRepository().updateUserInfo(
backgroundPhotos: [imageUrl],
);
final returnedPhotos = updatedProfile.backgroundPhotos ?? [];
final hasUploadedPhoto = returnedPhotos.any(
(photo) => (photo.url ?? "").trim() == imageUrl,
);
final backgroundPhotos =
hasUploadedPhoto
? returnedPhotos
: [PersonPhoto(url: imageUrl, status: 1)];
final mergedProfile = updatedProfile.copyWith(
backgroundPhotos: backgroundPhotos,
);
ref.userProfile = mergedProfile;
ref.syncCurrentUserProfile(mergedProfile);
ref.userProfile = updatedProfile;
ref.syncCurrentUserProfile(updatedProfile);
if (!mounted) {
return;
}

View File

@ -64,6 +64,7 @@ import '../../ui_kit/widgets/room/rocket/room_rocket_pag_effect_overlay.dart';
import '../../ui_kit/widgets/room/rocket/room_rocket_api_mapper.dart';
typedef OnSoundVoiceChange = Function(num index, int volum);
typedef RoomMusicSessionExitListener = Future<void> Function();
typedef RtcProvider = RealTimeCommunicationManager;
enum RoomStartupStatus { idle, loading, ready, failed }
@ -464,6 +465,7 @@ class RealTimeCommunicationManager extends ChangeNotifier {
RoomRtcEngineAdapter? _roomRtcEngineAdapter;
RoomMusicMixingStateListener? _roomMusicMixingStateListener;
RoomMusicMicRouteChangedListener? _roomMusicMicRouteChangedListener;
RoomMusicSessionExitListener? _roomMusicSessionExitListener;
BuildContext? context;
RtmProvider? rtmProvider;
@ -2761,7 +2763,7 @@ class RealTimeCommunicationManager extends ChangeNotifier {
}
}
if (currenRoom != null) {
_switchAwayFromCurrentRoomForNewEntry();
await _switchAwayFromCurrentRoomForNewEntry();
}
if (!context.mounted) {
return;
@ -4728,8 +4730,9 @@ class RealTimeCommunicationManager extends ChangeNotifier {
exitRtmProvider?.cleanRoomData();
} catch (e) {}
await _notifyRoomMusicSessionExit();
_clearData(clearPersistedRoomMarker: false);
if (!isLogout && navigationContext != null) {
if (!isLogout && navigationContext != null && navigationContext.mounted) {
VoiceRoomRoute.popVoiceRoomToPrevious(navigationContext);
}
@ -4749,7 +4752,7 @@ class RealTimeCommunicationManager extends ChangeNotifier {
}
}
void _switchAwayFromCurrentRoomForNewEntry() {
Future<void> _switchAwayFromCurrentRoomForNewEntry() async {
_stopRoomStatePolling();
final groupId = currenRoom?.roomProfile?.roomProfile?.roomAccount ?? "";
final roomId = currenRoom?.roomProfile?.roomProfile?.id ?? "";
@ -4763,6 +4766,7 @@ class RealTimeCommunicationManager extends ChangeNotifier {
exitRtmProvider?.cleanRoomData();
} catch (e) {}
await _notifyRoomMusicSessionExit();
_clearData(clearPersistedRoomMarker: false);
final roomRtcLeaveTask = _leaveRoomRtcForExit();
_pendingRoomSwitchRtcLeaveTask = roomRtcLeaveTask;
@ -5776,6 +5780,20 @@ class RealTimeCommunicationManager extends ChangeNotifier {
_roomMusicMicRouteChangedListener = listener;
}
void setRoomMusicSessionExitListener(RoomMusicSessionExitListener? listener) {
_roomMusicSessionExitListener = listener;
}
Future<void> _notifyRoomMusicSessionExit() async {
final listener = _roomMusicSessionExitListener;
if (listener == null) {
return;
}
try {
await listener();
} catch (_) {}
}
void updateRoomMusicPublishingState({
required String? userId,
required bool publishing,

View File

@ -213,24 +213,28 @@ class SCAppGeneralManager extends ChangeNotifier {
}
}
String _displayGiftTab(String? giftTab) {
return giftTab == "EXCLUSIVE" ? "CUSTOMIZED" : (giftTab ?? "");
}
void _rebuildGiftTabs({required bool includeCustomized}) {
giftByTab.clear();
_giftByIdMap.clear();
_giftByStandardIdMap.clear();
for (var gift in giftResList) {
giftByTab[gift.giftTab];
var gmap = giftByTab[gift.giftTab];
final tab = _displayGiftTab(gift.giftTab);
var gmap = giftByTab[tab];
gmap ??= [];
gmap.add(gift);
giftByTab[gift.giftTab!] = gmap;
giftByTab[tab] = gmap;
var gAllMap = giftByTab["ALL"];
gAllMap ??= [];
if (gift.giftTab != "NSCIONAL_FLAG" &&
gift.giftTab != "ACTIVITY" &&
gift.giftTab != "LUCKY_GIFT" &&
gift.giftTab != "CP" &&
gift.giftTab != "CUSTOMIZED" &&
gift.giftTab != "MAGIC") {
if (tab != "NSCIONAL_FLAG" &&
tab != "ACTIVITY" &&
tab != "LUCKY_GIFT" &&
tab != "CP" &&
tab != "CUSTOMIZED" &&
tab != "MAGIC") {
gAllMap.add(gift);
}
giftByTab["ALL"] = gAllMap;

View File

@ -1,7 +1,11 @@
import 'dart:convert';
import 'dart:io';
import 'package:file_picker/file_picker.dart';
import 'package:just_audio/just_audio.dart';
import 'package:on_audio_query/on_audio_query.dart';
import 'package:path/path.dart' as p;
import 'package:path_provider/path_provider.dart';
import 'package:yumi/shared/data_sources/models/sc_music_folder_mode.dart';
import 'package:yumi/shared/data_sources/models/sc_music_mode.dart';
import 'package:yumi/shared/tools/sc_permission_utils.dart';
@ -15,6 +19,10 @@ class LocalMusicScanner {
Future<List<SCMusicFolderMode>> scanMp3Folders({
List<SCMusicMode> addedSongs = const [],
}) async {
if (Platform.isIOS) {
return _pickIosMp3Files(addedSongs: addedSongs);
}
final hasPermission = await SCPermissionUtils.checkAudioPermission();
if (!hasPermission) {
return const <SCMusicFolderMode>[];
@ -96,6 +104,98 @@ class LocalMusicScanner {
return List<SCMusicFolderMode>.unmodifiable(folders);
}
Future<List<SCMusicFolderMode>> _pickIosMp3Files({
required List<SCMusicMode> addedSongs,
}) async {
final FilePickerResult? result;
try {
result = await FilePicker.pickFiles(
type: FileType.custom,
allowedExtensions: const ['mp3'],
allowMultiple: true,
withData: false,
withReadStream: false,
);
} catch (_) {
return const <SCMusicFolderMode>[];
}
if (result == null || result.files.isEmpty) {
return const <SCMusicFolderMode>[];
}
final addedIds = addedSongs.map((item) => item.id).toSet();
final addedPaths = addedSongs.map((item) => item.localPath).toSet();
final storageDir = await _iosRoomMusicDirectory();
final player = AudioPlayer();
final songs = <SCMusicMode>[];
final seen = <String>{};
try {
for (final file in result.files) {
final sourcePath = (file.path ?? '').trim();
if (sourcePath.isEmpty ||
!_isMp3FileName(file.name) ||
!_fileExists(sourcePath)) {
continue;
}
final sourceId = _firstNonEmpty([
file.identifier,
'${file.name}:${file.size}',
sourcePath,
]);
if (sourceId.isEmpty || !seen.add(sourceId)) {
continue;
}
final storedPath = await _copyIosPickedFile(
sourcePath: sourcePath,
fileName: file.name,
sourceId: sourceId,
storageDir: storageDir,
);
final durationMs = await _readLocalMp3DurationMs(player, storedPath);
final storedFile = File(storedPath);
final safeFileName = p.basename(storedPath);
songs.add(
SCMusicMode(
id: sourceId,
title: p.basenameWithoutExtension(file.name).trim(),
artist: '',
durationMs: durationMs,
localPath: storedPath,
contentUri: '',
folderPath: storageDir.path,
fileName: safeFileName,
size: storedFile.existsSync() ? storedFile.lengthSync() : file.size,
addedAt: DateTime.now().millisecondsSinceEpoch,
),
);
}
} finally {
await player.dispose();
}
if (songs.isEmpty) {
return const <SCMusicFolderMode>[];
}
songs.sort(
(a, b) => a.title.toLowerCase().compareTo(b.title.toLowerCase()),
);
final addedCount =
songs.where((song) {
return addedIds.contains(song.id) ||
addedPaths.contains(song.localPath);
}).length;
return <SCMusicFolderMode>[
SCMusicFolderMode(
id: 'ios_file_picker',
name: 'Selected Music',
path: 'Files',
songs: List<SCMusicMode>.unmodifiable(songs),
addedCount: addedCount,
),
];
}
bool _isMp3(SongModel song) {
final extension = _songString(
song,
@ -108,6 +208,72 @@ class LocalMusicScanner {
_songString(song, "_data").toLowerCase().endsWith(".mp3");
}
bool _isMp3FileName(String fileName) {
return fileName.toLowerCase().endsWith('.mp3');
}
Future<Directory> _iosRoomMusicDirectory() async {
final supportDir = await getApplicationSupportDirectory();
final directory = Directory(p.join(supportDir.path, 'room_music'));
if (!directory.existsSync()) {
await directory.create(recursive: true);
}
return directory;
}
Future<String> _copyIosPickedFile({
required String sourcePath,
required String fileName,
required String sourceId,
required Directory storageDir,
}) async {
if (p.isWithin(storageDir.path, sourcePath)) {
return sourcePath;
}
final sourceFile = File(sourcePath);
final targetFile = File(
p.join(storageDir.path, _iosStoredFileName(fileName, sourceId)),
);
if (targetFile.existsSync() &&
targetFile.lengthSync() == sourceFile.lengthSync()) {
return targetFile.path;
}
await sourceFile.copy(targetFile.path);
return targetFile.path;
}
String _iosStoredFileName(String fileName, String sourceId) {
final baseName = p.basenameWithoutExtension(fileName).trim();
final safeBaseName =
baseName
.replaceAll(RegExp(r'[^A-Za-z0-9._ -]+'), '_')
.replaceAll(RegExp(r'\s+'), ' ')
.trim();
final token = base64Url.encode(utf8.encode(sourceId)).replaceAll('=', '');
final suffix = token.length > 12 ? token.substring(0, 12) : token;
return '${safeBaseName.isEmpty ? 'music' : safeBaseName}_$suffix.mp3';
}
Future<int> _readLocalMp3DurationMs(AudioPlayer player, String path) async {
try {
final duration = await player.setFilePath(path);
await player.stop();
return duration?.inMilliseconds ?? 0;
} catch (_) {
return 0;
}
}
String _firstNonEmpty(List<String?> values) {
for (final value in values) {
final text = value?.trim() ?? '';
if (text.isNotEmpty) {
return text;
}
}
return '';
}
bool _fileExists(String path) {
try {
return File(path).existsSync();

View File

@ -2,6 +2,7 @@ import 'dart:async';
import 'dart:io';
import 'dart:math';
import 'package:audio_session/audio_session.dart';
import 'package:flutter/foundation.dart';
import 'package:yumi/services/audio/rtc_manager.dart';
import 'package:yumi/services/audio/room_rtc_types.dart';
@ -86,9 +87,11 @@ class RoomMusicManager extends ChangeNotifier {
}
_rtcProvider?.setRoomMusicMixingStateListener(null);
_rtcProvider?.setRoomMusicMicRouteChangedListener(null);
_rtcProvider?.setRoomMusicSessionExitListener(null);
_rtcProvider = provider;
provider.setRoomMusicMixingStateListener(_handleMixingStateChanged);
provider.setRoomMusicMicRouteChangedListener(_handleMicRouteChanged);
provider.setRoomMusicSessionExitListener(stopForRoomExit);
_syncPublishingState(force: true);
}
@ -364,6 +367,7 @@ class RoomMusicManager extends ChangeNotifier {
}
_isStarting = true;
try {
await _configureIosAudioSessionIfNeeded();
await _waitForStartInterval();
_lastLoopback = !rtcProvider.isOnMai();
await rtcProvider.startRoomMusicAudioMixing(
@ -404,6 +408,31 @@ class RoomMusicManager extends ChangeNotifier {
}
}
Future<void> _configureIosAudioSessionIfNeeded() async {
if (!Platform.isIOS) {
return;
}
try {
final session = await AudioSession.instance;
await session.configure(
AudioSessionConfiguration(
avAudioSessionCategory: AVAudioSessionCategory.playAndRecord,
avAudioSessionCategoryOptions:
AVAudioSessionCategoryOptions.mixWithOthers |
AVAudioSessionCategoryOptions.defaultToSpeaker |
AVAudioSessionCategoryOptions.allowBluetooth |
AVAudioSessionCategoryOptions.allowBluetoothA2dp,
avAudioSessionMode: AVAudioSessionMode.voiceChat,
avAudioSessionRouteSharingPolicy:
AVAudioSessionRouteSharingPolicy.defaultPolicy,
avAudioSessionSetActiveOptions: AVAudioSessionSetActiveOptions.none,
),
);
} catch (_) {
// TRTC can still manage the iOS audio session if this best-effort setup fails.
}
}
void _startPositionTimer() {
_positionTimer?.cancel();
_positionTimer = Timer.periodic(const Duration(milliseconds: 800), (_) {
@ -554,6 +583,7 @@ class RoomMusicManager extends ChangeNotifier {
_publishingStateHeartbeatTimer?.cancel();
_rtcProvider?.setRoomMusicMixingStateListener(null);
_rtcProvider?.setRoomMusicMicRouteChangedListener(null);
_rtcProvider?.setRoomMusicSessionExitListener(null);
super.dispose();
}
}

View File

@ -1,5 +1,4 @@
import 'dart:io';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';
import 'package:yumi/ui_kit/components/sc_tts.dart';
@ -11,6 +10,8 @@ import 'package:yumi/shared/tools/sc_loading_manager.dart';
class SCPickUtils {
static final ImagePicker _pkr = ImagePicker();
static const int _defaultMaxImageBytes = 4000000;
static const int _gifOriginalMaxImageBytes = 10 * 1024 * 1024;
static void pickImage(
BuildContext context,
@ -18,27 +19,51 @@ class SCPickUtils {
double? aspectRatio,
bool? backOriginalFile = true,
bool? neeCrop = true,
bool allowGif = false,
bool skipCropForGif = true,
}) async {
try {
final XFile? pickedFile = await _pkr.pickImage(
source: ImageSource.gallery,
imageQuality: 90,
maxWidth: 1920,
maxHeight: 1080,
);
final XFile? pickedFile =
allowGif
? await _pkr.pickImage(source: ImageSource.gallery)
: await _pkr.pickImage(
source: ImageSource.gallery,
imageQuality: 90,
maxWidth: 1920,
maxHeight: 1080,
);
if (pickedFile == null) return;
if (!SCPathUtils.fileTypeIsPic(pickedFile.path)) {
SCTts.show("Please select sc_images in .jpg, .jpeg, .png format.");
final isGif = await _igif(pickedFile);
if (!context.mounted) {
onUpLoadCallBack(false, "");
return;
}
// GIF
if (await _igif(pickedFile)) {
SCTts.show("GIF sc_images are not supported");
if (isGif) {
if (!allowGif) {
SCTts.show("GIF sc_images are not supported");
return;
}
} else if (!SCPathUtils.fileTypeIsPic(pickedFile.path)) {
SCTts.show(
allowGif
? "Please select sc_images in .jpg, .jpeg, .png, .gif format."
: "Please select sc_images in .jpg, .jpeg, .png format.",
);
return;
}
final File imageFile = File(pickedFile.path);
if (isGif && skipCropForGif) {
await _uploadOriginalImage(
context,
imageFile,
onUpLoadCallBack,
maxBytes: _gifOriginalMaxImageBytes,
oversizeMessage: "The GIF image size cannot exceed 10M",
);
return;
}
if (neeCrop ?? false) {
cropImage(
imageFile,
@ -48,28 +73,45 @@ class SCPickUtils {
onUpLoadCallBack,
);
} else {
if (imageFile.lengthSync() > 4000000) {
SCTts.show(SCAppLocalizations.of(context)!.theImageSizeCannotExceed);
onUpLoadCallBack?.call(false, "");
return;
}
SCLoadingManager.show(context: context);
try {
String fileUrl = await SCGeneralRepositoryImp().upload(imageFile);
SCLoadingManager.hide();
onUpLoadCallBack?.call(true, fileUrl);
} catch (e) {
SCTts.show("upload fail $e");
onUpLoadCallBack?.call(false, "");
SCLoadingManager.hide();
}
await _uploadOriginalImage(
context,
imageFile,
onUpLoadCallBack,
maxBytes: _defaultMaxImageBytes,
oversizeMessage:
SCAppLocalizations.of(context)!.theImageSizeCannotExceed,
);
}
} catch (e) {
onUpLoadCallBack?.call(false, "");
onUpLoadCallBack(false, "");
SCTts.show("Failed to select image");
}
}
static Future<void> _uploadOriginalImage(
BuildContext context,
File imageFile,
OnUpLoadCallBack onUpLoadCallBack, {
required int maxBytes,
required String oversizeMessage,
}) async {
if (imageFile.lengthSync() > maxBytes) {
SCTts.show(oversizeMessage);
onUpLoadCallBack(false, "");
return;
}
SCLoadingManager.show(context: context);
try {
String fileUrl = await SCGeneralRepositoryImp().upload(imageFile);
SCLoadingManager.hide();
onUpLoadCallBack(true, fileUrl);
} catch (e) {
SCTts.show("upload fail $e");
onUpLoadCallBack(false, "");
SCLoadingManager.hide();
}
}
/// GIF
static Future<bool> _igif(XFile file) async {
try {
@ -165,7 +207,12 @@ class SCPickUtils {
if (pickedFile == null) return;
// GIF
if (await _igif(pickedFile)) {
final isGif = await _igif(pickedFile);
if (!context.mounted) {
onUpLoadCallBack(false, "");
return;
}
if (isGif) {
SCTts.show("Unsupported image format");
return;
}
@ -209,9 +256,6 @@ class SCPickUtils {
OnUpLoadCallBack onUpLoadCallBack, {
bool needUpload = true,
}) async {
if (originalImage == null) {
return;
}
await Navigator.push(
context,
MaterialPageRoute(

View File

@ -49,6 +49,7 @@ Widget head({
String? headdressCover,
BoxShape shape = BoxShape.circle,
BoxFit fit = BoxFit.cover,
BoxFit gifFit = BoxFit.contain,
BorderRadius? borderRadius,
bool showDefault = true,
bool isRoom = false,
@ -85,6 +86,7 @@ Widget head({
width: avatarWidth,
height: avatarHeight,
fit: fit,
gifFit: gifFit,
noDefaultImg: !showDefault,
defaultImg: "sc_images/general/sc_icon_avar_defalt.png",
),
@ -221,19 +223,28 @@ Widget netImage({
double? height,
BorderRadius? borderRadius,
BoxFit? fit,
BoxFit? gifFit,
AlignmentGeometry? gifAlignment,
BoxShape? shape,
Border? border,
Widget? loadingWidget,
Widget? errorWidget,
}) {
final isGif = SCPathUtils.getFileExtension(url) == ".gif";
final resolvedHeight = height ?? width;
final resolvedFit =
isGif ? (gifFit ?? fit ?? BoxFit.cover) : (fit ?? BoxFit.cover);
final resolvedAlignment =
isGif ? (gifAlignment ?? Alignment.center) : Alignment.center;
return ExtendedImage.network(
url,
width: width,
height: height ?? width,
cacheWidth: _resolveImageCacheDimension(width),
cacheHeight: _resolveImageCacheDimension(height ?? width),
height: resolvedHeight,
cacheWidth: isGif ? null : _resolveImageCacheDimension(width),
cacheHeight: isGif ? null : _resolveImageCacheDimension(resolvedHeight),
headers: buildNetworkImageHeaders(url),
fit: fit ?? BoxFit.cover,
fit: resolvedFit,
alignment: resolvedAlignment,
cache: true,
shape: shape ?? BoxShape.rectangle,
borderRadius: borderRadius,
@ -246,7 +257,10 @@ Widget netImage({
if (state.extendedImageLoadState == LoadState.completed) {
return ExtendedRawImage(
image: state.extendedImageInfo?.image,
fit: fit ?? BoxFit.cover,
width: width,
height: resolvedHeight,
fit: resolvedFit,
alignment: resolvedAlignment,
);
} else if (state.extendedImageLoadState == LoadState.failed) {
if (errorWidget != null) {

View File

@ -1,5 +1,3 @@
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:yumi/app_localizations.dart';
@ -10,7 +8,6 @@ import 'package:yumi/app/routes/sc_fluro_navigator.dart';
import 'package:yumi/modules/room/voice_room_route.dart';
import 'package:yumi/services/audio/rtm_manager.dart';
import 'package:yumi/services/gift/gift_animation_manager.dart';
import 'package:yumi/services/music/room_music_manager.dart';
import 'package:yumi/services/audio/rtc_manager.dart';
import 'package:yumi/shared/data_sources/sources/local/floating_screen_manager.dart';
import 'package:yumi/shared/tools/sc_gift_vap_svga_manager.dart';
@ -88,7 +85,6 @@ class _ExitMinRoomPageState extends State<ExitMinRoomPage> {
reason: 'room_minimize',
);
SCGiftVapSvgaManager().stopPlayback();
unawaited(context.read<RoomMusicManager>().stopForRoomExit());
giftAnimationManager.cleanupAnimationResources();
SCFloatIchart().show();
VoiceRoomRoute.popVoiceRoomToPrevious(context);

File diff suppressed because it is too large Load Diff

View File

@ -16,7 +16,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
# In Windows, build-name is used as the major, minor, and patch parts
# of the product and file versions while build-number is used as the build suffix.
version: 1.5.0+150
version: 1.6.3+1631
environment:
@ -47,8 +47,8 @@ dependencies:
pretty_dio_logger: ^1.1.1
#下拉刷新
pull_to_refresh: 2.0.0
#腾讯TRTC
tencent_rtc_sdk: ^13.2.2
#腾讯TRTC
tencent_rtc_sdk: ^13.2.2
#腾讯IM
tencent_cloud_chat_sdk: 8.3.6498+3
#缓存
@ -84,26 +84,26 @@ dependencies:
#相册
# wechat_assets_picker: ^9.5.0
# wechat_camera_picker: ^4.2.0
image_picker: ^1.2.0
#图片裁剪
image_cropper:
path: ./local_packages/image_cropper-5.0.1-patched
back_button_interceptor: ^8.0.4
image_picker: ^1.2.0
#图片裁剪
image_cropper:
path: ./local_packages/image_cropper-5.0.1-patched
back_button_interceptor: ^8.0.4
#vap特效
# flutter_vap_plus: ^1.2.10
# tancent_vap: ^1.0.0+1
tancent_vap:
path: ./local_packages/tancent_vap-1.0.0+1
#svga特效
flutter_svga:
path: ./local_packages/flutter_svga-0.0.13-patched
#banner
tancent_vap:
path: ./local_packages/tancent_vap-1.0.0+1
#svga特效
flutter_svga:
path: ./local_packages/flutter_svga-0.0.13-patched
#banner
carousel_slider: ^5.1.1
#谷歌支付
in_app_purchase: ^3.2.3
in_app_purchase_android: ^0.4.0+10
device_info_plus: ^10.0.0
#谷歌支付
in_app_purchase: ^3.2.3
in_app_purchase_android: ^0.4.0+10
device_info_plus: ^10.0.0
package_info_plus: ^8.0.0
uuid: ^4.5.1
wakelock_plus: ^1.1.0
@ -115,34 +115,42 @@ dependencies:
# flutter_sound: 9.28.0
#图片压缩
flutter_image_compress: ^2.4.0
extended_text: ^15.0.2
audioplayers: ^6.5.1
#缩略图
video_thumbnail: ^0.5.6
extended_text: ^15.0.2
audioplayers: ^6.5.1
#缩略图
video_thumbnail: ^0.5.6
badges: ^3.1.2
#本地路径
path_provider: ^2.1.4
path: ^1.9.0
on_audio_query:
path: ./local_packages/on_audio_query-2.9.0
photo_view: ^0.15.0
#本地路径
path_provider: ^2.1.4
path: ^1.9.0
on_audio_query:
path: ./local_packages/on_audio_query-2.9.0
photo_view: ^0.15.0
flutter_staggered_grid_view: ^0.7.0
marquee: ^2.3.0
extended_nested_scroll_view: ^6.2.1
event_bus: ^2.0.1
readmore: ^3.0.0
#外链跳转
app_links: ^6.4.1
readmore: ^3.0.0
#外链跳转
app_links: ^6.4.1
flutter_svg: ^2.3.0
pag:
path: ./local_packages/pag-1.0.7-patched
dev_dependencies:
pag:
path: ./local_packages/pag-1.0.7-patched
just_audio: ^0.10.5
audio_session: ^0.2.3
file_picker: ^11.0.2
dev_dependencies:
flutter_launcher_icons: ^0.14.4
flutter_test:
sdk: flutter
flutter_lints: ^5.0.0
dependency_overrides:
# path_provider_foundation 2.6.0 pulls in objective_c native assets that are
# currently packaged as simulator frameworks and rejected by App Store upload.
path_provider_foundation: 2.4.2
# For information on the generic Dart part of this file, see the
# following page: https://dart.dev/tools/pub/pubspec
@ -156,38 +164,38 @@ flutter:
# - family: MyCustomFont
# fonts:
# - asset: fonts/AAA-bold.ttf
assets:
# 共享资源
# 应用资源路径
- assets/
- assets/debug/
- assets/l10n/
- sc_images/splash/
assets:
# 共享资源
# 应用资源路径
- assets/
- assets/debug/
- assets/l10n/
- sc_images/splash/
- sc_images/login/
- sc_images/general/
- sc_images/index/
- sc_images/daily_sign_in/
- sc_images/register_reward/
- sc_images/first_recharge/
- sc_images/room/
- sc_images/room/cp_profile/
- sc_images/room/cp_rights/
- sc_images/room/cp_progress/
- sc_images/room/cp_invite/
- sc_images/room/background_examples/
- sc_images/room/cp_broadcast/
- sc_images/room/emoji/
- sc_images/room/entrance/
- sc_images/room/mic/
- sc_images/room/red_packet/
- sc_images/room/rocket/
- sc_images/room/anim/
- sc_images/room/anim/gift/
- sc_images/room/anim/luck_gift/
- sc_images/person/
- sc_images/general/
- sc_images/index/
- sc_images/daily_sign_in/
- sc_images/register_reward/
- sc_images/first_recharge/
- sc_images/room/
- sc_images/room/cp_profile/
- sc_images/room/cp_rights/
- sc_images/room/cp_progress/
- sc_images/room/cp_invite/
- sc_images/room/background_examples/
- sc_images/room/cp_broadcast/
- sc_images/room/emoji/
- sc_images/room/entrance/
- sc_images/room/mic/
- sc_images/room/red_packet/
- sc_images/room/rocket/
- sc_images/room/anim/
- sc_images/room/anim/gift/
- sc_images/room/anim/luck_gift/
- sc_images/person/
- sc_images/store/
- sc_images/msg/
- sc_images/level/
- sc_images/coupon/
- sc_images/vip/
- fonts/
- fonts/