307 lines
9.5 KiB
Dart
307 lines
9.5 KiB
Dart
import 'dart:math' as math;
|
|
|
|
import 'package:flutter/material.dart';
|
|
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
|
import 'package:provider/provider.dart';
|
|
import 'package:sail/entity/plan_entity.dart';
|
|
import 'package:sail/models/user_model.dart';
|
|
import 'package:sail/service/plan_service.dart';
|
|
import 'package:sail/service/user_service.dart';
|
|
import 'package:sail/utils/navigator_util.dart';
|
|
|
|
class SlidingCardsView extends StatefulWidget {
|
|
const SlidingCardsView({Key? key}) : super(key: key);
|
|
|
|
@override
|
|
SlidingCardsViewState createState() => SlidingCardsViewState();
|
|
}
|
|
|
|
class SlidingCardsViewState extends State<SlidingCardsView> {
|
|
late PageController pageController;
|
|
double pageOffset = 0;
|
|
List<PlanEntity> _planEntityList = [];
|
|
|
|
@override
|
|
void initState() {
|
|
super.initState();
|
|
pageController = PageController(viewportFraction: 0.8);
|
|
pageController.addListener(() {
|
|
setState(() => pageOffset = pageController.page!);
|
|
});
|
|
|
|
PlanService().plan()?.then((planEntityList) {
|
|
if (this.mounted) {
|
|
setState(() {
|
|
_planEntityList = planEntityList;
|
|
});
|
|
}
|
|
});
|
|
}
|
|
|
|
@override
|
|
void dispose() {
|
|
pageController.dispose();
|
|
super.dispose();
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return SizedBox(
|
|
height: MediaQuery.of(context).size.height * 0.55,
|
|
child: PageView(
|
|
controller: pageController,
|
|
children: List.from(_planEntityList.map((e) => SlidingCard(
|
|
id: e.id,
|
|
name: e.name,
|
|
content: e.content ?? "",
|
|
date: e.createdAt?.toIso8601String(),
|
|
onetimePrice: (e.onetimePrice ?? 0.0) / 100,
|
|
monthPrice: (e.monthPrice ?? 0.0) / 100,
|
|
quarterPrice: (e.quarterPrice ?? 0.0) / 100,
|
|
halfYearPrice: (e.halfYearPrice ?? 0.0) / 100,
|
|
yearPrice: (e.yearPrice ?? 0.0) / 100,
|
|
twoYearPrice: (e.twoYearPrice ?? 0.0) / 100,
|
|
threeYearPrice: (e.threeYearPrice ?? 0.0) / 100,
|
|
assetName: 'steve-johnson.jpeg',
|
|
offset: pageOffset)))),
|
|
);
|
|
}
|
|
}
|
|
|
|
class SlidingCard extends StatelessWidget {
|
|
final int id;
|
|
final String name;
|
|
final String content;
|
|
final String? date;
|
|
final String assetName;
|
|
final double offset;
|
|
final double onetimePrice;
|
|
final double monthPrice;
|
|
final double quarterPrice;
|
|
final double halfYearPrice;
|
|
final double yearPrice;
|
|
final double twoYearPrice;
|
|
final double threeYearPrice;
|
|
|
|
const SlidingCard({
|
|
Key? key,
|
|
required this.id,
|
|
required this.name,
|
|
required this.content,
|
|
required this.date,
|
|
required this.assetName,
|
|
required this.offset,
|
|
required this.onetimePrice,
|
|
required this.monthPrice,
|
|
required this.quarterPrice,
|
|
required this.halfYearPrice,
|
|
required this.yearPrice,
|
|
required this.twoYearPrice,
|
|
required this.threeYearPrice,
|
|
}) : super(key: key);
|
|
|
|
double lowestPrice() {
|
|
List<double> list = [
|
|
onetimePrice,
|
|
monthPrice,
|
|
quarterPrice,
|
|
halfYearPrice,
|
|
yearPrice,
|
|
twoYearPrice,
|
|
threeYearPrice,
|
|
];
|
|
|
|
double min = double.maxFinite;
|
|
|
|
for (int i = 0; i < list.length; i++) {
|
|
if ((list[i] < min) && list[i] > 0) {
|
|
min = list[i];
|
|
}
|
|
}
|
|
|
|
return min;
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
UserModel _userModel = Provider.of<UserModel>(context);
|
|
double gauss = math.exp(-(math.pow((offset.abs() - 0.5), 2) / 0.08));
|
|
return Transform.translate(
|
|
offset: Offset(-32 * gauss * offset.sign, 0),
|
|
child: Card(
|
|
margin: const EdgeInsets.only(left: 8, right: 8, bottom: 24),
|
|
elevation: 8,
|
|
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(32)),
|
|
child: Column(
|
|
children: <Widget>[
|
|
ClipRRect(
|
|
borderRadius:
|
|
const BorderRadius.vertical(top: Radius.circular(32)),
|
|
child: Container(
|
|
height: MediaQuery.of(context).size.height * 0.1,
|
|
decoration: const BoxDecoration(
|
|
gradient: LinearGradient(
|
|
begin: Alignment.centerLeft,
|
|
end: Alignment.centerRight,
|
|
colors: [Colors.red, Colors.orange, Colors.indigo]),
|
|
),
|
|
child: Center(
|
|
child: Text('${name}',
|
|
style: TextStyle(
|
|
fontWeight: FontWeight.bold,
|
|
color: Colors.white,
|
|
fontSize: 25,
|
|
))),
|
|
),
|
|
),
|
|
// const SizedBox(height: 8),
|
|
Expanded(
|
|
child: CardContent(
|
|
id: id,
|
|
name: name,
|
|
desc: content,
|
|
date: date,
|
|
offset: gauss,
|
|
lowestPrice: lowestPrice(),
|
|
),
|
|
),
|
|
GestureDetector(
|
|
onTap: () {
|
|
_userModel.checkHasLogin(
|
|
context,
|
|
() => UserService().getQuickLoginUrl(
|
|
{'redirect': "/plan/${id}"})?.then((value) {
|
|
NavigatorUtil.goWebView(
|
|
context, "购买${name}订阅", value);
|
|
}));
|
|
},
|
|
child: ClipRRect(
|
|
borderRadius:
|
|
const BorderRadius.vertical(bottom: Radius.circular(32)),
|
|
child: Container(
|
|
height: MediaQuery.of(context).size.height * 0.1,
|
|
decoration: const BoxDecoration(
|
|
gradient: LinearGradient(
|
|
begin: Alignment.centerLeft,
|
|
end: Alignment.centerRight,
|
|
colors: [Colors.orange, Colors.orange, Colors.orange]),
|
|
),
|
|
child: Center(
|
|
child: Text('点击购买 ¥${lowestPrice()} 起',
|
|
style: TextStyle(
|
|
fontWeight: FontWeight.bold,
|
|
color: Colors.white,
|
|
fontSize: 20,
|
|
))),
|
|
),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
class CardContent extends StatefulWidget {
|
|
final int id;
|
|
final String name;
|
|
final String desc;
|
|
final String? date;
|
|
final double offset;
|
|
final double lowestPrice;
|
|
|
|
const CardContent(
|
|
{Key? key,
|
|
required this.id,
|
|
required this.name,
|
|
required this.desc,
|
|
required this.date,
|
|
required this.offset,
|
|
required this.lowestPrice})
|
|
: super(key: key);
|
|
|
|
@override
|
|
CardContentState createState() => CardContentState();
|
|
}
|
|
|
|
class CardContentState extends State<CardContent> {
|
|
late UserModel _userModel;
|
|
|
|
@override
|
|
void didChangeDependencies() {
|
|
super.didChangeDependencies();
|
|
_userModel = Provider.of<UserModel>(context);
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return Padding(
|
|
padding: const EdgeInsets.all(8.0),
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: <Widget>[
|
|
Transform.translate(
|
|
offset: Offset(8 * widget.offset, 0),
|
|
child: Text(widget.desc,
|
|
style:
|
|
const TextStyle(fontSize: 20, fontWeight: FontWeight.bold)),
|
|
),
|
|
const SizedBox(height: 8),
|
|
// Transform.translate(
|
|
// offset: Offset(32 * widget.offset, 0),
|
|
// child: Text(
|
|
// widget.date!,
|
|
// style: const TextStyle(
|
|
// color: Colors.grey, fontWeight: FontWeight.bold),
|
|
// ),
|
|
// ),
|
|
// const Spacer(),
|
|
// Row(
|
|
// children: <Widget>[
|
|
// Transform.translate(
|
|
// offset: Offset(48 * widget.offset, 0),
|
|
// child: ElevatedButton(
|
|
// style: ElevatedButton.styleFrom(
|
|
// foregroundColor: Colors.white,
|
|
// backgroundColor: Colors.yellow,
|
|
// shape: RoundedRectangleBorder(
|
|
// borderRadius: BorderRadius.circular(32),
|
|
// ),
|
|
// ),
|
|
// onPressed: () => _userModel.checkHasLogin(
|
|
// context,
|
|
// () => UserService().getQuickLoginUrl({
|
|
// 'redirect': "/plan/${widget.id}"
|
|
// })?.then((value) {
|
|
// NavigatorUtil.goWebView(context, "配置订阅", value);
|
|
// })),
|
|
// child: Transform.translate(
|
|
// offset: Offset(24 * widget.offset, 0),
|
|
// child: Text('购买',
|
|
// style: TextStyle(
|
|
// color: Colors.black87,
|
|
// fontSize: ScreenUtil().setSp(36))),
|
|
// ),
|
|
// ),
|
|
// ),
|
|
// const Spacer(),
|
|
// Transform.translate(
|
|
// offset: Offset(32 * widget.offset, 0),
|
|
// child: Text(
|
|
// '¥ ${widget.lowestPrice} 起',
|
|
// style: const TextStyle(
|
|
// fontWeight: FontWeight.bold,
|
|
// fontSize: 20,
|
|
// ),
|
|
// ),
|
|
// ),
|
|
// const SizedBox(width: 16),
|
|
// ],
|
|
// )
|
|
],
|
|
),
|
|
);
|
|
}
|
|
}
|