dev
dart 208 lines 6.38 KB
Raw
1 import 'dart:convert';
2 import 'dart:io';
3
4 import 'package:cake_wallet/generated/i18n.dart';
5 import 'package:cake_wallet/new-ui/widgets/new_primary_button.dart';
6 import 'package:cake_wallet/new-ui/widgets/receive_page/receive_top_bar.dart';
7 import 'package:cake_wallet/src/widgets/cake_image_widget.dart';
8 import 'package:flutter/material.dart';
9 import 'package:flutter/services.dart';
10 import 'package:flutter_svg/flutter_svg.dart';
11 import 'package:url_launcher/url_launcher.dart';
12
13 const changelogIconLocation = "assets/new-ui/changelog/icons";
14 const changelogTextLocation = "assets/new-ui/changelog/text";
15
16 class ChangelogItem {
17 final String iconFilename;
18 final String title;
19 final String description;
20
21 ChangelogItem(this.iconFilename, this.title, this.description);
22 }
23
24 class ChangelogModal extends StatefulWidget {
25 const ChangelogModal({super.key, required this.version});
26
27 final String version;
28
29 @override
30 State<ChangelogModal> createState() => _ChangelogModalState();
31 }
32
33 class _ChangelogModalState extends State<ChangelogModal> {
34 List<ChangelogItem> _items = [];
35
36 @override
37 void initState() {
38 super.initState();
39 loadChangelog();
40 }
41
42 void loadChangelog() async {
43 String lang = WidgetsBinding.instance.platformDispatcher.locale.languageCode;
44 if (lang == "und" ||
45 lang.isEmpty ||
46 !(await File("$changelogTextLocation/changelog_$lang.json").exists())) {
47 lang = "en";
48 }
49
50 final List<dynamic> changelog =
51 jsonDecode(await rootBundle.loadString("$changelogTextLocation/changelog_$lang.json"))
52 as List<dynamic>;
53
54 for (final item in changelog) {
55 final itemMap = item as Map<String, dynamic>;
56 _items.add(ChangelogItem(
57 itemMap["icon"] as String? ?? "",
58 itemMap["title"] as String? ?? "",
59 itemMap["description"] as String? ?? "",
60 ));
61 }
62 setState(() {});
63 }
64
65 @override
66 Widget build(BuildContext context) {
67 if (_items.isEmpty) return SizedBox.shrink();
68
69 return Container(
70 decoration: BoxDecoration(
71 color: Theme.of(context).colorScheme.surface,
72 borderRadius: BorderRadius.vertical(top: Radius.circular(20)),
73 ),
74 child: SafeArea(
75 child: Column(
76 mainAxisSize: MainAxisSize.min,
77 spacing: 12,
78 children: [
79 SizedBox(),
80 ModalTopBar(title: S.of(context).whats_new),
81 SizedBox(),
82 Flexible(
83 child: SingleChildScrollView(
84 child: Column(
85 children: [
86 VersionNumberHeader(version: widget.version),
87 SizedBox(height: 40),
88 Column(
89 crossAxisAlignment: CrossAxisAlignment.start,
90 spacing: 32,
91 children: _items.map((item) => ChangelogItemWidget(item: item)).toList(),
92 ),
93 SizedBox(height: 32),
94 Text(
95 S.of(context).and_much_more_to_come,
96 style: TextStyle(color: Theme.of(context).colorScheme.onSurfaceVariant),
97 )
98 ],
99 ),
100 ),
101 ),
102 Padding(
103 padding: const EdgeInsets.all(16.0),
104 child: Column(
105 spacing: 12,
106 children: [
107 NewPrimaryButton(
108 onPressed: () {
109 try {
110 launchUrl(Uri.https("docs.cakewallet.com", "/release-notes"));
111 } catch (_) {}
112 },
113 text: S.of(context).view_more_info,
114 color: Theme.of(context).colorScheme.surfaceContainer,
115 textColor: Theme.of(context).colorScheme.primary),
116 NewPrimaryButton(
117 onPressed: Navigator.of(context).pop,
118 text: S.of(context).continue_text,
119 color: Theme.of(context).colorScheme.primary,
120 textColor: Theme.of(context).colorScheme.onPrimary),
121 ],
122 ),
123 )
124 ],
125 ),
126 ),
127 );
128 }
129 }
130
131 class VersionNumberHeader extends StatelessWidget {
132 VersionNumberHeader({super.key, required this.version});
133
134 final String version;
135
136 @override
137 Widget build(BuildContext context) {
138 return Container(
139 decoration: BoxDecoration(
140 border: Border.all(color: Theme.of(context).colorScheme.primary, width: 2),
141 borderRadius: BorderRadius.circular(99999999)),
142 child: Padding(
143 padding: const EdgeInsets.symmetric(vertical: 8.0, horizontal: 16),
144 child: Row(
145 spacing: 8,
146 mainAxisSize: MainAxisSize.min,
147 children: [
148 CakeImageWidget(
149 imageUrl: "assets/images/cake_logo_dark.svg",
150 height: 32,
151 width: 32,
152 colorFilter:
153 ColorFilter.mode(Theme.of(context).colorScheme.onSurface, BlendMode.srcIn),
154 ),
155 Text(
156 version,
157 style: TextStyle(color: Theme.of(context).colorScheme.onSurface, fontSize: 36),
158 )
159 ],
160 ),
161 ),
162 );
163 }
164 }
165
166 class ChangelogItemWidget extends StatelessWidget {
167 const ChangelogItemWidget({super.key, required this.item});
168
169 final ChangelogItem item;
170
171 @override
172 Widget build(BuildContext context) {
173 return Row(
174 mainAxisSize: MainAxisSize.min,
175 spacing: 12,
176 children: [
177 if (item.iconFilename.isNotEmpty)
178 CakeImageWidget(
179 imageUrl: "$changelogIconLocation/${item.iconFilename}.svg",
180 height: 36,
181 width: 36,
182 colorFilter: ColorFilter.mode(Theme.of(context).colorScheme.primary, BlendMode.srcIn),
183 ),
184 Expanded(
185 child: Column(
186 crossAxisAlignment: CrossAxisAlignment.start,
187 spacing: 4,
188 children: [
189 if (item.title.isNotEmpty)
190 Text(
191 item.title,
192 style: TextStyle(fontWeight: FontWeight.w500),
193 ),
194 if (item.description.isNotEmpty)
195 Text(
196 item.description,
197 style: TextStyle(
198 color: Theme.of(context).colorScheme.onSurfaceVariant,
199 ),
200 )
201 ],
202 ),
203 )
204 ],
205 );
206 }
207 }
208