413 lines
13 KiB
Dart
413 lines
13 KiB
Dart
import 'dart:io';
|
|
|
|
import 'package:flutter/material.dart';
|
|
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
|
import 'package:yumi/app/constants/sc_global_config.dart';
|
|
import 'package:yumi/app_localizations.dart';
|
|
import 'package:yumi/modules/room/voice_room_route.dart';
|
|
import 'package:yumi/shared/business_logic/usecases/sc_fixed_width_tabIndicator.dart';
|
|
import 'package:yumi/ui_kit/components/appbar/socialchat_appbar.dart';
|
|
import 'package:yumi/ui_kit/theme/socialchat_theme.dart';
|
|
|
|
class RoomBackgroundSelectPage extends StatefulWidget {
|
|
const RoomBackgroundSelectPage({super.key});
|
|
|
|
@override
|
|
State<RoomBackgroundSelectPage> createState() =>
|
|
_RoomBackgroundSelectPageState();
|
|
}
|
|
|
|
class _RoomBackgroundSelectPageState extends State<RoomBackgroundSelectPage>
|
|
with SingleTickerProviderStateMixin {
|
|
late final TabController _tabController;
|
|
late final List<_RoomBackgroundItem> _officialItems;
|
|
late final List<_RoomBackgroundItem> _mineItems;
|
|
|
|
bool get _showAddButton => _tabController.index == 1;
|
|
|
|
@override
|
|
void initState() {
|
|
super.initState();
|
|
_tabController = TabController(length: 2, vsync: this);
|
|
_tabController.addListener(_handleTabChange);
|
|
_officialItems = [
|
|
_RoomBackgroundItem(inUse: true),
|
|
_RoomBackgroundItem(),
|
|
_RoomBackgroundItem(),
|
|
_RoomBackgroundItem(),
|
|
];
|
|
_mineItems = [_RoomBackgroundItem(), _RoomBackgroundItem()];
|
|
}
|
|
|
|
@override
|
|
void dispose() {
|
|
_tabController.removeListener(_handleTabChange);
|
|
_tabController.dispose();
|
|
super.dispose();
|
|
}
|
|
|
|
void _handleTabChange() {
|
|
if (!mounted) {
|
|
return;
|
|
}
|
|
setState(() {});
|
|
}
|
|
|
|
Future<void> _openUploadPage() async {
|
|
final uploadedPath = await VoiceRoomRoute.openRoomBackgroundUpload<String>(
|
|
context,
|
|
);
|
|
if (!mounted || (uploadedPath ?? "").trim().isEmpty) {
|
|
return;
|
|
}
|
|
|
|
setState(() {
|
|
for (final item in _mineItems) {
|
|
item.inUse = false;
|
|
}
|
|
_mineItems.insert(
|
|
0,
|
|
_RoomBackgroundItem(localImagePath: uploadedPath, inUse: true),
|
|
);
|
|
});
|
|
_tabController.animateTo(1);
|
|
}
|
|
|
|
void _selectItem(List<_RoomBackgroundItem> items, int index) {
|
|
setState(() {
|
|
for (final item in items) {
|
|
item.inUse = false;
|
|
}
|
|
items[index].inUse = true;
|
|
});
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final localizations = SCAppLocalizations.of(context)!;
|
|
final bottomPadding = MediaQuery.of(context).padding.bottom;
|
|
return Stack(
|
|
children: [
|
|
Image.asset(
|
|
SCGlobalConfig.businessLogicStrategy.getLanguagePageBackgroundImage(),
|
|
width: ScreenUtil().screenWidth,
|
|
height: ScreenUtil().screenHeight,
|
|
fit: BoxFit.fill,
|
|
),
|
|
Scaffold(
|
|
backgroundColor: Colors.transparent,
|
|
appBar: _buildAppBar(context, localizations),
|
|
body: Container(
|
|
color: const Color(0xff0F0F0F),
|
|
child: Stack(
|
|
children: [
|
|
Column(
|
|
children: [
|
|
Container(
|
|
height: 0.5,
|
|
color: Colors.white.withValues(alpha: 0.15),
|
|
),
|
|
Expanded(
|
|
child: TabBarView(
|
|
controller: _tabController,
|
|
children: [
|
|
_RoomBackgroundGrid(
|
|
items: _officialItems,
|
|
onTap:
|
|
(index) => _selectItem(_officialItems, index),
|
|
bottomPadding: 24.w,
|
|
),
|
|
_RoomBackgroundGrid(
|
|
items: _mineItems,
|
|
onTap: (index) => _selectItem(_mineItems, index),
|
|
bottomPadding: 100.w,
|
|
),
|
|
],
|
|
),
|
|
),
|
|
],
|
|
),
|
|
if (_showAddButton)
|
|
Positioned(
|
|
left: 18.w,
|
|
right: 18.w,
|
|
bottom: 20.w + bottomPadding,
|
|
child: GestureDetector(
|
|
behavior: HitTestBehavior.opaque,
|
|
onTap: _openUploadPage,
|
|
child: Container(
|
|
height: 48.w,
|
|
alignment: Alignment.center,
|
|
decoration: BoxDecoration(
|
|
borderRadius: BorderRadius.circular(999.w),
|
|
gradient: LinearGradient(
|
|
colors: [
|
|
SocialChatTheme.primaryLight,
|
|
const Color(0xff8BF2D0),
|
|
],
|
|
),
|
|
),
|
|
child: Text(
|
|
'add',
|
|
style: TextStyle(
|
|
color: const Color(0xff0B2823),
|
|
fontSize: 16.sp,
|
|
fontWeight: FontWeight.w700,
|
|
),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
],
|
|
);
|
|
}
|
|
|
|
PreferredSizeWidget _buildAppBar(
|
|
BuildContext context,
|
|
SCAppLocalizations localizations,
|
|
) {
|
|
return SocialChatAppBar(
|
|
backgroundColor: Colors.transparent,
|
|
child: Row(
|
|
children: [
|
|
SizedBox(
|
|
width: 52.w,
|
|
child: GestureDetector(
|
|
behavior: HitTestBehavior.opaque,
|
|
onTap: () => Navigator.pop(context),
|
|
child: Icon(
|
|
SCGlobalConfig.lang == "ar"
|
|
? Icons.keyboard_arrow_right
|
|
: Icons.keyboard_arrow_left,
|
|
size: 28.w,
|
|
color: Colors.white,
|
|
),
|
|
),
|
|
),
|
|
Expanded(
|
|
child: Center(
|
|
child: SizedBox(
|
|
width: 180.w,
|
|
child: TabBar(
|
|
controller: _tabController,
|
|
labelColor: Colors.white,
|
|
unselectedLabelColor: Colors.white54,
|
|
overlayColor: const WidgetStatePropertyAll<Color>(
|
|
Colors.transparent,
|
|
),
|
|
labelStyle: TextStyle(
|
|
fontSize: 16.sp,
|
|
fontWeight: FontWeight.w600,
|
|
),
|
|
unselectedLabelStyle: TextStyle(
|
|
fontSize: 16.sp,
|
|
fontWeight: FontWeight.w500,
|
|
),
|
|
indicator: SCFixedWidthTabIndicator(
|
|
width: 18.w,
|
|
color: SocialChatTheme.primaryLight,
|
|
height: 3.w,
|
|
borderRadius: 2.w,
|
|
),
|
|
dividerColor: Colors.transparent,
|
|
splashFactory: NoSplash.splashFactory,
|
|
tabs: [
|
|
Tab(text: localizations.official),
|
|
Tab(text: localizations.mine),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
),
|
|
SizedBox(
|
|
width: 72.w,
|
|
child: GestureDetector(
|
|
behavior: HitTestBehavior.opaque,
|
|
onTap: _openUploadPage,
|
|
child: Align(
|
|
alignment: Alignment.center,
|
|
child: Text(
|
|
localizations.custom,
|
|
style: TextStyle(
|
|
color: SocialChatTheme.primaryLight,
|
|
fontSize: 15.sp,
|
|
fontWeight: FontWeight.w600,
|
|
),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
class _RoomBackgroundGrid extends StatelessWidget {
|
|
const _RoomBackgroundGrid({
|
|
required this.items,
|
|
required this.onTap,
|
|
required this.bottomPadding,
|
|
});
|
|
|
|
final List<_RoomBackgroundItem> items;
|
|
final ValueChanged<int> onTap;
|
|
final double bottomPadding;
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return GridView.builder(
|
|
padding: EdgeInsets.fromLTRB(16.w, 16.w, 16.w, bottomPadding),
|
|
itemCount: items.length,
|
|
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
|
|
crossAxisCount: 2,
|
|
mainAxisSpacing: 14.w,
|
|
crossAxisSpacing: 14.w,
|
|
childAspectRatio: 0.64,
|
|
),
|
|
itemBuilder: (context, index) {
|
|
return _RoomBackgroundCard(
|
|
item: items[index],
|
|
onTap: () => onTap(index),
|
|
);
|
|
},
|
|
);
|
|
}
|
|
}
|
|
|
|
class _RoomBackgroundCard extends StatelessWidget {
|
|
const _RoomBackgroundCard({required this.item, required this.onTap});
|
|
|
|
final _RoomBackgroundItem item;
|
|
final VoidCallback onTap;
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final localizations = SCAppLocalizations.of(context)!;
|
|
return GestureDetector(
|
|
onTap: onTap,
|
|
child: Container(
|
|
decoration: BoxDecoration(
|
|
color: const Color(0xff18F2B1).withValues(alpha: 0.1),
|
|
borderRadius: BorderRadius.circular(12.w),
|
|
border: Border.all(
|
|
color:
|
|
item.inUse
|
|
? SocialChatTheme.primaryLight
|
|
: Colors.white.withValues(alpha: 0.08),
|
|
width: 1.w,
|
|
),
|
|
),
|
|
child: Stack(
|
|
children: [
|
|
Column(
|
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
|
children: [
|
|
Expanded(
|
|
child: Padding(
|
|
padding: EdgeInsets.all(10.w),
|
|
child: ClipRRect(
|
|
borderRadius: BorderRadius.circular(10.w),
|
|
child: _buildPreview(context),
|
|
),
|
|
),
|
|
),
|
|
Padding(
|
|
padding: EdgeInsets.fromLTRB(10.w, 0, 10.w, 12.w),
|
|
child: Text(
|
|
localizations.staticOrGifImage,
|
|
textAlign: TextAlign.center,
|
|
maxLines: 1,
|
|
overflow: TextOverflow.ellipsis,
|
|
style: TextStyle(
|
|
color: Colors.white,
|
|
fontSize: 13.sp,
|
|
fontWeight: FontWeight.w500,
|
|
),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
if (item.inUse)
|
|
PositionedDirectional(
|
|
top: 10.w,
|
|
start: 10.w,
|
|
child: Container(
|
|
padding: EdgeInsets.symmetric(horizontal: 8.w, vertical: 4.w),
|
|
decoration: BoxDecoration(
|
|
color: SocialChatTheme.primaryLight,
|
|
borderRadius: BorderRadius.circular(999.w),
|
|
),
|
|
child: Text(
|
|
localizations.inUse,
|
|
style: TextStyle(
|
|
color: const Color(0xff09372E),
|
|
fontSize: 11.sp,
|
|
fontWeight: FontWeight.w700,
|
|
),
|
|
),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
Widget _buildPreview(BuildContext context) {
|
|
final localizations = SCAppLocalizations.of(context)!;
|
|
if ((item.localImagePath ?? "").isNotEmpty) {
|
|
final file = File(item.localImagePath!);
|
|
if (file.existsSync()) {
|
|
return Image.file(file, fit: BoxFit.cover);
|
|
}
|
|
}
|
|
|
|
return DecoratedBox(
|
|
decoration: BoxDecoration(
|
|
gradient: LinearGradient(
|
|
begin: Alignment.topCenter,
|
|
end: Alignment.bottomCenter,
|
|
colors: [const Color(0xff0F4C40), const Color(0xff0B2823)],
|
|
),
|
|
),
|
|
child: Stack(
|
|
children: [
|
|
Center(
|
|
child: Icon(
|
|
Icons.image_outlined,
|
|
size: 34.w,
|
|
color: Colors.white.withValues(alpha: 0.45),
|
|
),
|
|
),
|
|
Center(
|
|
child: Padding(
|
|
padding: EdgeInsets.symmetric(horizontal: 12.w),
|
|
child: Text(
|
|
localizations.staticOrGifImage,
|
|
textAlign: TextAlign.center,
|
|
style: TextStyle(
|
|
color: Colors.white.withValues(alpha: 0.72),
|
|
fontSize: 12.sp,
|
|
fontWeight: FontWeight.w500,
|
|
),
|
|
),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
class _RoomBackgroundItem {
|
|
_RoomBackgroundItem({this.localImagePath, this.inUse = false});
|
|
|
|
final String? localImagePath;
|
|
bool inUse;
|
|
}
|