mirror of
https://github.com/cypherstack/stack_wallet.git
synced 2025-01-03 09:19:22 +00:00
Add desktop custom theme selection and download ui. As well fixed a couple bugs on the mobile version
This commit is contained in:
parent
d17da24607
commit
63fff1d644
14 changed files with 940 additions and 20 deletions
3
assets/svg/file-upload.svg
Normal file
3
assets/svg/file-upload.svg
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M14.75 1V6.5H20.25L14.75 1ZM13.375 6.5V1H5.8125C4.6734 1 3.75 1.9234 3.75 3.0625V20.9375C3.75 22.0762 4.6734 23 5.8125 23H18.1875C19.3266 23 20.25 22.0766 20.25 20.9375V7.875H14.7887C13.9895 7.875 13.375 7.26055 13.375 6.5ZM16.1293 15.7855C15.966 16.0262 15.7039 16.125 15.4375 16.125C15.1711 16.125 14.9098 16.0243 14.7083 15.8229L13.0312 14.1441V18.5312C13.0312 19.1006 12.5693 19.5625 12 19.5625C11.4307 19.5625 10.9688 19.1006 10.9688 18.5312V14.1441L9.29168 15.8212C8.88885 16.224 8.23637 16.224 7.83332 15.8212C7.43027 15.4184 7.43049 14.7659 7.83332 14.3629L11.2708 10.9254C11.6737 10.5225 12.3261 10.5225 12.7292 10.9254L16.1667 14.3629C16.5676 14.7672 16.5676 15.4203 16.1293 15.7855Z" fill="#A9ACAC"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 824 B |
3
assets/svg/file.svg
Normal file
3
assets/svg/file.svg
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
<svg width="17" height="17" viewBox="0 0 17 17" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M8.16667 2.41699V4.83366C8.16667 6.03104 9.13595 7.00033 10.3333 7.00033H12.75V14.0003C12.75 14.3212 12.4875 14.5837 12.1667 14.5837H4.83333C4.51169 14.5837 4.25 14.3218 4.25 14.0003V3.00033C4.25 2.67805 4.51106 2.41699 4.83333 2.41699H8.16667Z" fill="#232323" stroke="#232323" stroke-width="2.5"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 411 B |
|
@ -34,7 +34,7 @@ class ManageThemesView extends ConsumerStatefulWidget {
|
||||||
class _ManageThemesViewState extends ConsumerState<ManageThemesView> {
|
class _ManageThemesViewState extends ConsumerState<ManageThemesView> {
|
||||||
late bool _showThemes;
|
late bool _showThemes;
|
||||||
|
|
||||||
Future<List<StackThemeMetaData>> future = Future(() => []);
|
Future<List<StackThemeMetaData>> Function() future = () async => [];
|
||||||
|
|
||||||
void _onInstallPressed() {
|
void _onInstallPressed() {
|
||||||
showDialog<void>(
|
showDialog<void>(
|
||||||
|
@ -46,6 +46,9 @@ class _ManageThemesViewState extends ConsumerState<ManageThemesView> {
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
_showThemes = ref.read(prefsChangeNotifierProvider).externalCalls;
|
_showThemes = ref.read(prefsChangeNotifierProvider).externalCalls;
|
||||||
|
if (_showThemes) {
|
||||||
|
future = ref.read(pThemeService).fetchThemes;
|
||||||
|
}
|
||||||
super.initState();
|
super.initState();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -121,7 +124,7 @@ class _ManageThemesViewState extends ConsumerState<ManageThemesView> {
|
||||||
child: Text(
|
child: Text(
|
||||||
"You are using Incognito Mode. Please press the"
|
"You are using Incognito Mode. Please press the"
|
||||||
" button below to load available themes from our server"
|
" button below to load available themes from our server"
|
||||||
" or upload a theme file manually from your device.",
|
" or install a theme file manually from your device.",
|
||||||
style: STextStyles.smallMed12(context),
|
style: STextStyles.smallMed12(context),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -133,7 +136,7 @@ class _ManageThemesViewState extends ConsumerState<ManageThemesView> {
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
setState(() {
|
setState(() {
|
||||||
_showThemes = true;
|
_showThemes = true;
|
||||||
future = ref.watch(pThemeService).fetchThemes();
|
future = ref.watch(pThemeService).fetchThemes;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
@ -147,8 +150,11 @@ class _ManageThemesViewState extends ConsumerState<ManageThemesView> {
|
||||||
const SizedBox(
|
const SizedBox(
|
||||||
height: 16,
|
height: 16,
|
||||||
),
|
),
|
||||||
const Expanded(
|
Expanded(
|
||||||
child: _IncognitoInstalledThemes(),
|
child: IncognitoInstalledThemes(
|
||||||
|
cardWidth:
|
||||||
|
(MediaQuery.of(context).size.width - 48) / 2,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(
|
const SizedBox(
|
||||||
height: 16,
|
height: 16,
|
||||||
|
@ -164,7 +170,7 @@ class _ManageThemesViewState extends ConsumerState<ManageThemesView> {
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
FutureBuilder(
|
FutureBuilder(
|
||||||
future: future,
|
future: future(),
|
||||||
builder: (
|
builder: (
|
||||||
context,
|
context,
|
||||||
AsyncSnapshot<List<StackThemeMetaData>> snapshot,
|
AsyncSnapshot<List<StackThemeMetaData>> snapshot,
|
||||||
|
@ -177,6 +183,7 @@ class _ManageThemesViewState extends ConsumerState<ManageThemesView> {
|
||||||
children: snapshot.data!
|
children: snapshot.data!
|
||||||
.map(
|
.map(
|
||||||
(e) => SizedBox(
|
(e) => SizedBox(
|
||||||
|
key: Key("ManageThemesView_card_${e.id}_key"),
|
||||||
width: (MediaQuery.of(context).size.width - 48) / 2,
|
width: (MediaQuery.of(context).size.width - 48) / 2,
|
||||||
child: StackThemeCard(
|
child: StackThemeCard(
|
||||||
data: e,
|
data: e,
|
||||||
|
@ -200,16 +207,21 @@ class _ManageThemesViewState extends ConsumerState<ManageThemesView> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class _IncognitoInstalledThemes extends ConsumerStatefulWidget {
|
class IncognitoInstalledThemes extends ConsumerStatefulWidget {
|
||||||
const _IncognitoInstalledThemes({Key? key}) : super(key: key);
|
const IncognitoInstalledThemes({
|
||||||
|
Key? key,
|
||||||
|
required this.cardWidth,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
final double cardWidth;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
ConsumerState<_IncognitoInstalledThemes> createState() =>
|
ConsumerState<IncognitoInstalledThemes> createState() =>
|
||||||
_IncognitoInstalledThemesState();
|
_IncognitoInstalledThemesState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _IncognitoInstalledThemesState
|
class _IncognitoInstalledThemesState
|
||||||
extends ConsumerState<_IncognitoInstalledThemes> {
|
extends ConsumerState<IncognitoInstalledThemes> {
|
||||||
late final StreamSubscription<void> _subscription;
|
late final StreamSubscription<void> _subscription;
|
||||||
|
|
||||||
List<Tuple2<String, String>> installedThemeIdNames = [];
|
List<Tuple2<String, String>> installedThemeIdNames = [];
|
||||||
|
@ -255,7 +267,8 @@ class _IncognitoInstalledThemesState
|
||||||
children: installedThemeIdNames
|
children: installedThemeIdNames
|
||||||
.map(
|
.map(
|
||||||
(e) => SizedBox(
|
(e) => SizedBox(
|
||||||
width: (MediaQuery.of(context).size.width - 48) / 2,
|
key: Key("IncognitoInstalledThemes_card_${e.item1}_key"),
|
||||||
|
width: widget.cardWidth,
|
||||||
child: StackThemeCard(
|
child: StackThemeCard(
|
||||||
data: StackThemeMetaData(
|
data: StackThemeMetaData(
|
||||||
name: e.item2,
|
name: e.item2,
|
||||||
|
|
|
@ -8,12 +8,14 @@ import 'package:isar/isar.dart';
|
||||||
import 'package:stackwallet/models/isar/stack_theme.dart';
|
import 'package:stackwallet/models/isar/stack_theme.dart';
|
||||||
import 'package:stackwallet/providers/db/main_db_provider.dart';
|
import 'package:stackwallet/providers/db/main_db_provider.dart';
|
||||||
import 'package:stackwallet/providers/global/prefs_provider.dart';
|
import 'package:stackwallet/providers/global/prefs_provider.dart';
|
||||||
|
import 'package:stackwallet/themes/stack_colors.dart';
|
||||||
import 'package:stackwallet/themes/theme_providers.dart';
|
import 'package:stackwallet/themes/theme_providers.dart';
|
||||||
import 'package:stackwallet/themes/theme_service.dart';
|
import 'package:stackwallet/themes/theme_service.dart';
|
||||||
import 'package:stackwallet/utilities/logger.dart';
|
import 'package:stackwallet/utilities/logger.dart';
|
||||||
import 'package:stackwallet/utilities/show_loading.dart';
|
import 'package:stackwallet/utilities/show_loading.dart';
|
||||||
import 'package:stackwallet/utilities/stack_file_system.dart';
|
import 'package:stackwallet/utilities/stack_file_system.dart';
|
||||||
import 'package:stackwallet/utilities/text_styles.dart';
|
import 'package:stackwallet/utilities/text_styles.dart';
|
||||||
|
import 'package:stackwallet/utilities/util.dart';
|
||||||
import 'package:stackwallet/widgets/animated_text.dart';
|
import 'package:stackwallet/widgets/animated_text.dart';
|
||||||
import 'package:stackwallet/widgets/desktop/primary_button.dart';
|
import 'package:stackwallet/widgets/desktop/primary_button.dart';
|
||||||
import 'package:stackwallet/widgets/desktop/secondary_button.dart';
|
import 'package:stackwallet/widgets/desktop/secondary_button.dart';
|
||||||
|
@ -33,6 +35,7 @@ class StackThemeCard extends ConsumerStatefulWidget {
|
||||||
}
|
}
|
||||||
|
|
||||||
class _StackThemeCardState extends ConsumerState<StackThemeCard> {
|
class _StackThemeCardState extends ConsumerState<StackThemeCard> {
|
||||||
|
final isDesktop = Util.isDesktop;
|
||||||
late final StreamSubscription<void> _subscription;
|
late final StreamSubscription<void> _subscription;
|
||||||
|
|
||||||
late bool _hasTheme;
|
late bool _hasTheme;
|
||||||
|
@ -170,6 +173,10 @@ class _StackThemeCardState extends ConsumerState<StackThemeCard> {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return RoundedWhiteContainer(
|
return RoundedWhiteContainer(
|
||||||
|
radiusMultiplier: isDesktop ? 2.5 : 1,
|
||||||
|
borderColor: isDesktop
|
||||||
|
? Theme.of(context).extension<StackColors>()!.textSubtitle6
|
||||||
|
: null,
|
||||||
child: Column(
|
child: Column(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
|
@ -259,13 +266,13 @@ class _StackThemeCardState extends ConsumerState<StackThemeCard> {
|
||||||
: CrossFadeState.showFirst,
|
: CrossFadeState.showFirst,
|
||||||
firstChild: PrimaryButton(
|
firstChild: PrimaryButton(
|
||||||
label: "Download",
|
label: "Download",
|
||||||
buttonHeight: ButtonHeight.l,
|
buttonHeight: isDesktop ? ButtonHeight.s : ButtonHeight.l,
|
||||||
onPressed: _downloadPressed,
|
onPressed: _downloadPressed,
|
||||||
),
|
),
|
||||||
secondChild: SecondaryButton(
|
secondChild: SecondaryButton(
|
||||||
label: themeIsInUse ? "Theme is active" : "Remove from device",
|
label: themeIsInUse ? "Theme is active" : "Remove",
|
||||||
enabled: !themeIsInUse,
|
enabled: !themeIsInUse,
|
||||||
buttonHeight: ButtonHeight.l,
|
buttonHeight: isDesktop ? ButtonHeight.s : ButtonHeight.l,
|
||||||
onPressed: _uninstallThemePressed,
|
onPressed: _uninstallThemePressed,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
|
@ -2,7 +2,7 @@ import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:stackwallet/pages_desktop_specific/settings/settings_menu.dart';
|
import 'package:stackwallet/pages_desktop_specific/settings/settings_menu.dart';
|
||||||
import 'package:stackwallet/pages_desktop_specific/settings/settings_menu/advanced_settings/advanced_settings.dart';
|
import 'package:stackwallet/pages_desktop_specific/settings/settings_menu/advanced_settings/advanced_settings.dart';
|
||||||
import 'package:stackwallet/pages_desktop_specific/settings/settings_menu/appearance_settings.dart';
|
import 'package:stackwallet/pages_desktop_specific/settings/settings_menu/appearance_settings/appearance_settings.dart';
|
||||||
import 'package:stackwallet/pages_desktop_specific/settings/settings_menu/backup_and_restore/backup_and_restore_settings.dart';
|
import 'package:stackwallet/pages_desktop_specific/settings/settings_menu/backup_and_restore/backup_and_restore_settings.dart';
|
||||||
import 'package:stackwallet/pages_desktop_specific/settings/settings_menu/currency_settings/currency_settings.dart';
|
import 'package:stackwallet/pages_desktop_specific/settings/settings_menu/currency_settings/currency_settings.dart';
|
||||||
import 'package:stackwallet/pages_desktop_specific/settings/settings_menu/language_settings/language_settings.dart';
|
import 'package:stackwallet/pages_desktop_specific/settings/settings_menu/language_settings/language_settings.dart';
|
||||||
|
|
|
@ -1,8 +1,12 @@
|
||||||
|
import 'dart:async';
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:flutter_svg/svg.dart';
|
import 'package:flutter_svg/svg.dart';
|
||||||
|
import 'package:stackwallet/models/isar/stack_theme.dart';
|
||||||
|
import 'package:stackwallet/pages_desktop_specific/settings/settings_menu/appearance_settings/sub_widgets/desktop_manage_themes.dart';
|
||||||
|
import 'package:stackwallet/providers/db/main_db_provider.dart';
|
||||||
import 'package:stackwallet/providers/global/prefs_provider.dart';
|
import 'package:stackwallet/providers/global/prefs_provider.dart';
|
||||||
import 'package:stackwallet/themes/stack_colors.dart';
|
import 'package:stackwallet/themes/stack_colors.dart';
|
||||||
import 'package:stackwallet/themes/theme_providers.dart';
|
import 'package:stackwallet/themes/theme_providers.dart';
|
||||||
|
@ -200,6 +204,7 @@ class ThemeToggle extends ConsumerStatefulWidget {
|
||||||
}
|
}
|
||||||
|
|
||||||
class _ThemeToggle extends ConsumerState<ThemeToggle> {
|
class _ThemeToggle extends ConsumerState<ThemeToggle> {
|
||||||
|
late final StreamSubscription<void> _subscription;
|
||||||
late int _current;
|
late int _current;
|
||||||
|
|
||||||
List<Tuple3<String, String, String>> installedThemeIdNames = [];
|
List<Tuple3<String, String, String>> installedThemeIdNames = [];
|
||||||
|
@ -261,13 +266,24 @@ class _ThemeToggle extends ConsumerState<ThemeToggle> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
void _updateInstalledList() {
|
||||||
void initState() {
|
|
||||||
installedThemeIdNames = ref
|
installedThemeIdNames = ref
|
||||||
.read(pThemeService)
|
.read(pThemeService)
|
||||||
.installedThemes
|
.installedThemes
|
||||||
.map((e) => Tuple3(e.themeId, e.name, e.assets.themePreview))
|
.map((e) => Tuple3(e.themeId, e.name, e.assets.themePreview))
|
||||||
.toList();
|
.toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
void _manageThemesPressed() {
|
||||||
|
showDialog<void>(
|
||||||
|
context: context,
|
||||||
|
builder: (_) => const DesktopManageThemesDialog(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
_updateInstalledList();
|
||||||
|
|
||||||
if (ref.read(prefsChangeNotifierProvider).enableSystemBrightness) {
|
if (ref.read(prefsChangeNotifierProvider).enableSystemBrightness) {
|
||||||
_current = installedThemeIdNames.length;
|
_current = installedThemeIdNames.length;
|
||||||
|
@ -282,9 +298,26 @@ class _ThemeToggle extends ConsumerState<ThemeToggle> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_subscription =
|
||||||
|
ref.read(mainDBProvider).isar.stackThemes.watchLazy().listen((_) {
|
||||||
|
if (mounted) {
|
||||||
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
|
setState(() {
|
||||||
|
_updateInstalledList();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
super.initState();
|
super.initState();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_subscription.cancel();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Wrap(
|
return Wrap(
|
||||||
|
@ -372,7 +405,56 @@ class _ThemeToggle extends ConsumerState<ThemeToggle> {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
)
|
),
|
||||||
|
Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
border: Border.all(
|
||||||
|
width: 2.5,
|
||||||
|
color: Theme.of(context).extension<StackColors>()!.popupBG,
|
||||||
|
),
|
||||||
|
borderRadius: BorderRadius.circular(
|
||||||
|
Constants.size.circularBorderRadius,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(8.0),
|
||||||
|
child: Semantics(
|
||||||
|
label: "Manage themes",
|
||||||
|
button: true,
|
||||||
|
excludeSemantics: true,
|
||||||
|
child: RawMaterialButton(
|
||||||
|
onPressed: _manageThemesPressed,
|
||||||
|
elevation: 0,
|
||||||
|
focusElevation: 0,
|
||||||
|
hoverElevation: 0,
|
||||||
|
highlightElevation: 0,
|
||||||
|
fillColor: Theme.of(context)
|
||||||
|
.extension<StackColors>()!
|
||||||
|
.textFieldActiveBG,
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.circular(
|
||||||
|
Constants.size.circularBorderRadius,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: Container(
|
||||||
|
color: Colors.transparent,
|
||||||
|
height: 160,
|
||||||
|
width: 200,
|
||||||
|
child: Center(
|
||||||
|
child: SvgPicture.asset(
|
||||||
|
Assets.svg.circlePlusFilled,
|
||||||
|
color: Theme.of(context)
|
||||||
|
.extension<StackColors>()!
|
||||||
|
.textSubtitle2,
|
||||||
|
width: 20,
|
||||||
|
height: 20,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
|
@ -0,0 +1,331 @@
|
||||||
|
import 'dart:typed_data';
|
||||||
|
|
||||||
|
import 'package:desktop_drop/desktop_drop.dart';
|
||||||
|
import 'package:file_picker/file_picker.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
|
import 'package:flutter_svg/flutter_svg.dart';
|
||||||
|
import 'package:share_plus/share_plus.dart';
|
||||||
|
import 'package:stackwallet/themes/stack_colors.dart';
|
||||||
|
import 'package:stackwallet/themes/theme_service.dart';
|
||||||
|
import 'package:stackwallet/utilities/assets.dart';
|
||||||
|
import 'package:stackwallet/utilities/logger.dart';
|
||||||
|
import 'package:stackwallet/utilities/show_loading.dart';
|
||||||
|
import 'package:stackwallet/utilities/text_styles.dart';
|
||||||
|
import 'package:stackwallet/widgets/desktop/outline_blue_button.dart';
|
||||||
|
import 'package:stackwallet/widgets/desktop/primary_button.dart';
|
||||||
|
import 'package:stackwallet/widgets/rounded_container.dart';
|
||||||
|
|
||||||
|
class DesktopInstallTheme extends ConsumerStatefulWidget {
|
||||||
|
const DesktopInstallTheme({Key? key}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
ConsumerState<DesktopInstallTheme> createState() =>
|
||||||
|
_DesktopInstallThemeState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _DesktopInstallThemeState extends ConsumerState<DesktopInstallTheme> {
|
||||||
|
final _boxKey = GlobalKey(debugLabel: "selectThemeFileBoxKey");
|
||||||
|
|
||||||
|
XFile? _selectedFile;
|
||||||
|
bool? _installedState;
|
||||||
|
Size? _size;
|
||||||
|
bool _dragging = false;
|
||||||
|
|
||||||
|
Future<bool> _install() async {
|
||||||
|
try {
|
||||||
|
final timedFuture = Future<void>.delayed(const Duration(seconds: 2));
|
||||||
|
final installFuture = _selectedFile!.readAsBytes().then(
|
||||||
|
(fileBytes) => ref.read(pThemeService).install(
|
||||||
|
themeArchive: ByteData.view(
|
||||||
|
fileBytes.buffer,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
// wait for at least 2 seconds to prevent annoying screen flashing
|
||||||
|
await Future.wait([
|
||||||
|
installFuture,
|
||||||
|
timedFuture,
|
||||||
|
]);
|
||||||
|
return true;
|
||||||
|
} catch (e, s) {
|
||||||
|
Logging.instance.log(
|
||||||
|
"Failed to install theme: $e\n$s",
|
||||||
|
level: LogLevel.Warning,
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _chooseFile() async {
|
||||||
|
try {
|
||||||
|
final result = await FilePicker.platform.pickFiles(
|
||||||
|
dialogTitle: "Choose theme file",
|
||||||
|
type: FileType.custom,
|
||||||
|
allowedExtensions: ["zip"],
|
||||||
|
lockParentWindow: true, // windows only
|
||||||
|
);
|
||||||
|
|
||||||
|
if (result != null && mounted) {
|
||||||
|
if (result.paths.isNotEmpty && result.paths.first != null) {
|
||||||
|
setState(() {
|
||||||
|
_selectedFile = XFile(result.paths.first!);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e, s) {
|
||||||
|
Logging.instance.log("$e\n$s", level: LogLevel.Error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void setBoxSize() {
|
||||||
|
if (_size == null) {
|
||||||
|
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
|
||||||
|
setState(() {
|
||||||
|
_size = _boxKey.currentContext?.size;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
setBoxSize();
|
||||||
|
super.initState();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
"Install theme file",
|
||||||
|
style: STextStyles.desktopTextExtraExtraSmall(context),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
const SizedBox(
|
||||||
|
height: 12,
|
||||||
|
),
|
||||||
|
DropTarget(
|
||||||
|
onDragDone: (detail) {
|
||||||
|
setState(() {
|
||||||
|
if (detail.files.isNotEmpty) {
|
||||||
|
_selectedFile = detail.files.first;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
onDragEntered: (detail) {
|
||||||
|
setState(() {
|
||||||
|
_dragging = true;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
onDragExited: (detail) {
|
||||||
|
setState(() {
|
||||||
|
_dragging = false;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
child: RoundedContainer(
|
||||||
|
key: _boxKey,
|
||||||
|
height: _size?.height,
|
||||||
|
color: _dragging
|
||||||
|
? Theme.of(context).extension<StackColors>()!.textSubtitle6
|
||||||
|
: Theme.of(context).extension<StackColors>()!.popupBG,
|
||||||
|
borderColor:
|
||||||
|
Theme.of(context).extension<StackColors>()!.textSubtitle6,
|
||||||
|
child: _selectedFile == null
|
||||||
|
? Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
const SizedBox(
|
||||||
|
height: 12,
|
||||||
|
),
|
||||||
|
SvgPicture.asset(
|
||||||
|
Assets.svg.fileUpload,
|
||||||
|
color: Theme.of(context)
|
||||||
|
.extension<StackColors>()!
|
||||||
|
.textSubtitle2,
|
||||||
|
width: 24,
|
||||||
|
height: 24,
|
||||||
|
),
|
||||||
|
const SizedBox(
|
||||||
|
height: 12,
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
"Drag and drop your file here",
|
||||||
|
style: STextStyles.fieldLabel(context),
|
||||||
|
),
|
||||||
|
const SizedBox(
|
||||||
|
height: 12,
|
||||||
|
),
|
||||||
|
OutlineBlueButton(
|
||||||
|
label: "Browse",
|
||||||
|
buttonHeight: ButtonHeight.s,
|
||||||
|
width: 140,
|
||||||
|
onPressed: _chooseFile,
|
||||||
|
),
|
||||||
|
const SizedBox(
|
||||||
|
height: 12,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
: Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
RoundedContainer(
|
||||||
|
padding: EdgeInsets.zero,
|
||||||
|
color: Theme.of(context)
|
||||||
|
.extension<StackColors>()!
|
||||||
|
.textFieldActiveBG,
|
||||||
|
width: 300,
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
const SizedBox(
|
||||||
|
width: 10,
|
||||||
|
),
|
||||||
|
SvgPicture.asset(
|
||||||
|
Assets.svg.file,
|
||||||
|
color: Theme.of(context)
|
||||||
|
.extension<StackColors>()!
|
||||||
|
.textDark,
|
||||||
|
width: 16,
|
||||||
|
height: 16,
|
||||||
|
),
|
||||||
|
const SizedBox(
|
||||||
|
width: 8,
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: Text(
|
||||||
|
_selectedFile!.name,
|
||||||
|
style: STextStyles.w500_14(context),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
IconButton(
|
||||||
|
onPressed: () {
|
||||||
|
setState(() {
|
||||||
|
_selectedFile = null;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
icon: SvgPicture.asset(
|
||||||
|
Assets.svg.circleX,
|
||||||
|
color: Theme.of(context)
|
||||||
|
.extension<StackColors>()!
|
||||||
|
.textSubtitle2,
|
||||||
|
width: 16,
|
||||||
|
height: 16,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (_selectedFile != null)
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.only(top: 16, bottom: 20),
|
||||||
|
child: PrimaryButton(
|
||||||
|
label: "Install",
|
||||||
|
buttonHeight: ButtonHeight.s,
|
||||||
|
width: 140,
|
||||||
|
enabled: _installedState == null,
|
||||||
|
onPressed: () async {
|
||||||
|
final result = await showLoading(
|
||||||
|
whileFuture: _install(),
|
||||||
|
context: context,
|
||||||
|
message: "Installing ${_selectedFile!.name}...",
|
||||||
|
);
|
||||||
|
if (mounted) {
|
||||||
|
setState(() {
|
||||||
|
_installedState = result;
|
||||||
|
});
|
||||||
|
|
||||||
|
await Future<void>.delayed(
|
||||||
|
const Duration(milliseconds: 2000),
|
||||||
|
).then((_) {
|
||||||
|
if (mounted) {
|
||||||
|
setState(() {
|
||||||
|
_selectedFile = null;
|
||||||
|
_installedState = null;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
if (_installedState == true)
|
||||||
|
RoundedContainer(
|
||||||
|
color:
|
||||||
|
Theme.of(context).extension<StackColors>()!.snackBarBackSuccess,
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
SvgPicture.asset(
|
||||||
|
Assets.svg.circleX,
|
||||||
|
color: Theme.of(context)
|
||||||
|
.extension<StackColors>()!
|
||||||
|
.snackBarTextSuccess,
|
||||||
|
width: 16,
|
||||||
|
height: 16,
|
||||||
|
),
|
||||||
|
const SizedBox(
|
||||||
|
width: 10,
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
"${_selectedFile?.name} theme installed",
|
||||||
|
style:
|
||||||
|
STextStyles.desktopTextExtraExtraSmall(context).copyWith(
|
||||||
|
color: Theme.of(context)
|
||||||
|
.extension<StackColors>()!
|
||||||
|
.snackBarTextSuccess,
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (_installedState == false)
|
||||||
|
RoundedContainer(
|
||||||
|
color:
|
||||||
|
Theme.of(context).extension<StackColors>()!.snackBarBackError,
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
SvgPicture.asset(
|
||||||
|
Assets.svg.circleX,
|
||||||
|
color: Theme.of(context)
|
||||||
|
.extension<StackColors>()!
|
||||||
|
.snackBarTextError,
|
||||||
|
width: 16,
|
||||||
|
height: 16,
|
||||||
|
),
|
||||||
|
const SizedBox(
|
||||||
|
width: 10,
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
"Failed to install ${_selectedFile?.name} theme",
|
||||||
|
style:
|
||||||
|
STextStyles.desktopTextExtraExtraSmall(context).copyWith(
|
||||||
|
color: Theme.of(context)
|
||||||
|
.extension<StackColors>()!
|
||||||
|
.snackBarTextError,
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,112 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
|
import 'package:stackwallet/pages_desktop_specific/settings/settings_menu/appearance_settings/sub_widgets/desktop_install_theme.dart';
|
||||||
|
import 'package:stackwallet/pages_desktop_specific/settings/settings_menu/appearance_settings/sub_widgets/desktop_themes_gallery.dart';
|
||||||
|
import 'package:stackwallet/themes/stack_colors.dart';
|
||||||
|
import 'package:stackwallet/utilities/constants.dart';
|
||||||
|
import 'package:stackwallet/utilities/text_styles.dart';
|
||||||
|
import 'package:stackwallet/widgets/desktop/desktop_dialog.dart';
|
||||||
|
import 'package:stackwallet/widgets/desktop/desktop_dialog_close_button.dart';
|
||||||
|
import 'package:stackwallet/widgets/toggle.dart';
|
||||||
|
|
||||||
|
class DesktopManageThemesDialog extends ConsumerStatefulWidget {
|
||||||
|
const DesktopManageThemesDialog({Key? key}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
ConsumerState<DesktopManageThemesDialog> createState() =>
|
||||||
|
_DesktopManageThemesDialogState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _DesktopManageThemesDialogState
|
||||||
|
extends ConsumerState<DesktopManageThemesDialog> {
|
||||||
|
static const width = 580.0;
|
||||||
|
bool _isInstallFromFile = false;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return DesktopDialog(
|
||||||
|
maxWidth: width,
|
||||||
|
maxHeight: 708,
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.only(left: 32),
|
||||||
|
child: Text(
|
||||||
|
"Add more themes",
|
||||||
|
style: STextStyles.desktopH3(context),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const DesktopDialogCloseButton(),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 32),
|
||||||
|
child: SizedBox(
|
||||||
|
height: 56,
|
||||||
|
child: Toggle(
|
||||||
|
isOn: _isInstallFromFile,
|
||||||
|
onValueChanged: (value) {
|
||||||
|
if (value != _isInstallFromFile) {
|
||||||
|
setState(() {
|
||||||
|
_isInstallFromFile = value;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onColor: Theme.of(context)
|
||||||
|
.extension<StackColors>()!
|
||||||
|
.rateTypeToggleDesktopColorOn,
|
||||||
|
offColor: Theme.of(context)
|
||||||
|
.extension<StackColors>()!
|
||||||
|
.rateTypeToggleDesktopColorOff,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
borderRadius: BorderRadius.circular(
|
||||||
|
Constants.size.circularBorderRadius,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
onText: "Theme gallery",
|
||||||
|
offText: "Install file",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(
|
||||||
|
height: 16,
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: LayoutBuilder(
|
||||||
|
builder: (context, constraints) {
|
||||||
|
return AnimatedCrossFade(
|
||||||
|
crossFadeState: _isInstallFromFile
|
||||||
|
? CrossFadeState.showSecond
|
||||||
|
: CrossFadeState.showFirst,
|
||||||
|
duration: const Duration(
|
||||||
|
milliseconds: 300,
|
||||||
|
),
|
||||||
|
firstChild: SizedBox(
|
||||||
|
height: constraints.maxHeight,
|
||||||
|
child: const DesktopThemeGallery(
|
||||||
|
dialogWidth: width,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
secondChild: SizedBox(
|
||||||
|
height: constraints.maxHeight,
|
||||||
|
child: const Padding(
|
||||||
|
padding: EdgeInsets.symmetric(horizontal: 32),
|
||||||
|
child: DesktopInstallTheme(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(
|
||||||
|
height: 32,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,153 @@
|
||||||
|
import 'dart:async';
|
||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
|
import 'package:stackwallet/pages/settings_views/global_settings_view/appearance_settings/manage_themes.dart';
|
||||||
|
import 'package:stackwallet/pages/settings_views/global_settings_view/appearance_settings/sub_widgets/stack_theme_card.dart';
|
||||||
|
import 'package:stackwallet/providers/global/prefs_provider.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/widgets/desktop/primary_button.dart';
|
||||||
|
import 'package:stackwallet/widgets/loading_indicator.dart';
|
||||||
|
import 'package:stackwallet/widgets/rounded_white_container.dart';
|
||||||
|
|
||||||
|
class DesktopThemeGallery extends ConsumerStatefulWidget {
|
||||||
|
const DesktopThemeGallery({
|
||||||
|
Key? key,
|
||||||
|
required this.dialogWidth,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
final double dialogWidth;
|
||||||
|
|
||||||
|
@override
|
||||||
|
ConsumerState<DesktopThemeGallery> createState() =>
|
||||||
|
_DesktopThemeGalleryState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _DesktopThemeGalleryState extends ConsumerState<DesktopThemeGallery> {
|
||||||
|
late bool _showThemes;
|
||||||
|
Future<List<StackThemeMetaData>> Function() future = () async => [];
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
_showThemes = ref.read(prefsChangeNotifierProvider).externalCalls;
|
||||||
|
if (_showThemes) {
|
||||||
|
future = ref.read(pThemeService).fetchThemes;
|
||||||
|
}
|
||||||
|
super.initState();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Column(
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.only(left: 32),
|
||||||
|
child: Text(
|
||||||
|
"Theme Gallery",
|
||||||
|
style: STextStyles.desktopTextExtraExtraSmall(context),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
const SizedBox(
|
||||||
|
height: 12,
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 32),
|
||||||
|
child: SingleChildScrollView(
|
||||||
|
child: _showThemes
|
||||||
|
? Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
FutureBuilder(
|
||||||
|
future: future(),
|
||||||
|
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(
|
||||||
|
key: Key(
|
||||||
|
"_DesktopThemeGalleryState_card_${e.id}_key"),
|
||||||
|
width:
|
||||||
|
(widget.dialogWidth - 64 - 32) / 3,
|
||||||
|
child: StackThemeCard(
|
||||||
|
data: e,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.toList(),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return const Center(
|
||||||
|
child: LoadingIndicator(
|
||||||
|
width: 200,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
RoundedWhiteContainer(
|
||||||
|
borderColor: Theme.of(context)
|
||||||
|
.extension<StackColors>()!
|
||||||
|
.textSubtitle6,
|
||||||
|
child: Text(
|
||||||
|
"You are using Incognito Mode."
|
||||||
|
" Please press the button below to load "
|
||||||
|
"available themes from our server or install a "
|
||||||
|
"theme file manually from your computer.",
|
||||||
|
style:
|
||||||
|
STextStyles.desktopTextExtraExtraSmall(context),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(
|
||||||
|
height: 16,
|
||||||
|
),
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
PrimaryButton(
|
||||||
|
label: "Load themes",
|
||||||
|
width: 140,
|
||||||
|
buttonHeight: ButtonHeight.s,
|
||||||
|
onPressed: () {
|
||||||
|
setState(() {
|
||||||
|
_showThemes = true;
|
||||||
|
future = ref.read(pThemeService).fetchThemes;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
const SizedBox(
|
||||||
|
height: 20,
|
||||||
|
),
|
||||||
|
IncognitoInstalledThemes(
|
||||||
|
cardWidth: (widget.dialogWidth - 64 - 32) / 3,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -101,7 +101,6 @@ import 'package:stackwallet/pages/settings_views/wallet_settings_view/wallet_set
|
||||||
import 'package:stackwallet/pages/settings_views/wallet_settings_view/wallet_settings_wallet_settings/rename_wallet_view.dart';
|
import 'package:stackwallet/pages/settings_views/wallet_settings_view/wallet_settings_wallet_settings/rename_wallet_view.dart';
|
||||||
import 'package:stackwallet/pages/settings_views/wallet_settings_view/wallet_settings_wallet_settings/wallet_settings_wallet_settings_view.dart';
|
import 'package:stackwallet/pages/settings_views/wallet_settings_view/wallet_settings_wallet_settings/wallet_settings_wallet_settings_view.dart';
|
||||||
import 'package:stackwallet/pages/stack_privacy_calls.dart';
|
import 'package:stackwallet/pages/stack_privacy_calls.dart';
|
||||||
import 'package:stackwallet/widgets/choose_coin_view.dart';
|
|
||||||
import 'package:stackwallet/pages/token_view/my_tokens_view.dart';
|
import 'package:stackwallet/pages/token_view/my_tokens_view.dart';
|
||||||
import 'package:stackwallet/pages/token_view/token_contract_details_view.dart';
|
import 'package:stackwallet/pages/token_view/token_contract_details_view.dart';
|
||||||
import 'package:stackwallet/pages/token_view/token_view.dart';
|
import 'package:stackwallet/pages/token_view/token_view.dart';
|
||||||
|
@ -136,7 +135,7 @@ import 'package:stackwallet/pages_desktop_specific/password/forgot_password_desk
|
||||||
import 'package:stackwallet/pages_desktop_specific/password/forgotten_passphrase_restore_from_swb.dart';
|
import 'package:stackwallet/pages_desktop_specific/password/forgotten_passphrase_restore_from_swb.dart';
|
||||||
import 'package:stackwallet/pages_desktop_specific/settings/desktop_settings_view.dart';
|
import 'package:stackwallet/pages_desktop_specific/settings/desktop_settings_view.dart';
|
||||||
import 'package:stackwallet/pages_desktop_specific/settings/settings_menu/advanced_settings/advanced_settings.dart';
|
import 'package:stackwallet/pages_desktop_specific/settings/settings_menu/advanced_settings/advanced_settings.dart';
|
||||||
import 'package:stackwallet/pages_desktop_specific/settings/settings_menu/appearance_settings.dart';
|
import 'package:stackwallet/pages_desktop_specific/settings/settings_menu/appearance_settings/appearance_settings.dart';
|
||||||
import 'package:stackwallet/pages_desktop_specific/settings/settings_menu/backup_and_restore/backup_and_restore_settings.dart';
|
import 'package:stackwallet/pages_desktop_specific/settings/settings_menu/backup_and_restore/backup_and_restore_settings.dart';
|
||||||
import 'package:stackwallet/pages_desktop_specific/settings/settings_menu/currency_settings/currency_settings.dart';
|
import 'package:stackwallet/pages_desktop_specific/settings/settings_menu/currency_settings/currency_settings.dart';
|
||||||
import 'package:stackwallet/pages_desktop_specific/settings/settings_menu/desktop_about_view.dart';
|
import 'package:stackwallet/pages_desktop_specific/settings/settings_menu/desktop_about_view.dart';
|
||||||
|
@ -151,6 +150,7 @@ import 'package:stackwallet/services/event_bus/events/global/wallet_sync_status_
|
||||||
import 'package:stackwallet/utilities/amount/amount.dart';
|
import 'package:stackwallet/utilities/amount/amount.dart';
|
||||||
import 'package:stackwallet/utilities/enums/add_wallet_type_enum.dart';
|
import 'package:stackwallet/utilities/enums/add_wallet_type_enum.dart';
|
||||||
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
||||||
|
import 'package:stackwallet/widgets/choose_coin_view.dart';
|
||||||
import 'package:tuple/tuple.dart';
|
import 'package:tuple/tuple.dart';
|
||||||
|
|
||||||
class RouteGenerator {
|
class RouteGenerator {
|
||||||
|
|
|
@ -1749,6 +1749,30 @@ class StackColors extends ThemeExtension<StackColors> {
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
ButtonStyle? getOutlineBlueButtonStyle(BuildContext context) =>
|
||||||
|
Theme.of(context).textButtonTheme.style?.copyWith(
|
||||||
|
backgroundColor: MaterialStateProperty.all<Color>(
|
||||||
|
Colors.transparent,
|
||||||
|
),
|
||||||
|
side: MaterialStateProperty.all<BorderSide>(
|
||||||
|
BorderSide(
|
||||||
|
color: customTextButtonEnabledText,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
ButtonStyle? getOutlineBlueButtonDisabledStyle(BuildContext context) =>
|
||||||
|
Theme.of(context).textButtonTheme.style?.copyWith(
|
||||||
|
backgroundColor: MaterialStateProperty.all<Color>(
|
||||||
|
Colors.transparent,
|
||||||
|
),
|
||||||
|
side: MaterialStateProperty.all<BorderSide>(
|
||||||
|
BorderSide(
|
||||||
|
color: customTextButtonDisabledText,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
ButtonStyle? getSecondaryEnabledButtonStyle(BuildContext context) =>
|
ButtonStyle? getSecondaryEnabledButtonStyle(BuildContext context) =>
|
||||||
Theme.of(context).textButtonTheme.style?.copyWith(
|
Theme.of(context).textButtonTheme.style?.copyWith(
|
||||||
backgroundColor: MaterialStateProperty.all<Color>(
|
backgroundColor: MaterialStateProperty.all<Color>(
|
||||||
|
|
|
@ -182,6 +182,8 @@ class _SVG {
|
||||||
String get tokens => "assets/svg/tokens.svg";
|
String get tokens => "assets/svg/tokens.svg";
|
||||||
String get circlePlusDark => "assets/svg/circle-plus.svg";
|
String get circlePlusDark => "assets/svg/circle-plus.svg";
|
||||||
String get creditCard => "assets/svg/cc.svg";
|
String get creditCard => "assets/svg/cc.svg";
|
||||||
|
String get file => "assets/svg/file.svg";
|
||||||
|
String get fileUpload => "assets/svg/file-upload.svg";
|
||||||
|
|
||||||
String get ellipse1 => "assets/svg/Ellipse-43.svg";
|
String get ellipse1 => "assets/svg/Ellipse-43.svg";
|
||||||
String get ellipse2 => "assets/svg/Ellipse-42.svg";
|
String get ellipse2 => "assets/svg/Ellipse-42.svg";
|
||||||
|
|
188
lib/widgets/desktop/outline_blue_button.dart
Normal file
188
lib/widgets/desktop/outline_blue_button.dart
Normal file
|
@ -0,0 +1,188 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:stackwallet/themes/stack_colors.dart';
|
||||||
|
import 'package:stackwallet/utilities/text_styles.dart';
|
||||||
|
import 'package:stackwallet/utilities/util.dart';
|
||||||
|
import 'package:stackwallet/widgets/desktop/custom_text_button.dart';
|
||||||
|
|
||||||
|
export 'package:stackwallet/widgets/desktop/custom_text_button.dart';
|
||||||
|
|
||||||
|
class OutlineBlueButton extends StatelessWidget {
|
||||||
|
const OutlineBlueButton({
|
||||||
|
Key? key,
|
||||||
|
this.width,
|
||||||
|
this.height,
|
||||||
|
this.label,
|
||||||
|
this.icon,
|
||||||
|
this.onPressed,
|
||||||
|
this.enabled = true,
|
||||||
|
this.buttonHeight,
|
||||||
|
this.iconSpacing = 10,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
final double? width;
|
||||||
|
final double? height;
|
||||||
|
final String? label;
|
||||||
|
final VoidCallback? onPressed;
|
||||||
|
final bool enabled;
|
||||||
|
final Widget? icon;
|
||||||
|
final ButtonHeight? buttonHeight;
|
||||||
|
final double? iconSpacing;
|
||||||
|
|
||||||
|
TextStyle getStyle(bool isDesktop, BuildContext context) {
|
||||||
|
if (isDesktop) {
|
||||||
|
if (buttonHeight == null) {
|
||||||
|
return enabled
|
||||||
|
? STextStyles.desktopButtonEnabled(context).copyWith(
|
||||||
|
color: Theme.of(context)
|
||||||
|
.extension<StackColors>()!
|
||||||
|
.customTextButtonEnabledText,
|
||||||
|
)
|
||||||
|
: STextStyles.desktopButtonDisabled(context).copyWith(
|
||||||
|
color: Theme.of(context)
|
||||||
|
.extension<StackColors>()!
|
||||||
|
.customTextButtonDisabledText,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (buttonHeight!) {
|
||||||
|
case ButtonHeight.xxs:
|
||||||
|
case ButtonHeight.xs:
|
||||||
|
case ButtonHeight.s:
|
||||||
|
return STextStyles.desktopTextExtraExtraSmall(context).copyWith(
|
||||||
|
color: enabled
|
||||||
|
? Theme.of(context)
|
||||||
|
.extension<StackColors>()!
|
||||||
|
.customTextButtonEnabledText
|
||||||
|
: Theme.of(context)
|
||||||
|
.extension<StackColors>()!
|
||||||
|
.customTextButtonDisabledText,
|
||||||
|
);
|
||||||
|
|
||||||
|
case ButtonHeight.m:
|
||||||
|
case ButtonHeight.l:
|
||||||
|
return STextStyles.desktopTextExtraSmall(context).copyWith(
|
||||||
|
color: enabled
|
||||||
|
? Theme.of(context)
|
||||||
|
.extension<StackColors>()!
|
||||||
|
.customTextButtonEnabledText
|
||||||
|
: Theme.of(context)
|
||||||
|
.extension<StackColors>()!
|
||||||
|
.customTextButtonDisabledText,
|
||||||
|
);
|
||||||
|
|
||||||
|
case ButtonHeight.xl:
|
||||||
|
case ButtonHeight.xxl:
|
||||||
|
return enabled
|
||||||
|
? STextStyles.desktopButtonEnabled(context)
|
||||||
|
: STextStyles.desktopButtonDisabled(context);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (buttonHeight == ButtonHeight.l) {
|
||||||
|
return STextStyles.button(context).copyWith(
|
||||||
|
fontSize: 10,
|
||||||
|
color: enabled
|
||||||
|
? Theme.of(context)
|
||||||
|
.extension<StackColors>()!
|
||||||
|
.customTextButtonEnabledText
|
||||||
|
: Theme.of(context)
|
||||||
|
.extension<StackColors>()!
|
||||||
|
.customTextButtonDisabledText,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return STextStyles.button(context).copyWith(
|
||||||
|
color: enabled
|
||||||
|
? Theme.of(context)
|
||||||
|
.extension<StackColors>()!
|
||||||
|
.customTextButtonEnabledText
|
||||||
|
: Theme.of(context)
|
||||||
|
.extension<StackColors>()!
|
||||||
|
.customTextButtonDisabledText,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
double? _getHeight() {
|
||||||
|
if (buttonHeight == null) {
|
||||||
|
return height;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Util.isDesktop) {
|
||||||
|
switch (buttonHeight!) {
|
||||||
|
case ButtonHeight.xxs:
|
||||||
|
return 32;
|
||||||
|
case ButtonHeight.xs:
|
||||||
|
return 37;
|
||||||
|
case ButtonHeight.s:
|
||||||
|
return 40;
|
||||||
|
case ButtonHeight.m:
|
||||||
|
return 48;
|
||||||
|
case ButtonHeight.l:
|
||||||
|
return 56;
|
||||||
|
case ButtonHeight.xl:
|
||||||
|
return 70;
|
||||||
|
case ButtonHeight.xxl:
|
||||||
|
return 96;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
switch (buttonHeight!) {
|
||||||
|
case ButtonHeight.xxs:
|
||||||
|
case ButtonHeight.xs:
|
||||||
|
case ButtonHeight.s:
|
||||||
|
case ButtonHeight.m:
|
||||||
|
return 28;
|
||||||
|
case ButtonHeight.l:
|
||||||
|
return 30;
|
||||||
|
case ButtonHeight.xl:
|
||||||
|
return 46;
|
||||||
|
case ButtonHeight.xxl:
|
||||||
|
return 56;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final isDesktop = Util.isDesktop;
|
||||||
|
|
||||||
|
return CustomTextButtonBase(
|
||||||
|
height: _getHeight(),
|
||||||
|
width: width,
|
||||||
|
textButton: TextButton(
|
||||||
|
onPressed: enabled ? onPressed : null,
|
||||||
|
style: enabled
|
||||||
|
? Theme.of(context)
|
||||||
|
.extension<StackColors>()!
|
||||||
|
.getOutlineBlueButtonStyle(context)
|
||||||
|
: Theme.of(context)
|
||||||
|
.extension<StackColors>()!
|
||||||
|
.getOutlineBlueButtonDisabledStyle(context),
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
if (icon != null) icon!,
|
||||||
|
if (icon != null && label != null)
|
||||||
|
SizedBox(
|
||||||
|
width: iconSpacing,
|
||||||
|
),
|
||||||
|
if (label != null)
|
||||||
|
Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
label!,
|
||||||
|
style: getStyle(isDesktop, context),
|
||||||
|
),
|
||||||
|
if (buttonHeight != null && buttonHeight == ButtonHeight.s)
|
||||||
|
const SizedBox(
|
||||||
|
height: 2,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -329,6 +329,8 @@ flutter:
|
||||||
- assets/svg/framed-gear.svg
|
- assets/svg/framed-gear.svg
|
||||||
- assets/svg/list-ul.svg
|
- assets/svg/list-ul.svg
|
||||||
- assets/svg/cc.svg
|
- assets/svg/cc.svg
|
||||||
|
- assets/svg/file.svg
|
||||||
|
- assets/svg/file-upload.svg
|
||||||
- assets/svg/trocador_rating_a.svg
|
- assets/svg/trocador_rating_a.svg
|
||||||
- assets/svg/trocador_rating_b.svg
|
- assets/svg/trocador_rating_b.svg
|
||||||
- assets/svg/trocador_rating_c.svg
|
- assets/svg/trocador_rating_c.svg
|
||||||
|
|
Loading…
Reference in a new issue