mirror of
https://github.com/cypherstack/stack_wallet.git
synced 2025-01-10 12:44:31 +00:00
various fixes, layout tweaks, and refactoring
This commit is contained in:
parent
6ed6ffb18b
commit
6990d60b9b
4 changed files with 234 additions and 100 deletions
|
@ -1645,7 +1645,9 @@ class StackTheme {
|
|||
backgroundInt: parseColor(json["colors"]["background"] as String),
|
||||
backgroundAppBarInt:
|
||||
parseColor(json["colors"]["background_app_bar"] as String),
|
||||
gradientBackgroundString: json["colors"]["gradients"] as String?,
|
||||
gradientBackgroundString: json["colors"]["gradients"] != null
|
||||
? jsonEncode(json["colors"]["gradients"])
|
||||
: null,
|
||||
standardBoxShadowString:
|
||||
jsonEncode(json["colors"]["box_shadows"]["standard"] as Map),
|
||||
homeViewButtonBarBoxShadowString:
|
||||
|
|
|
@ -1,24 +1,25 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:stackwallet/pages/settings_views/global_settings_view/appearance_settings/sub_widgets/stack_theme_card.dart';
|
||||
import 'package:stackwallet/themes/stack_colors.dart';
|
||||
import 'package:stackwallet/themes/theme_service.dart';
|
||||
import 'package:stackwallet/utilities/text_styles.dart';
|
||||
import 'package:stackwallet/utilities/util.dart';
|
||||
import 'package:stackwallet/widgets/conditional_parent.dart';
|
||||
import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart';
|
||||
import 'package:stackwallet/widgets/desktop/primary_button.dart';
|
||||
import 'package:stackwallet/widgets/desktop/secondary_button.dart';
|
||||
import 'package:stackwallet/widgets/rounded_container.dart';
|
||||
import 'package:stackwallet/widgets/rounded_white_container.dart';
|
||||
import 'package:stackwallet/widgets/loading_indicator.dart';
|
||||
|
||||
class ManageThemesView extends StatefulWidget {
|
||||
class ManageThemesView extends ConsumerStatefulWidget {
|
||||
const ManageThemesView({Key? key}) : super(key: key);
|
||||
|
||||
static const String routeName = "/manageThemes";
|
||||
|
||||
@override
|
||||
State<ManageThemesView> createState() => _ManageThemesViewState();
|
||||
ConsumerState<ManageThemesView> createState() => _ManageThemesViewState();
|
||||
}
|
||||
|
||||
class _ManageThemesViewState extends State<ManageThemesView> {
|
||||
class _ManageThemesViewState extends ConsumerState<ManageThemesView> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ConditionalParent(
|
||||
|
@ -36,105 +37,64 @@ class _ManageThemesViewState extends State<ManageThemesView> {
|
|||
style: STextStyles.navBarTitle(context),
|
||||
),
|
||||
),
|
||||
body: SingleChildScrollView(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 16,
|
||||
body: Column(
|
||||
children: [
|
||||
Expanded(
|
||||
child: SingleChildScrollView(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 16,
|
||||
),
|
||||
child: IntrinsicHeight(
|
||||
child: child,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
child: child,
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: SecondaryButton(
|
||||
label: "Install theme file",
|
||||
onPressed: () {},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
const SizedBox(
|
||||
height: 16,
|
||||
),
|
||||
GridView.builder(
|
||||
shrinkWrap: true,
|
||||
primary: false,
|
||||
itemCount: 100,
|
||||
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
|
||||
crossAxisCount: 2,
|
||||
crossAxisSpacing: 16,
|
||||
mainAxisSpacing: 16,
|
||||
childAspectRatio: 2 / 2.7,
|
||||
),
|
||||
itemBuilder: (_, index) {
|
||||
return StackThemeCard(
|
||||
name: index.toString(),
|
||||
size: "lol GB",
|
||||
);
|
||||
FutureBuilder(
|
||||
future: ref.watch(pThemeService).fetchThemes(),
|
||||
builder: (
|
||||
context,
|
||||
AsyncSnapshot<List<StackThemeMetaData>> snapshot,
|
||||
) {
|
||||
if (snapshot.connectionState == ConnectionState.done &&
|
||||
snapshot.hasData) {
|
||||
return Wrap(
|
||||
spacing: 16,
|
||||
runSpacing: 16,
|
||||
children: snapshot.data!
|
||||
.map(
|
||||
(e) => SizedBox(
|
||||
width: (MediaQuery.of(context).size.width - 48) / 2,
|
||||
child: StackThemeCard(
|
||||
data: e,
|
||||
),
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
);
|
||||
} else {
|
||||
return Center(
|
||||
child: LoadingIndicator(
|
||||
width: (MediaQuery.of(context).size.width - 48) / 2,
|
||||
),
|
||||
);
|
||||
}
|
||||
},
|
||||
),
|
||||
const SizedBox(
|
||||
height: 28,
|
||||
),
|
||||
SecondaryButton(
|
||||
label: "Install theme file",
|
||||
onPressed: () {},
|
||||
),
|
||||
const SizedBox(
|
||||
height: 16,
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class StackThemeCard extends StatefulWidget {
|
||||
const StackThemeCard({
|
||||
Key? key,
|
||||
required this.name,
|
||||
required this.size,
|
||||
}) : super(key: key);
|
||||
|
||||
final String name;
|
||||
final String size;
|
||||
|
||||
@override
|
||||
State<StackThemeCard> createState() => _StackThemeCardState();
|
||||
}
|
||||
|
||||
class _StackThemeCardState extends State<StackThemeCard> {
|
||||
String buttonLabel = "Download";
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return RoundedWhiteContainer(
|
||||
child: Column(
|
||||
children: [
|
||||
const Padding(
|
||||
padding: EdgeInsets.symmetric(
|
||||
horizontal: 18,
|
||||
),
|
||||
child: AspectRatio(
|
||||
aspectRatio: 1,
|
||||
child: RoundedContainer(
|
||||
color: Colors.grey,
|
||||
radiusMultiplier: 100,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 12,
|
||||
),
|
||||
Text(
|
||||
widget.name,
|
||||
),
|
||||
const SizedBox(
|
||||
height: 6,
|
||||
),
|
||||
Text(
|
||||
widget.size,
|
||||
),
|
||||
const Spacer(),
|
||||
PrimaryButton(
|
||||
label: buttonLabel,
|
||||
buttonHeight: ButtonHeight.l,
|
||||
onPressed: () {},
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
|
|
|
@ -0,0 +1,167 @@
|
|||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:isar/isar.dart';
|
||||
import 'package:stackwallet/models/isar/stack_theme.dart';
|
||||
import 'package:stackwallet/providers/db/main_db_provider.dart';
|
||||
import 'package:stackwallet/themes/theme_service.dart';
|
||||
import 'package:stackwallet/utilities/logger.dart';
|
||||
import 'package:stackwallet/utilities/show_loading.dart';
|
||||
import 'package:stackwallet/widgets/desktop/primary_button.dart';
|
||||
import 'package:stackwallet/widgets/rounded_white_container.dart';
|
||||
import 'package:stackwallet/widgets/stack_dialog.dart';
|
||||
|
||||
class StackThemeCard extends ConsumerStatefulWidget {
|
||||
const StackThemeCard({
|
||||
Key? key,
|
||||
required this.data,
|
||||
}) : super(key: key);
|
||||
|
||||
final StackThemeMetaData data;
|
||||
|
||||
@override
|
||||
ConsumerState<StackThemeCard> createState() => _StackThemeCardState();
|
||||
}
|
||||
|
||||
class _StackThemeCardState extends ConsumerState<StackThemeCard> {
|
||||
String buttonLabel = "Download";
|
||||
|
||||
late bool _hasTheme;
|
||||
|
||||
Future<bool> _downloadAndInstall() async {
|
||||
final service = ref.read(pThemeService);
|
||||
|
||||
try {
|
||||
final data = await service.fetchTheme(
|
||||
themeMetaData: widget.data,
|
||||
);
|
||||
|
||||
await service.install(themeArchive: data);
|
||||
return true;
|
||||
} catch (e, s) {
|
||||
Logging.instance.log(
|
||||
"Failed _downloadAndInstall of ${widget.data.id}: $e\n$s",
|
||||
level: LogLevel.Warning,
|
||||
);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _downloadPressed() async {
|
||||
final result = await showLoading(
|
||||
whileFuture: _downloadAndInstall(),
|
||||
context: context,
|
||||
message: "Downloading and installing theme...",
|
||||
);
|
||||
|
||||
if (mounted) {
|
||||
final message = result
|
||||
? "${widget.data.name} theme installed!"
|
||||
: "Failed to install ${widget.data.name} theme";
|
||||
await showDialog<void>(
|
||||
context: context,
|
||||
builder: (_) => StackOkDialog(
|
||||
title: message,
|
||||
onOkPressed: (_) {
|
||||
setState(() {
|
||||
_hasTheme = result;
|
||||
});
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
late final StreamSubscription<void> _subscription;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
_hasTheme = ref
|
||||
.read(mainDBProvider)
|
||||
.isar
|
||||
.stackThemes
|
||||
.where()
|
||||
.themeIdEqualTo(widget.data.id)
|
||||
.countSync() >
|
||||
0;
|
||||
|
||||
_subscription = ref
|
||||
.read(mainDBProvider)
|
||||
.isar
|
||||
.stackThemes
|
||||
.watchLazy()
|
||||
.listen((event) async {
|
||||
final hasTheme = (await ref
|
||||
.read(mainDBProvider)
|
||||
.isar
|
||||
.stackThemes
|
||||
.where()
|
||||
.themeIdEqualTo(widget.data.id)
|
||||
.count()) >
|
||||
0;
|
||||
if (_hasTheme != hasTheme && mounted) {
|
||||
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
|
||||
setState(() {
|
||||
_hasTheme = hasTheme;
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
_subscription.resume();
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_subscription.cancel();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return RoundedWhiteContainer(
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 18,
|
||||
),
|
||||
child: AspectRatio(
|
||||
aspectRatio: 1,
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.circular(100),
|
||||
child: Image.network(
|
||||
widget.data.previewImageUrl,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 12,
|
||||
),
|
||||
Text(
|
||||
widget.data.name,
|
||||
),
|
||||
const SizedBox(
|
||||
height: 6,
|
||||
),
|
||||
Text(
|
||||
widget.data.size,
|
||||
),
|
||||
const SizedBox(
|
||||
height: 12,
|
||||
),
|
||||
PrimaryButton(
|
||||
label: buttonLabel,
|
||||
enabled: !_hasTheme,
|
||||
buttonHeight: ButtonHeight.l,
|
||||
onPressed: _downloadPressed,
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -117,7 +117,7 @@ class ThemeService {
|
|||
}
|
||||
}
|
||||
|
||||
Future<List<StackThemeMetaData>> fetchThemeList() async {
|
||||
Future<List<StackThemeMetaData>> fetchThemes() async {
|
||||
try {
|
||||
final response = await get(Uri.parse("$baseServerUrl/themes"));
|
||||
|
||||
|
@ -125,6 +125,7 @@ class ThemeService {
|
|||
|
||||
final result = List<Map<String, dynamic>>.from(jsonList)
|
||||
.map((e) => StackThemeMetaData.fromMap(e))
|
||||
.where((e) => e.id != "light" && e.id != "dark")
|
||||
.toList();
|
||||
|
||||
return result;
|
||||
|
@ -178,12 +179,14 @@ class StackThemeMetaData {
|
|||
final String name;
|
||||
final String id;
|
||||
final String sha256;
|
||||
final String size;
|
||||
final String previewImageUrl;
|
||||
|
||||
StackThemeMetaData({
|
||||
required this.name,
|
||||
required this.id,
|
||||
required this.sha256,
|
||||
required this.size,
|
||||
required this.previewImageUrl,
|
||||
});
|
||||
|
||||
|
@ -193,6 +196,7 @@ class StackThemeMetaData {
|
|||
name: map["name"] as String,
|
||||
id: map["id"] as String,
|
||||
sha256: map["sha256"] as String,
|
||||
size: map["size"] as String,
|
||||
previewImageUrl: map["previewImageUrl"] as String,
|
||||
);
|
||||
} catch (e, s) {
|
||||
|
@ -210,6 +214,7 @@ class StackThemeMetaData {
|
|||
"name: $name, "
|
||||
"id: $id, "
|
||||
"sha256: $sha256, "
|
||||
"size: $size, "
|
||||
"previewImageUrl: $previewImageUrl"
|
||||
")";
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue