398 lines
12 KiB
Dart
398 lines
12 KiB
Dart
import 'dart:convert';
|
|
import 'dart:developer';
|
|
|
|
import 'package:auto_route/auto_route.dart';
|
|
import 'package:flutter/cupertino.dart';
|
|
import 'package:flutter/foundation.dart';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:flutter/widgets.dart';
|
|
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
|
import 'package:mnemo_cards/features/packs/pack_manager.dart';
|
|
import 'package:mnemo_cards/managers/user_state_holder.dart';
|
|
import 'package:mnemo_cards/utils/string_helper.dart';
|
|
import 'package:mnemo_cards/widgets/header.dart';
|
|
import 'package:mnemo_cards/widgets/shared_pref_button.dart';
|
|
import 'package:mnemo_cards_common/mnemo_cards_common.dart';
|
|
import 'package:shimmer/shimmer.dart';
|
|
|
|
import '../admin/add_package.dart';
|
|
import '../di/locator.dart';
|
|
import '../domain/router/app_router.dart';
|
|
import '../domain/router/app_router.gr.dart';
|
|
import '../flags.dart';
|
|
import '../managers/repository/repository.dart';
|
|
import '../theme/themes.dart';
|
|
import 'package:collection/collection.dart';
|
|
|
|
class PacksMenuWidget extends StatefulWidget {
|
|
final Repository repository;
|
|
final PackManager packManager;
|
|
final ScrollController? scrollController;
|
|
|
|
const PacksMenuWidget(
|
|
this.repository,
|
|
this.packManager, {
|
|
this.scrollController,
|
|
super.key,
|
|
});
|
|
|
|
@override
|
|
State<StatefulWidget> createState() => _PacksMenuWidgetState();
|
|
}
|
|
|
|
class _PacksMenuWidgetState extends State<PacksMenuWidget> {
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return LayoutBuilder(builder: (context, constraints) {
|
|
final cardHeight = 130.h;
|
|
final theme = Theme.of(context);
|
|
|
|
return StreamBuilder(
|
|
stream: widget.packManager.packsPreviewStream.asyncMap((packs) async {
|
|
if (packs != null) {
|
|
await _precache(packs);
|
|
}
|
|
return packs;
|
|
}),
|
|
builder: (context, snapshot) {
|
|
return Column(
|
|
children: [
|
|
Header(
|
|
'Темы',
|
|
trail: GestureDetector(
|
|
onTap: () {
|
|
AppRouter.openAuthOrProfile();
|
|
},
|
|
child: Image.asset(
|
|
'icons/profile.png',
|
|
width: 27.w,
|
|
height: 27.h,
|
|
),
|
|
),
|
|
),
|
|
if (ADMIN_BUILD)
|
|
Column(
|
|
children: [
|
|
GestureDetector(
|
|
onTap: () {
|
|
locator.packManager.clearCache();
|
|
},
|
|
child: Container(
|
|
alignment: Alignment.center,
|
|
color: Colors.white,
|
|
margin: EdgeInsets.all(8.0),
|
|
child: Text('Clear cache'),
|
|
height: 40.h,
|
|
),
|
|
),
|
|
SharedPrefButton(
|
|
enabledWidget: Text('PROD'),
|
|
disabledWidget: Text('TEST'),
|
|
spKey: 'env',
|
|
),
|
|
],
|
|
),
|
|
Expanded(
|
|
child: Padding(
|
|
padding: const EdgeInsets.all(8.0),
|
|
child: RefreshIndicator(
|
|
onRefresh: locator.previewPackPoller.poll,
|
|
backgroundColor: Colors.white,
|
|
color: snapshot.data?.firstOrNull?.color?.asColor ??
|
|
Colors.black,
|
|
child: ListView(
|
|
physics: BouncingScrollPhysics(
|
|
decelerationRate: ScrollDecelerationRate.fast,
|
|
parent: AlwaysScrollableScrollPhysics()
|
|
),
|
|
scrollDirection: Axis.vertical,
|
|
children: [
|
|
if (snapshot.data == null)
|
|
...[1, 2, 3, 4].map(
|
|
(e) => _PackButton4Shimmer(
|
|
constraints.maxWidth,
|
|
cardHeight,
|
|
),
|
|
),
|
|
if (snapshot.hasData)
|
|
...snapshot.data!
|
|
.map((pack) => _PackButton4(pack, cardHeight)),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
),
|
|
],
|
|
);
|
|
},
|
|
);
|
|
});
|
|
}
|
|
|
|
Future<void> _precache(List<CardPackPreviewDto> packs) async {
|
|
for (final pack in packs) {
|
|
if (pack.imageBase64 != null) {
|
|
try {
|
|
final bytes = base64Decode(pack.imageBase64!);
|
|
final image = MemoryImage(bytes);
|
|
locator.imagesHolder.setImage('pack_${pack.id}', image);
|
|
await precacheImage(image, context);
|
|
} catch (e) {
|
|
log('${pack.id} cover not cached');
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
class _PackButton4 extends StatelessWidget {
|
|
final CardPackPreviewDto pack;
|
|
final double cardHeight;
|
|
|
|
const _PackButton4(
|
|
this.pack,
|
|
this.cardHeight,
|
|
);
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final theme = Theme.of(context);
|
|
|
|
return InkWell(
|
|
onTap: () {
|
|
AutoRouter.of(context).push(
|
|
PageRouteInfo(
|
|
CardPackPage.name,
|
|
args: CardPackPageArgs(
|
|
previewDto: pack,
|
|
),
|
|
),
|
|
);
|
|
},
|
|
child: Container(
|
|
margin: EdgeInsets.all(4.0.h),
|
|
alignment: Alignment.center,
|
|
height: cardHeight,
|
|
decoration: BoxDecoration(
|
|
color: Colors.white,
|
|
border: Border.all(
|
|
color: pack.color?.asColor?.withOpacity(0.9) ??
|
|
Colors.grey.withOpacity(0.5),
|
|
),
|
|
borderRadius: BorderRadius.circular(12.0),
|
|
),
|
|
child: Row(
|
|
mainAxisSize: MainAxisSize.max,
|
|
children: [
|
|
Container(
|
|
decoration: BoxDecoration(
|
|
// border: Border.all(
|
|
// color: pack.dto.color?.asColor?.withOpacity(0.9) ??
|
|
// Colors.grey.withOpacity(0.5),
|
|
// ),
|
|
// borderRadius: BorderRadius.circular(12.0),
|
|
image: pack.imageBase64 == null
|
|
? null
|
|
: DecorationImage(
|
|
image: locator.imagesHolder.get('pack_${pack.id}') ??
|
|
MemoryImage(
|
|
base64Decode(pack.imageBase64!),
|
|
),
|
|
),
|
|
),
|
|
margin: EdgeInsets.all(2.0.w),
|
|
width: cardHeight,
|
|
height: cardHeight,
|
|
),
|
|
Expanded(
|
|
child: Padding(
|
|
padding: const EdgeInsets.all(8.0),
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
FittedBox(
|
|
fit: BoxFit.scaleDown,
|
|
child: Text(
|
|
pack.title,
|
|
style: TextStyle(
|
|
fontWeight: FontWeight.w500,
|
|
fontSize: 24.sp,
|
|
height: 0.9,
|
|
),
|
|
),
|
|
),
|
|
if (pack.subtitle != null && pack.subtitle!.isNotEmpty)
|
|
FittedBox(
|
|
fit: BoxFit.scaleDown,
|
|
child: Text(
|
|
pack.subtitle!,
|
|
style: TextStyle(
|
|
fontWeight: FontWeight.w300,
|
|
fontSize: 16.sp,
|
|
),
|
|
),
|
|
),
|
|
Spacer(),
|
|
Row(
|
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
children: [
|
|
Expanded(
|
|
child: Row(
|
|
children: [
|
|
Text(
|
|
pack.cards.toString(),
|
|
style: TextStyle(
|
|
fontWeight: FontWeight.w200,
|
|
fontSize: 15.sp,
|
|
),
|
|
),
|
|
Image.asset(
|
|
'icons/cards.png',
|
|
width: 18.w,
|
|
height: 16.h,
|
|
)
|
|
],
|
|
),
|
|
),
|
|
if (pack.price != null && !pack.isAvailable)
|
|
Text(
|
|
pack.price!,
|
|
style: TextStyle(
|
|
fontWeight: FontWeight.w400,
|
|
fontSize: 20.sp,
|
|
),
|
|
),
|
|
],
|
|
)
|
|
],
|
|
),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
class _PackButton4Shimmer extends StatelessWidget {
|
|
final double cardHeight;
|
|
final double cardWidth;
|
|
|
|
const _PackButton4Shimmer(
|
|
this.cardWidth,
|
|
this.cardHeight,
|
|
);
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return Shimmer.fromColors(
|
|
baseColor: Colors.white,
|
|
highlightColor: borderGray,
|
|
child: Container(
|
|
alignment: Alignment.center,
|
|
height: cardHeight,
|
|
decoration: BoxDecoration(
|
|
color: Colors.white,
|
|
border: Border.all(
|
|
color: Colors.grey.withOpacity(0.5),
|
|
),
|
|
borderRadius: BorderRadius.circular(12.0),
|
|
),
|
|
child: Row(
|
|
mainAxisSize: MainAxisSize.max,
|
|
children: [
|
|
Container(
|
|
color: Colors.white,
|
|
width: cardHeight,
|
|
height: cardHeight,
|
|
),
|
|
Expanded(
|
|
child: Padding(
|
|
padding: const EdgeInsets.all(8.0),
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Container(
|
|
height: 30,
|
|
width: (cardWidth - cardHeight) * 0.7,
|
|
color: Colors.white,
|
|
),
|
|
Container(
|
|
height: 20,
|
|
width: (cardWidth - cardHeight) * 0.5,
|
|
color: Colors.white,
|
|
),
|
|
Spacer(),
|
|
Row(
|
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
children: [
|
|
Container(
|
|
height: 20,
|
|
width: (cardWidth - cardHeight) * 0.1,
|
|
color: Colors.white,
|
|
),
|
|
Container(
|
|
height: 25,
|
|
width: (cardWidth - cardHeight) * 0.1,
|
|
color: Colors.white,
|
|
),
|
|
],
|
|
)
|
|
],
|
|
),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
class _PackButtonShimmer extends StatelessWidget {
|
|
final double cardWidth;
|
|
final double cardHeight;
|
|
|
|
const _PackButtonShimmer(
|
|
this.cardWidth,
|
|
this.cardHeight,
|
|
);
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return Shimmer.fromColors(
|
|
baseColor: Colors.white,
|
|
highlightColor: Colors.grey[200]!,
|
|
child: Container(
|
|
width: cardWidth,
|
|
height: cardHeight,
|
|
child: Padding(
|
|
padding: const EdgeInsets.all(12.0),
|
|
child: Column(
|
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
children: [
|
|
Container(
|
|
alignment: Alignment.center,
|
|
width: cardWidth,
|
|
height: cardWidth,
|
|
decoration: BoxDecoration(
|
|
color: Colors.white,
|
|
borderRadius: BorderRadius.circular(12.0),
|
|
)),
|
|
Container(
|
|
decoration: BoxDecoration(
|
|
borderRadius: BorderRadius.all(Radius.circular(8.0)),
|
|
color: Colors.white,
|
|
),
|
|
width: cardWidth * 0.7,
|
|
height: 30,
|
|
alignment: Alignment.center,
|
|
)
|
|
],
|
|
),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
}
|