diff --git a/lib/main.dart b/lib/main.dart index b57e73e..b901f45 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,21 +1,28 @@ // ignore_for_file: unnecessary_import, prefer_const_constructors +import 'dart:async'; +import 'dart:io'; + import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:tabamewin32/tabamewin32.dart'; import 'package:window_manager/window_manager.dart'; import 'models/globals.dart'; -import 'models/utils.dart'; +import 'models/settings.dart'; import 'models/win32/win32.dart'; import 'pages/interface.dart'; import 'pages/quickmenu.dart'; Future main(List arguments) async { - if (arguments.length == 1 && arguments[0].contains('-wizardly')) { - arguments = ['"${arguments[0].replaceAll(' -wizardly', '')}\\', '-wizardly']; + List auxArgs = [...arguments]; + if (auxArgs.length == 1 && auxArgs[0].contains('-wizardly')) { + auxArgs = ['"${auxArgs[0].replaceAll(' -wizardly', '')}\\', '-wizardly']; } - globalSettings.args = arguments; + + // auxArgs.add("-strudel"); + globalSettings.args = [...auxArgs]; + // WinUtils.msgBox(globalSettings.args.join(' '), ""); WidgetsFlutterBinding.ensureInitialized(); await windowManager.ensureInitialized(); @@ -52,7 +59,11 @@ Future main(List arguments) async { }); await setWindowAsTransparent(); - + if (globalSettings.runAsAdministrator && !WinUtils.isAdministrator() && globalSettings.args.join(' ').contains('-strudel')) { + globalSettings.args.remove('-strudel'); + WinUtils.run(Platform.resolvedExecutable, arguments: globalSettings.args.join(' ')); + Timer(const Duration(seconds: 5), () => exit(0)); + } runApp(const Tabame()); } diff --git a/lib/models/classes/boxes.dart b/lib/models/classes/boxes.dart index 7c15e3a..40d7067 100644 --- a/lib/models/classes/boxes.dart +++ b/lib/models/classes/boxes.dart @@ -6,7 +6,7 @@ import 'package:flutter/foundation.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:tabamewin32/tabamewin32.dart'; import '../../main.dart'; -import '../utils.dart'; +import '../settings.dart'; import 'saved_maps.dart'; import 'package:http/http.dart' as http; @@ -68,9 +68,9 @@ class Boxes { globalSettings ..hideTaskbarOnStartup = pref.getBool("hideTaskbarOnStartup") ?? false ..taskBarAppsStyle = TaskBarAppsStyle.values[pref.getInt("taskBarAppsStyle") ?? 0] - ..themeType = ThemeType.values[pref.getInt("themeType") ?? 0] ..themeScheduleMin = pref.getInt("themeScheduleMin") ?? 0 ..themeScheduleMax = pref.getInt("themeScheduleMax") ?? 0 + ..themeType = ThemeType.values[pref.getInt("themeType") ?? 0] // * always after schedule ..language = pref.getString("language") ?? Platform.localeName.substring(0, 2) ..customLogo = pref.getString("customLogo") ?? "" ..customSpash = pref.getString("customSpash") ?? "" @@ -86,6 +86,7 @@ class Boxes { ..usePowerShellAsToastNotification = pref.getBool("usePowerShellAsToastNotification") ?? false ..showSystemUsage = pref.getBool("showSystemUsage") ?? false; + // ? Theme final String? lightTheme = pref.getString("lightTheme"); final String? darkTheme = pref.getString("darkTheme"); if (lightTheme == null || darkTheme == null) { @@ -162,6 +163,47 @@ class Boxes { return rewritesMap; } + List> _runShortcuts = >[]; + set runShortcuts(List> items) { + _runShortcuts = items; + updateSettings("runShortcuts", jsonEncode(items)); + } + + List> get runShortcuts { + if (_runShortcuts.isNotEmpty) return _runShortcuts; + final String prefString = pref.getString("runShortcuts") ?? ""; + if (prefString.isEmpty) return _runShortcuts; + final List runShortcuts = jsonDecode(pref.getString("runShortcuts")!); + _runShortcuts.clear(); + for (List x in runShortcuts) { + _runShortcuts.add([x[0], x[1]]); + } + return _runShortcuts; + } + + List> _runKeys = >[]; + set runKeys(List> items) { + _runKeys = items; + updateSettings("runKeys", jsonEncode(items)); + } + + List> get runKeys { + if (_runKeys.isNotEmpty) return _runKeys; + final String prefString = pref.getString("runKeys") ?? ""; + if (prefString.isEmpty) { + return >[ + ["m", "{MEDIA_NEXT_TRACK}"], + ["p", "{MEDIA_PREVIOUS_TRACK}"] + ]; + } + final List runKeys = jsonDecode(pref.getString("runKeys")!); + _runKeys.clear(); + for (List x in runKeys) { + _runKeys.add([x[0], x[1]]); + } + return _runKeys; + } + List get topBarWidgets { List defaultWidgets = [ "TaskManagerButton", diff --git a/lib/models/classes/saved_maps.dart b/lib/models/classes/saved_maps.dart index a318a91..03a0a82 100644 --- a/lib/models/classes/saved_maps.dart +++ b/lib/models/classes/saved_maps.dart @@ -3,7 +3,7 @@ import 'dart:convert'; import 'package:flutter/foundation.dart'; -import '../utils.dart'; +import '../settings.dart'; abstract class SavedMap { const SavedMap(); diff --git a/lib/models/utils.dart b/lib/models/settings.dart similarity index 68% rename from lib/models/utils.dart rename to lib/models/settings.dart index 5977aa9..0430987 100644 --- a/lib/models/utils.dart +++ b/lib/models/settings.dart @@ -1,6 +1,7 @@ // ignore_for_file: public_member_api_docs, sort_constructors_first // vscode-fold=2 import 'dart:async'; +import 'dart:convert'; import 'dart:io'; import 'dart:math'; @@ -16,63 +17,6 @@ import 'classes/saved_maps.dart'; import 'win32/mixed.dart'; import 'win32/win32.dart'; -typedef Maa = MainAxisAlignment; -typedef Caa = CrossAxisAlignment; - -extension IntegerExtension on int { - String formatTime() { - final int hour = (this ~/ 60); - final int minute = (this % 60); - return "${hour.toString().numberFormat()}:${minute.toString().numberFormat()}"; - } - - bool isBetween(num from, num to) { - return from < this && this < to; - } - - bool isBetweenEqual(num from, num to) { - return from <= this && this <= to; - } -} - -extension StringExtension on String { - String truncate(int max, {String suffix = ''}) => length < max ? this : replaceRange(max, null, suffix); - String toUpperCaseFirst() { - if (length < 2) return toUpperCase(); - return "${this[0].toUpperCase()}${substring(1).toLowerCase()}"; - } - - String toUperCaseAll() => toUpperCase(); - String toUpperCaseEach() => split(" ").map((String str) => str.toUpperCaseFirst()).join(" "); - String numberFormat({int minNr = 10}) { - return (int.parse(this) / minNr).toDouble().toString().replaceAll('.', ''); - } -} - -int darkerColor(int color, {int darkenBy = 0x10, int floor = 0x0}) { - final int darkerHex = (max((color >> 16) - darkenBy, floor) << 16) + (max(((color & 0xff00) >> 8) - darkenBy, floor) << 8) + max(((color & 0xff) - darkenBy), floor); - return darkerHex; -} - -class AdjustableScrollController extends ScrollController { - AdjustableScrollController([int extraScrollSpeed = 40]) { - super.addListener(() { - ScrollDirection scrollDirection = super.position.userScrollDirection; - if (scrollDirection != ScrollDirection.idle) { - double scrollEnd = super.offset + (scrollDirection == ScrollDirection.reverse ? extraScrollSpeed : -extraScrollSpeed); - scrollEnd = min(super.position.maxScrollExtent, max(super.position.minScrollExtent, scrollEnd)); - jumpTo(scrollEnd); - } - }); - } -} - -enum TaskBarAppsStyle { onlyActiveMonitor, activeMonitorFirst, orderByActivity } - -enum VolumeOSDStyle { normal, media, visible, thin } - -enum ThemeType { system, light, dark, schedule } - class Settings { List args = []; @@ -94,7 +38,9 @@ class Settings { VolumeOSDStyle volumeOSDStyle = VolumeOSDStyle.normal; TaskBarAppsStyle taskBarAppsStyle = TaskBarAppsStyle.activeMonitorFirst; - List weather = ['10 C', "berlin, Germany", "m", "%c+%t"]; //u for US + List weather = ['10 C', "berlin, Germany", "m", "%c+%t"]; + + RunCommands run = RunCommands(); //u for US set weatherTemperature(String temp) => weather[0] = temp; String get weatherTemperature => weather[0]; set weatherCity(String temp) => weather[1] = temp; @@ -107,7 +53,13 @@ class Settings { int themeScheduleMin = 8 * 60; int themeScheduleMax = 20 * 60; ThemeColors get theme => themeColors; - ThemeType themeType = ThemeType.system; + ThemeType _themeType = ThemeType.system; + ThemeType get themeType => _themeType; + set themeType(ThemeType t) { + _themeType = t; + setScheduleThemeChange(); + } + ThemeColors lightTheme = ThemeColors(background: 0xffD5E0FB, textColor: 0xff3A404A, accentColor: 0xff446EE9, gradientAlpha: 200, quickMenuBoldFont: true); ThemeColors darkTheme = ThemeColors(background: 0xFF3B414D, accentColor: 0xDCFFDCAA, gradientAlpha: 240, textColor: 0xFFFAF9F8, quickMenuBoldFont: true); ThemeColors get themeColors => themeTypeMode == ThemeType.dark ? darkTheme : lightTheme; @@ -127,6 +79,73 @@ class Settings { } String get logo => themeTypeMode == ThemeType.dark ? "resources/logo_light.png" : "resources/logo_dark.png"; + Timer? themeScheduleChangeTimer; + void setScheduleThemeChange() { + themeScheduleChangeTimer?.cancel(); + if (themeType != ThemeType.schedule) return; + final int now = (DateTime.now().hour * 60) + DateTime.now().minute; + if (now.isBetween(themeScheduleMin, themeScheduleMax)) { + themeScheduleChangeTimer = Timer(Duration(minutes: themeScheduleMax - now), () {}); + } else { + themeScheduleChangeTimer = Timer(Duration(minutes: 24 - now + themeScheduleMin), () {}); + } + } +} + +class RunCommands { + String calculator = r"c ;^[0-9]+ ?[+\-*\\%]"; + String color = r"col ;^(#|0x|rgb)"; + String currency = r"cur ;\$;\d+ \w{3,4} to \w{3,4}"; + String shortcut = r"s ;"; + String regex = r"rgx ;^/"; + String lorem = r"lorem ;->"; + String encoders = r"enc ;^([\!|\@]|\[[$@])"; + String setvar = r"v ;^\$"; + String json = r"json"; + String timer = r"t ;~"; + String keys = r"k ;`"; + String timezones = r"t"; + + List get list => [calculator, color, currency, shortcut, regex, lorem, encoders, setvar, json, timezones]; + Future save() async { + await Boxes.updateSettings("runCommands", jsonEncode(toMap())); + return; + } + + Future fetch() async { + final Map output = jsonDecode(Boxes.pref.getString("runCommands2") ?? "[]"); + if (output.isEmpty) return; + calculator = output["calculator"] ?? r"c ;^[0-9]+ ?[+\-*\\%]"; + color = output["color"] ?? r"col ;^(#|0x|rgb)"; + currency = output["currency"] ?? r"cur ;\$;\d+ \w{3,4} to \w{3,4}"; + shortcut = output["shortcut"] ?? r"s ;"; + regex = output["regex"] ?? r"rgx ;^/"; + lorem = output["lorem"] ?? r"lorem ;->"; + encoders = output["encoders"] ?? r"enc ;^([\!|\@]|\[[$@])"; + setvar = output["setvar"] ?? r"v ;^\$"; + json = output["json"] ?? r"json"; + timer = output["timer"] ?? r"t ;~"; + keys = output["keys"] ?? r"k ;`"; + timezones = output["timezones"] ?? r"t"; + } + // String + + Map toMap() { + return { + "calculator": calculator, + "color": color, + "currency": currency, + "shortcut": shortcut, + "regex": regex, + "lorem": lorem, + "encoders": encoders, + "setvar": setvar, + "json": json, + "timer": timer, + "keys": keys, + "timezones": timezones, + }; + } } Settings globalSettings = Settings(); @@ -141,6 +160,9 @@ Future registerAll() async { Timer.periodic(const Duration(seconds: 10), (Timer timer) => Monitor.fetchMonitor()); //register await Boxes.registerBoxes(); + //Schedule Theme + globalSettings.setScheduleThemeChange(); + //Toast Future.delayed(const Duration(seconds: 2), () async { if (!WinUtils.windowsNotificationRegistered) { await localNotifier.setup(appName: 'Tabame', shortcutPolicy: ShortcutPolicy.requireCreate); @@ -149,6 +171,59 @@ Future registerAll() async { }); } +typedef Maa = MainAxisAlignment; +typedef Caa = CrossAxisAlignment; + +extension IntegerExtension on int { + String formatTime() { + final int hour = (this ~/ 60); + final int minute = (this % 60); + return "${hour.toString().numberFormat()}:${minute.toString().numberFormat()}"; + } + bool isBetween(num from, num to) { + return from < this && this < to; + } + + bool isBetweenEqual(num from, num to) { + return from <= this && this <= to; + } +} + +extension StringExtension on String { + String truncate(int max, {String suffix = ''}) => length < max ? this : replaceRange(max, null, suffix); + String toUpperCaseFirst() { + if (length < 2) return toUpperCase(); + return "${this[0].toUpperCase()}${substring(1).toLowerCase()}"; + } -// vscode-fold=dart \ No newline at end of file + String toUperCaseAll() => toUpperCase(); + String toUpperCaseEach() => split(" ").map((String str) => str.toUpperCaseFirst()).join(" "); + String numberFormat({int minNr = 10}) { + return (int.parse(this) / minNr).toDouble().toString().replaceAll('.', ''); + } +} + +int darkerColor(int color, {int darkenBy = 0x10, int floor = 0x0}) { + final int darkerHex = (max((color >> 16) - darkenBy, floor) << 16) + (max(((color & 0xff00) >> 8) - darkenBy, floor) << 8) + max(((color & 0xff) - darkenBy), floor); + return darkerHex; +} + +class AdjustableScrollController extends ScrollController { + AdjustableScrollController([int extraScrollSpeed = 40]) { + super.addListener(() { + ScrollDirection scrollDirection = super.position.userScrollDirection; + if (scrollDirection != ScrollDirection.idle) { + double scrollEnd = super.offset + (scrollDirection == ScrollDirection.reverse ? extraScrollSpeed : -extraScrollSpeed); + scrollEnd = min(super.position.maxScrollExtent, max(super.position.minScrollExtent, scrollEnd)); + jumpTo(scrollEnd); + } + }); + } +} + +enum TaskBarAppsStyle { onlyActiveMonitor, activeMonitorFirst, orderByActivity } + +enum VolumeOSDStyle { normal, media, visible, thin } + +enum ThemeType { system, light, dark, schedule } diff --git a/lib/models/win32/win32.dart b/lib/models/win32/win32.dart index 2dad10c..0f8d8b7 100644 --- a/lib/models/win32/win32.dart +++ b/lib/models/win32/win32.dart @@ -17,7 +17,7 @@ import 'package:tabamewin32/tabamewin32.dart'; import '../globals.dart'; import '../keys.dart'; -import '../utils.dart'; +import '../settings.dart'; import 'imports.dart'; import 'mixed.dart'; import 'registry.dart'; @@ -791,6 +791,10 @@ class WinUtils { free(ppsi); free(ppfi); } + + static msgBox(String text, String title) { + MessageBox(0, TEXT(text), TEXT(title), 0); + } } class WizardlyContextMenu { diff --git a/lib/models/win32/window.dart b/lib/models/win32/window.dart index 6ac910f..8384066 100644 --- a/lib/models/win32/window.dart +++ b/lib/models/win32/window.dart @@ -6,7 +6,7 @@ import 'dart:io'; import 'package:ffi/ffi.dart'; import 'package:win32/win32.dart' hide Size; -import '../utils.dart'; +import '../settings.dart'; import 'imports.dart'; import 'win32.dart'; diff --git a/lib/models/window_watcher.dart b/lib/models/window_watcher.dart index 2a2df9b..c86902c 100644 --- a/lib/models/window_watcher.dart +++ b/lib/models/window_watcher.dart @@ -11,7 +11,7 @@ import 'package:tabamewin32/tabamewin32.dart'; import 'classes/boxes.dart'; import 'globals.dart'; -import 'utils.dart'; +import 'settings.dart'; import 'win32/imports.dart'; import 'win32/mixed.dart'; import 'win32/win32.dart'; diff --git a/lib/pages/interface.dart b/lib/pages/interface.dart index a1531ae..2a80358 100644 --- a/lib/pages/interface.dart +++ b/lib/pages/interface.dart @@ -1,7 +1,6 @@ // ignore_for_file: public_member_api_docs, sort_constructors_first import 'dart:io'; -import 'dart:math'; import 'dart:ui'; import 'package:flutter/foundation.dart'; @@ -11,24 +10,18 @@ import 'package:window_manager/window_manager.dart'; import '../main.dart'; import '../models/globals.dart'; -import '../models/utils.dart'; +import '../models/settings.dart'; import '../models/win32/mixed.dart'; import '../models/win32/win32.dart'; import '../widgets/interface/home.dart'; import '../widgets/interface/projects.dart'; import '../widgets/interface/quickmenu.dart'; +import '../widgets/interface/run_settings.dart'; import '../widgets/interface/settings.dart'; import '../widgets/interface/tasks.dart'; import '../widgets/interface/theme_setup.dart'; import '../widgets/interface/wizardly.dart'; -class Interface extends StatefulWidget { - const Interface({Key? key}) : super(key: key); - - @override - InterfaceState createState() => InterfaceState(); -} - class PageClass { String? title; IconData? icon; @@ -66,16 +59,21 @@ class NotImplemeneted extends StatelessWidget { } } +class Interface extends StatefulWidget { + const Interface({Key? key}) : super(key: key); + @override + InterfaceState createState() => InterfaceState(); +} + class InterfaceState extends State { int currentPage = 0; - final ScrollController mainScrollControl = ScrollController(); PageController page = PageController(); final List pages = [ PageClass(title: 'Home', icon: Icons.home, widget: const Home()), PageClass(title: 'Settings', icon: Icons.settings, widget: const SettingsPage()), PageClass(title: 'Colors', icon: Icons.theater_comedy, widget: const ThemeSetup()), PageClass(title: 'QuickMenu', icon: Icons.apps, widget: const QuickmenuSettings()), - PageClass(title: 'Run Window', icon: Icons.drag_handle, widget: const NotImplemeneted()), + PageClass(title: 'Run Window', icon: Icons.drag_handle, widget: const RunSettings()), PageClass(title: 'Remap Keys', icon: Icons.keyboard, widget: const NotImplemeneted()), PageClass(title: 'Views', icon: Icons.view_agenda, widget: const NotImplemeneted()), PageClass(title: 'Projects', icon: Icons.folder_copy, widget: const ProjectsPage()), @@ -99,7 +97,6 @@ class InterfaceState extends State { @override void dispose() { page.dispose(); - mainScrollControl.dispose(); super.dispose(); } @@ -273,24 +270,26 @@ class InterfaceState extends State { return DecoratedBox( decoration: BoxDecoration( color: currentPage == index ? Color(globalSettings.theme.textColor).withOpacity(0.1) : Colors.transparent), - child: InkWell( + child: GestureDetector( onTap: () { currentPage = index; - // page.jumpToPage(index); - setState(() {}); + if (mounted) setState(() {}); }, - child: Padding( - padding: const EdgeInsets.symmetric(vertical: 5, horizontal: 5), - child: Row( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisSize: MainAxisSize.min, - children: [ - const SizedBox(width: 5), - Icon(pageItem.icon), - const SizedBox(width: 5), - Text(pageItem.title!), - ], + child: MouseRegion( + cursor: SystemMouseCursors.click, + child: Padding( + padding: const EdgeInsets.symmetric(vertical: 5, horizontal: 5), + child: Row( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisSize: MainAxisSize.min, + children: [ + const SizedBox(width: 5), + Icon(pageItem.icon), + const SizedBox(width: 5), + Text(pageItem.title!), + ], + ), ), ), ), @@ -318,17 +317,15 @@ class InterfaceState extends State { child: BackdropFilter( filter: ImageFilter.blur(sigmaX: 100, sigmaY: 100), child: Listener( - onPointerSignal: (PointerSignalEvent ps) { - if (!mainScrollEnabled) return; - if (ps is PointerScrollEvent) { - double scrollEnd = mainScrollControl.offset + (ps.scrollDelta.dy > 0 ? 30 : -30); - scrollEnd = min(mainScrollControl.position.maxScrollExtent, max(mainScrollControl.position.minScrollExtent, scrollEnd)); - mainScrollControl.jumpTo(scrollEnd); + onPointerSignal: (PointerSignalEvent pointerSignal) { + if (pointerSignal is PointerScrollEvent) { + if (pointerSignal.scrollDelta.dy < 0) { + } else {} } }, child: SingleChildScrollView( - controller: mainScrollControl, - physics: const NeverScrollableScrollPhysics(), + controller: AdjustableScrollController(40), + physics: mainScrollEnabled ? const BouncingScrollPhysics(parent: PageScrollPhysics()) : const NeverScrollableScrollPhysics(), child: Material(type: MaterialType.transparency, child: pages[currentPage].widget), ), ), diff --git a/lib/pages/quickmenu.dart b/lib/pages/quickmenu.dart index 40b754b..6837d6b 100644 --- a/lib/pages/quickmenu.dart +++ b/lib/pages/quickmenu.dart @@ -6,7 +6,7 @@ import 'package:flutter/material.dart'; // ignore: implementation_imports import 'package:flutter/src/gestures/events.dart'; import 'package:window_manager/window_manager.dart'; -import '../models/utils.dart'; +import '../models/settings.dart'; import '../models/win32/win32.dart'; import '../models/globals.dart'; import '../widgets/quickmenu/bottom_bar.dart'; diff --git a/lib/pages/run.dart b/lib/pages/run.dart index e69de29..48b351b 100644 --- a/lib/pages/run.dart +++ b/lib/pages/run.dart @@ -0,0 +1,15 @@ +import 'package:flutter/material.dart'; + +class Run extends StatefulWidget { + const Run({Key? key}) : super(key: key); + + @override + RunState createState() => RunState(); +} + +class RunState extends State { + @override + Widget build(BuildContext context) { + return Container(); + } +} diff --git a/lib/widgets/interface/home.dart b/lib/widgets/interface/home.dart index 519d805..7bf3b0d 100644 --- a/lib/widgets/interface/home.dart +++ b/lib/widgets/interface/home.dart @@ -2,7 +2,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_markdown/flutter_markdown.dart'; import '../../models/util/markdown_text.dart'; -import '../../models/utils.dart'; +import '../../models/settings.dart'; class Home extends StatefulWidget { const Home({Key? key}) : super(key: key); diff --git a/lib/widgets/interface/projects.dart b/lib/widgets/interface/projects.dart index a537814..71e2a3d 100644 --- a/lib/widgets/interface/projects.dart +++ b/lib/widgets/interface/projects.dart @@ -9,7 +9,7 @@ import 'package:tabamewin32/tabamewin32.dart'; import '../../models/classes/boxes.dart'; import '../../models/classes/saved_maps.dart'; -import '../../models/utils.dart'; +import '../../models/settings.dart'; import '../../models/win32/win32.dart'; class ProjectsPage extends StatefulWidget { diff --git a/lib/widgets/interface/run_settings.dart b/lib/widgets/interface/run_settings.dart new file mode 100644 index 0000000..1fcad58 --- /dev/null +++ b/lib/widgets/interface/run_settings.dart @@ -0,0 +1,69 @@ +import 'package:animated_button_bar/animated_button_bar.dart'; +import 'package:flutter/material.dart'; + +import '../../models/settings.dart'; +import '../run/interface_api_setup.dart'; +import '../run/interface_general.dart'; + +class RunSettings extends StatefulWidget { + const RunSettings({Key? key}) : super(key: key); + + @override + RunSettingsState createState() => RunSettingsState(); +} + +class WizardPage { + String title; + Widget widget; + String? tooltip; + WizardPage({ + required this.title, + required this.widget, + this.tooltip = "", + }); +} + +class RunSettingsState extends State { + @override + void initState() { + super.initState(); + } + + @override + void dispose() { + super.dispose(); + } + + final List pages = [ + WizardPage(title: "General", widget: const InterfaceGeneral(), tooltip: "General Settings"), + WizardPage(title: "API Setup", widget: InterfaceApiSetup(), tooltip: "Set up API"), + // WizardPage(title: "Image Work", widget: Container()), + ]; + int currentPage = 0; + @override + Widget build(BuildContext context) { + return Column( + mainAxisAlignment: Maa.start, + mainAxisSize: MainAxisSize.max, + children: [ + SizedBox( + height: 80, + child: Padding( + padding: const EdgeInsets.all(1), + child: AnimatedButtonBar( + foregroundColor: Color(globalSettings.theme.accentColor), + radius: 8.0, + padding: const EdgeInsets.all(16.0), + invertedSelection: true, + children: List.generate( + pages.length, + (int i) => ButtonBarEntry( + onTap: () => setState(() => currentPage = i), child: Tooltip(message: pages[i].tooltip, verticalOffset: 20, child: Text(pages[i].title)))), + ), + ), + ), + currentPage < pages.length ? pages[currentPage].widget : Container(), + ], + ); + } +} diff --git a/lib/widgets/interface/settings.dart b/lib/widgets/interface/settings.dart index 520f808..f12e114 100644 --- a/lib/widgets/interface/settings.dart +++ b/lib/widgets/interface/settings.dart @@ -9,7 +9,7 @@ import 'package:tabamewin32/tabamewin32.dart'; import '../../main.dart'; import '../../models/classes/boxes.dart'; -import '../../models/utils.dart'; +import '../../models/settings.dart'; import '../../models/win32/win32.dart'; class SettingsPage extends StatefulWidget { @@ -118,7 +118,13 @@ class SettingsPageState extends State { value: globalSettings.runAsAdministrator, onChanged: (bool? newValue) async { newValue ??= false; - await setStartOnStartupAsAdmin(newValue); + // await setStartOnStartupAsAdmin(newValue); + await setStartOnSystemStartup(false); + if (newValue == true) { + await setStartOnSystemStartup(true, args: "-strudel"); + } else { + await setStartOnSystemStartup(true); + } globalSettings.runAsAdministrator = newValue; await Boxes.updateSettings("runAsAdministrator", newValue); if (!mounted) return; diff --git a/lib/widgets/interface/tasks.dart b/lib/widgets/interface/tasks.dart index 3b2398f..e08113a 100644 --- a/lib/widgets/interface/tasks.dart +++ b/lib/widgets/interface/tasks.dart @@ -1,7 +1,7 @@ import 'package:flutter/material.dart'; import '../../models/classes/boxes.dart'; -import '../../models/utils.dart'; +import '../../models/settings.dart'; import '../itzy/interface/tasks_page_watchers.dart'; import '../itzy/interface/tasks_reminders.dart'; import '../widgets/info_text.dart'; diff --git a/lib/widgets/interface/theme_setup.dart b/lib/widgets/interface/theme_setup.dart index a27ec70..0694a77 100644 --- a/lib/widgets/interface/theme_setup.dart +++ b/lib/widgets/interface/theme_setup.dart @@ -1,4 +1,6 @@ // ignore_for_file: public_member_api_docs, sort_constructors_first +import 'dart:math'; + import 'package:flex_color_picker/flex_color_picker.dart'; import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; @@ -7,7 +9,7 @@ import '../../main.dart'; import '../../models/classes/boxes.dart'; import '../../models/classes/saved_maps.dart'; import '../../models/util/theme_colors.dart'; -import '../../models/utils.dart'; +import '../../models/settings.dart'; class ThemeSetup extends StatefulWidget { const ThemeSetup({Key? key}) : super(key: key); @@ -16,19 +18,21 @@ class ThemeSetup extends StatefulWidget { ThemeSetupState createState() => ThemeSetupState(); } -Map, String> getPredefinedColorSet(List> predefined, int offset) { +Map, String> getPredefinedColorSet(List> predefined, int offset, {int maximum = 60}) { final Map, String> output = , String>{}; final List colorSet = predefined.map((List e) => e[offset]).toSet().toList(); int i = 0; for (int element in colorSet) { i++; output[ColorTools.createPrimarySwatch(Color(element))] = "Variant #$i"; + if (i == maximum) break; } return output; } class ThemeSetupState extends State { final ScrollController colorScrollController = ScrollController(); + final ScrollController mainScrollControl = ScrollController(); ThemeColors savedLightTheme = globalSettings.lightTheme; ThemeColors savedDarkTheme = globalSettings.darkTheme; @@ -61,69 +65,82 @@ class ThemeSetupState extends State { @override Widget build(BuildContext context) { - return Padding( - padding: const EdgeInsets.all(10), - child: Material( - type: MaterialType.transparency, - child: ListTileTheme( - data: Theme.of(context).listTileTheme.copyWith( - dense: true, - style: ListTileStyle.drawer, - contentPadding: const EdgeInsets.symmetric(horizontal: 10), - minVerticalPadding: 0, - visualDensity: VisualDensity.compact, - horizontalTitleGap: 0, - ), - child: globalSettings.themeTypeMode == ThemeType.dark - ? ThemeSetupWidget( - title: "Dark Theme", - constraints: const BoxConstraints(), - savedColors: savedDarkTheme, - currentColors: globalSettings.darkTheme, - onSaved: () async { - await Boxes.updateSettings("darkTheme", globalSettings.darkTheme.toJson()); - savedLightTheme = globalSettings.lightTheme; - savedDarkTheme = globalSettings.darkTheme; - setState(() {}); - }, - onGradiendChanged: (double e) { - globalSettings.darkTheme.gradientAlpha = e.toInt(); - }, - quickMenuBoldChanged: (bool e) { - globalSettings.darkTheme.quickMenuBoldFont = e; - }, - onColorChanged: (Color color, int i) { - if (i == 0) globalSettings.darkTheme.background = color.value; - if (i == 1) globalSettings.darkTheme.textColor = color.value; - if (i == 2) globalSettings.darkTheme.accentColor = color.value; + return Listener( + onPointerSignal: (PointerSignalEvent ps) { + if (ps is PointerScrollEvent) { + double scrollEnd = mainScrollControl.offset + (ps.scrollDelta.dy > 0 ? 30 : -30); + scrollEnd = min(mainScrollControl.position.maxScrollExtent, max(mainScrollControl.position.minScrollExtent, scrollEnd)); + mainScrollControl.jumpTo(scrollEnd); + } + }, + child: SingleChildScrollView( + controller: mainScrollControl, + physics: const NeverScrollableScrollPhysics(), + child: Padding( + padding: const EdgeInsets.all(10), + child: Material( + type: MaterialType.transparency, + child: ListTileTheme( + data: Theme.of(context).listTileTheme.copyWith( + dense: true, + style: ListTileStyle.drawer, + contentPadding: const EdgeInsets.symmetric(horizontal: 10), + minVerticalPadding: 0, + visualDensity: VisualDensity.compact, + horizontalTitleGap: 0, + ), + child: globalSettings.themeTypeMode == ThemeType.dark + ? ThemeSetupWidget( + title: "Dark Theme", + constraints: const BoxConstraints(), + savedColors: savedDarkTheme, + currentColors: globalSettings.darkTheme, + onSaved: () async { + await Boxes.updateSettings("darkTheme", globalSettings.darkTheme.toJson()); + savedLightTheme = globalSettings.lightTheme; + savedDarkTheme = globalSettings.darkTheme; + setState(() {}); + }, + onGradiendChanged: (double e) { + globalSettings.darkTheme.gradientAlpha = e.toInt(); + }, + quickMenuBoldChanged: (bool e) { + globalSettings.darkTheme.quickMenuBoldFont = e; + }, + onColorChanged: (Color color, int i) { + if (i == 0) globalSettings.darkTheme.background = color.value; + if (i == 1) globalSettings.darkTheme.textColor = color.value; + if (i == 2) globalSettings.darkTheme.accentColor = color.value; - themeChangeNotifier.value = !themeChangeNotifier.value; - }, - predefinedColors: predefinedColorsDark, - ) - : ThemeSetupWidget( - title: "Light Theme", - constraints: const BoxConstraints(), - savedColors: savedLightTheme, - currentColors: globalSettings.lightTheme, - onSaved: () async { - await Boxes.updateSettings("lightTheme", globalSettings.lightTheme.toJson()); - setState(() {}); - }, - onGradiendChanged: (double e) { - globalSettings.lightTheme.gradientAlpha = e.toInt(); - }, - quickMenuBoldChanged: (bool e) { - globalSettings.lightTheme.quickMenuBoldFont = e; - }, - onColorChanged: (Color color, int i) { - if (i == 0) globalSettings.lightTheme.background = color.value; - if (i == 1) globalSettings.lightTheme.textColor = color.value; - if (i == 2) globalSettings.lightTheme.accentColor = color.value; - themeChangeNotifier.value = !themeChangeNotifier.value; - }, - predefinedColors: predefinedColorsLight, - ), + themeChangeNotifier.value = !themeChangeNotifier.value; + }, + predefinedColors: predefinedColorsDark, + ) + : ThemeSetupWidget( + title: "Light Theme", + constraints: const BoxConstraints(), + savedColors: savedLightTheme, + currentColors: globalSettings.lightTheme, + onSaved: () async { + await Boxes.updateSettings("lightTheme", globalSettings.lightTheme.toJson()); + setState(() {}); + }, + onGradiendChanged: (double e) { + globalSettings.lightTheme.gradientAlpha = e.toInt(); + }, + quickMenuBoldChanged: (bool e) { + globalSettings.lightTheme.quickMenuBoldFont = e; + }, + onColorChanged: (Color color, int i) { + if (i == 0) globalSettings.lightTheme.background = color.value; + if (i == 1) globalSettings.lightTheme.textColor = color.value; + if (i == 2) globalSettings.lightTheme.accentColor = color.value; + themeChangeNotifier.value = !themeChangeNotifier.value; + }, + predefinedColors: predefinedColorsLight, + ), + ), + ), ), ), ); @@ -240,20 +257,39 @@ class _ThemeSetupWidgetState extends State { setState(() {}); }, ), - CheckboxListTile( - value: widget.currentColors.quickMenuBoldFont, - controlAffinity: ListTileControlAffinity.leading, - onChanged: (bool? e) { - widget.quickMenuBoldChanged(e ?? false); - setState(() {}); - }, - title: const Text("Apps in QuickMenu written in Bold"), - ) + AppsWrittenInbold(widget: widget) ], ); } } +class AppsWrittenInbold extends StatefulWidget { + const AppsWrittenInbold({ + Key? key, + required this.widget, + }) : super(key: key); + + final ThemeSetupWidget widget; + + @override + State createState() => _AppsWrittenInboldState(); +} + +class _AppsWrittenInboldState extends State { + @override + Widget build(BuildContext context) { + return CheckboxListTile( + value: widget.widget.currentColors.quickMenuBoldFont, + controlAffinity: ListTileControlAffinity.leading, + onChanged: (bool? e) { + widget.widget.quickMenuBoldChanged(e ?? false); + setState(() {}); + }, + title: const Text("Apps in QuickMenu written in Bold"), + ); + } +} + class ColorSetup extends StatelessWidget { const ColorSetup({ Key? key, diff --git a/lib/widgets/interface/wizardly.dart b/lib/widgets/interface/wizardly.dart index cad3366..5401857 100644 --- a/lib/widgets/interface/wizardly.dart +++ b/lib/widgets/interface/wizardly.dart @@ -2,11 +2,11 @@ import 'package:animated_button_bar/animated_button_bar.dart'; import 'package:flutter/material.dart'; -import '../../models/utils.dart'; -import '../wizardly/file_name_widget.dart'; -import '../wizardly/file_size_widget.dart'; +import '../../models/settings.dart'; +import '../wizardly/rename_files.dart'; +import '../wizardly/folder_size_scan.dart'; import '../wizardly/project_overview.dart'; -import '../wizardly/search_text_widget.dart'; +import '../wizardly/find_text.dart'; class Wizardly extends StatefulWidget { const Wizardly({Key? key}) : super(key: key); @@ -15,8 +15,6 @@ class Wizardly extends StatefulWidget { WizardlyState createState() => WizardlyState(); } -enum Wizards { folder, name, image, find, cloc } - class WizardPage { String title; Widget widget; @@ -40,11 +38,11 @@ class WizardlyState extends State { } final List pages = [ - WizardPage(title: "Folder Size Scan", widget: const FileSizeWidget(), tooltip: "See how big folders and subfolder are"), - WizardPage(title: "Rename Files", widget: const FileNameWidget(), tooltip: "Rename files in bulk"), - // WizardPage(title: "Image Work", widget: Container()), WizardPage(title: "Find Text in Folder", widget: const SearchTextWidget(), tooltip: "Find Text in folders"), WizardPage(title: "Project Overview", widget: const ProjectOverviewWidget(), tooltip: "Count line of Code\nFiew project breakdown"), + WizardPage(title: "Rename Files", widget: const FileNameWidget(), tooltip: "Rename files in bulk"), + WizardPage(title: "Folder Size Scan", widget: const FileSizeWidget(), tooltip: "See how big folders and subfolder are"), + // WizardPage(title: "Image Work", widget: Container()), ]; int currentPage = 0; @override @@ -62,15 +60,10 @@ class WizardlyState extends State { radius: 8.0, padding: const EdgeInsets.all(16.0), invertedSelection: true, - children: [ - for (int i = 0; i < pages.length; i++) - ButtonBarEntry( - onTap: () { - currentPage = i; - setState(() {}); - }, - child: Text(pages[i].title)), - ], + children: List.generate( + pages.length, + (int i) => ButtonBarEntry( + onTap: () => setState(() => currentPage = i), child: Tooltip(message: pages[i].tooltip, verticalOffset: 20, child: Text(pages[i].title)))), ), ), ), diff --git a/lib/widgets/itzy/interface/quickmenu_bottom_bar.dart b/lib/widgets/itzy/interface/quickmenu_bottom_bar.dart index 9d51df4..21d5129 100644 --- a/lib/widgets/itzy/interface/quickmenu_bottom_bar.dart +++ b/lib/widgets/itzy/interface/quickmenu_bottom_bar.dart @@ -5,7 +5,7 @@ import 'package:flutter/material.dart'; import '../../../models/classes/boxes.dart'; import '../../../models/classes/saved_maps.dart'; import '../../../models/tray_watcher.dart'; -import '../../../models/utils.dart'; +import '../../../models/settings.dart'; import '../../../models/win32/win32.dart'; class QuickmenuBottomBar extends StatefulWidget { @@ -96,9 +96,7 @@ class QuickmenuBottomBarState extends State { setState(() {}); }, secondary: InkWell( - onTap: () { - WinUtils.open("https://wttr.in"); - }, + onTap: () => WinUtils.open("https://wttr.in"), child: Tooltip(message: "It uses wttr.in by chubin", child: Icon(Icons.info_outline, color: Theme.of(context).toggleableActiveColor)), ), ), diff --git a/lib/widgets/itzy/interface/quickmenu_quickactions.dart b/lib/widgets/itzy/interface/quickmenu_quickactions.dart index dbb8cb7..7d8b687 100644 --- a/lib/widgets/itzy/interface/quickmenu_quickactions.dart +++ b/lib/widgets/itzy/interface/quickmenu_quickactions.dart @@ -2,7 +2,7 @@ import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import '../../../models/classes/boxes.dart'; -import '../../../models/utils.dart'; +import '../../../models/settings.dart'; import '../../../pages/interface.dart'; class QuickmenuTopbar extends StatefulWidget { diff --git a/lib/widgets/itzy/interface/quickmenu_taskbar.dart b/lib/widgets/itzy/interface/quickmenu_taskbar.dart index 0c566c9..6b8d394 100644 --- a/lib/widgets/itzy/interface/quickmenu_taskbar.dart +++ b/lib/widgets/itzy/interface/quickmenu_taskbar.dart @@ -3,7 +3,7 @@ import 'dart:convert'; import 'package:flutter/material.dart'; import '../../../models/classes/boxes.dart'; -import '../../../models/utils.dart'; +import '../../../models/settings.dart'; import '../../../models/window_watcher.dart'; class QuickmenuTaskbar extends StatefulWidget { diff --git a/lib/widgets/itzy/interface/tasks_reminders.dart b/lib/widgets/itzy/interface/tasks_reminders.dart index d0bcd95..83afe7a 100644 --- a/lib/widgets/itzy/interface/tasks_reminders.dart +++ b/lib/widgets/itzy/interface/tasks_reminders.dart @@ -5,7 +5,7 @@ import 'package:flutter/material.dart'; import '../../../models/classes/boxes.dart'; import '../../../models/classes/saved_maps.dart'; -import '../../../models/utils.dart'; +import '../../../models/settings.dart'; import '../../widgets/info_text.dart'; class TasksReminders extends StatefulWidget { diff --git a/lib/widgets/itzy/quickmenu/button_change_theme.dart b/lib/widgets/itzy/quickmenu/button_change_theme.dart index fab18fc..a522049 100644 --- a/lib/widgets/itzy/quickmenu/button_change_theme.dart +++ b/lib/widgets/itzy/quickmenu/button_change_theme.dart @@ -1,7 +1,7 @@ import 'package:flutter/material.dart'; import '../../../main.dart'; -import '../../../models/utils.dart'; +import '../../../models/settings.dart'; class ChangeThemeButton extends StatelessWidget { const ChangeThemeButton({ diff --git a/lib/widgets/itzy/quickmenu/button_logo_drag.dart b/lib/widgets/itzy/quickmenu/button_logo_drag.dart index 8f90be1..0350265 100644 --- a/lib/widgets/itzy/quickmenu/button_logo_drag.dart +++ b/lib/widgets/itzy/quickmenu/button_logo_drag.dart @@ -3,24 +3,28 @@ import 'dart:io'; import 'package:flutter/material.dart'; import 'package:window_manager/window_manager.dart'; -import '../../../models/utils.dart'; +import '../../../main.dart'; +import '../../../models/settings.dart'; class LogoDragButton extends StatelessWidget { const LogoDragButton({Key? key}) : super(key: key); @override Widget build(BuildContext context) { - return GestureDetector( - behavior: HitTestBehavior.translucent, - onPanStart: (DragStartDetails details) { - windowManager.startDragging(); - }, - child: InkWell( - child: Padding( - padding: const EdgeInsets.symmetric(horizontal: 5), - child: Align( - alignment: Alignment.centerLeft, - child: globalSettings.customLogo == "" ? Image.asset(globalSettings.logo, width: 15) : Image.file(File(globalSettings.customLogo), width: 15)), + return ValueListenableBuilder( + valueListenable: themeChangeNotifier, + builder: (_, bool refreshed, __) => GestureDetector( + behavior: HitTestBehavior.translucent, + onPanStart: (DragStartDetails details) { + windowManager.startDragging(); + }, + child: InkWell( + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 5), + child: Align( + alignment: Alignment.centerLeft, + child: globalSettings.customLogo == "" ? Image.asset(globalSettings.logo, width: 15) : Image.file(File(globalSettings.customLogo), width: 15)), + ), ), ), ); diff --git a/lib/widgets/itzy/quickmenu/widget_audio.dart b/lib/widgets/itzy/quickmenu/widget_audio.dart index 4400b1f..717ce93 100644 --- a/lib/widgets/itzy/quickmenu/widget_audio.dart +++ b/lib/widgets/itzy/quickmenu/widget_audio.dart @@ -6,7 +6,7 @@ import 'package:flutter/material.dart'; import 'package:tabamewin32/tabamewin32.dart'; import '../../../models/globals.dart'; -import '../../../models/utils.dart'; +import '../../../models/settings.dart'; import '../../../models/win32/win32.dart'; class AudioBox extends StatefulWidget { diff --git a/lib/widgets/itzy/quickmenu/widget_weather.dart b/lib/widgets/itzy/quickmenu/widget_weather.dart index 9a093ee..4f4942f 100644 --- a/lib/widgets/itzy/quickmenu/widget_weather.dart +++ b/lib/widgets/itzy/quickmenu/widget_weather.dart @@ -5,7 +5,7 @@ import 'package:flutter/material.dart'; import 'package:http/http.dart' as http; import '../../../models/classes/boxes.dart'; -import '../../../models/utils.dart'; +import '../../../models/settings.dart'; import '../../../models/win32/win32.dart'; Future fetchWeather() async { diff --git a/lib/widgets/quickmenu/bottom_bar.dart b/lib/widgets/quickmenu/bottom_bar.dart index defb29f..74767c0 100644 --- a/lib/widgets/quickmenu/bottom_bar.dart +++ b/lib/widgets/quickmenu/bottom_bar.dart @@ -1,7 +1,7 @@ import 'package:flutter/material.dart'; import '../../models/classes/boxes.dart'; import '../../models/globals.dart'; -import '../../models/utils.dart'; +import '../../models/settings.dart'; import '../itzy/quickmenu/list_powershell.dart'; import '../itzy/quickmenu/widget_time.dart'; import '../itzy/quickmenu/widget_time_weather.dart'; diff --git a/lib/widgets/quickmenu/task_bar.dart b/lib/widgets/quickmenu/task_bar.dart index 00508d6..7577754 100644 --- a/lib/widgets/quickmenu/task_bar.dart +++ b/lib/widgets/quickmenu/task_bar.dart @@ -8,7 +8,7 @@ import 'package:flutter/material.dart' hide MenuItem; // ignore: implementation_imports import 'package:flutter/src/gestures/events.dart'; import '../../models/classes/boxes.dart'; -import '../../models/utils.dart'; +import '../../models/settings.dart'; import '../../models/win32/window.dart'; import '../../models/window_watcher.dart'; import '../../models/win32/mixed.dart'; diff --git a/lib/widgets/quickmenu/top_bar.dart b/lib/widgets/quickmenu/top_bar.dart index b03b720..99834d3 100644 --- a/lib/widgets/quickmenu/top_bar.dart +++ b/lib/widgets/quickmenu/top_bar.dart @@ -3,8 +3,7 @@ import 'package:flutter/material.dart'; import '../../models/classes/boxes.dart'; import '../../models/globals.dart'; -import '../../models/utils.dart'; -import '../../models/win32/win32.dart'; +import '../../models/settings.dart'; import '../itzy/quickmenu/button_always_awake.dart'; import '../itzy/quickmenu/button_audio.dart'; import '../itzy/quickmenu/button_change_theme.dart'; @@ -114,7 +113,8 @@ class TopBar extends StatelessWidget { message: "Testing", child: InkWell( onTap: () async { - WizardlyContextMenu().toggleWizardlyToContextMenu(); + // WinUtils.runAsAdministrator(); + // WizardlyContextMenu().toggleWizardlyToContextMenu(); }, child: const Icon(Icons.textsms_outlined), ), diff --git a/lib/widgets/quickmenu/tray_bar.dart b/lib/widgets/quickmenu/tray_bar.dart index fd88bab..31aa119 100644 --- a/lib/widgets/quickmenu/tray_bar.dart +++ b/lib/widgets/quickmenu/tray_bar.dart @@ -9,7 +9,7 @@ import 'package:win32/win32.dart' hide Rect; import '../../models/globals.dart'; import '../../models/tray_watcher.dart'; -import '../../models/utils.dart'; +import '../../models/settings.dart'; import '../../models/win32/win32.dart'; class TrayBar extends StatefulWidget { diff --git a/lib/widgets/run/interface_api_setup.dart b/lib/widgets/run/interface_api_setup.dart new file mode 100644 index 0000000..be8963c --- /dev/null +++ b/lib/widgets/run/interface_api_setup.dart @@ -0,0 +1,95 @@ +// ignore_for_file: public_member_api_docs, sort_constructors_first +import 'package:flutter/material.dart'; + +// ignore: unused_import +import 'package:http/http.dart' as http; + +class ApiRequest { + String url; + List headers; + List data; + String toMatch; + String matched = ""; + List result = [""]; + bool parseAsJson = true; + ApiRequest({ + required this.url, + required this.headers, + required this.data, + required this.toMatch, + this.parseAsJson = true, + }) { + matched = ""; + result = [""]; + } +} + +class ApiQuery { + String name; + List requests; + ApiQuery({ + required this.name, + required this.requests, + }); +} + +class RunAPIBearer { + String name; + ApiRequest token; + int refreshTokenAfterMinutes = 1 * 60 * 24; + List queries = []; + Map variables = {}; + RunAPIBearer({ + required this.name, + required this.token, + this.refreshTokenAfterMinutes = 1 * 60 * 24, + this.queries = const [], + }); +} + +class InterfaceApiSetup extends StatefulWidget { + const InterfaceApiSetup({Key? key}) : super(key: key); + + @override + InterfaceApiSetupState createState() => InterfaceApiSetupState(); +} + +class InterfaceApiSetupState extends State { + List api = [ + RunAPIBearer( + name: "Twitch", + token: ApiRequest( + url: "https://id.twitch.tv/oauth2/token", + headers: ["Content-Type: application/x-www-form-urlencoded"], + data: ["client_id=9duwo8nlogmbt6siqr6lkypxgyop05", "client_secret=1483rxcu10mddvkhkyrjsn42uooovx", "grant_type=client_credentials"], + toMatch: "access_token", + ), + queries: [ + ApiQuery(name: "user info", requests: [ + ApiRequest( + url: "https://api.twitch.tv/helix/users?login={params}", + headers: ["Authorization: Bearer {bearer}", "Client-Id: {client-id}"], + data: [], + toMatch: "", + ) + ]) + ]) + ]; + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + return Column( + children: [ + ListTile( + leading: const Icon(Icons.add), + title: const Text("Add New API"), + onTap: () {}, + ) + ], + ); + } +} diff --git a/lib/widgets/run/interface_converters.dart b/lib/widgets/run/interface_converters.dart new file mode 100644 index 0000000..e1cc39d --- /dev/null +++ b/lib/widgets/run/interface_converters.dart @@ -0,0 +1,113 @@ +// ignore_for_file: public_member_api_docs, sort_constructors_first +import 'package:flutter/material.dart'; + +import '../../models/settings.dart'; +import '../widgets/run_shortcut_widget.dart'; + +class InterfaceRunConverter extends StatefulWidget { + const InterfaceRunConverter({Key? key}) : super(key: key); + + @override + InterfaceRunConverterState createState() => InterfaceRunConverterState(); +} + +class InterfaceRunConverterState extends State { + @override + Widget build(BuildContext context) { + return Row( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Divider(height: 10, thickness: 1), + Expanded( + child: Column( + children: [ + RunShortCutInfo( + onChanged: (String newStr) { + globalSettings.run.calculator = newStr; + globalSettings.run.save(); + setState(() {}); + }, + title: "Calculator", + value: globalSettings.run.calculator, + link: "https://mathjs.org/docs/expressions/syntax.html", + tooltip: "It uses mathjs.org", + info: + "Default shortcut is c , or number and a mathematical symbol. It uses mathjs.org to process query.\nClick on Info Button to see all formats. It can convert units too!", + example: ["66*20/12", "c 10 inch to cm", "c 2+3*sqrt(4)"]), + RunShortCutInfo( + onChanged: (String newStr) { + globalSettings.run.currency = newStr; + globalSettings.run.save(); + setState(() {}); + }, + title: "Currency Converter", + value: globalSettings.run.currency, + link: "https://github.com/fawazahmed0/currency-api/tree/1/latest/currencies", + tooltip: "It uses fawazahmed0/currency-api", + info: "Default shortcut is cur , or Number Currency to Currency. It uses github repo by fawazahmed0 to fetch currency.", + example: ["100 USD TO EUR", "cur 564.23 usd to GBP"], + ), + ], + ), + ), + Expanded( + child: Column( + children: [ + RunShortCutInfo( + onChanged: (String newStr) { + globalSettings.run.color = newStr; + globalSettings.run.save(); + setState(() {}); + }, + title: "Color Converter", + value: globalSettings.run.color, + link: "https://www.google.com/search?q=color+picker+online", + tooltip: "Color picker", + info: "Default shortcut is col , or common Color prefixes.", + example: ["col #ffffff", "0xfa5b50", "rgba(123,255,44,12)"], + ), + RunShortCutInfo( + onChanged: (String newStr) { + globalSettings.run.color = newStr; + globalSettings.run.save(); + setState(() {}); + }, + title: "Time zones", + value: globalSettings.run.color, + link: "https://www.google.com/search?q=color+picker+online", + tooltip: "Time Zone Converter", + info: "Default is t and it converts to your local time.", + example: [ + "t 10 pm EEST", + ], + ), + ], + ), + ), + ], + ); + } + + bool tryRegex(String regex) { + bool worked = true; + try { + RegExp(regex, caseSensitive: false).hasMatch("Ciulama"); + } catch (e) { + worked = false; + print(e); + ScaffoldMessenger.of(context) + .showSnackBar(SnackBar(content: Text("Error: Regex Failed!\n$e"), duration: const Duration(seconds: 4), backgroundColor: Colors.red.shade600)); + } + return worked; + } + + bool isNewValValid(String newVal) { + if (newVal.isEmpty) return false; + final List listTriggers = newVal.split(';'); + if (listTriggers.length > 1) { + if (!tryRegex(listTriggers.last)) return false; + } + return true; + } +} diff --git a/lib/widgets/run/interface_general.dart b/lib/widgets/run/interface_general.dart new file mode 100644 index 0000000..3cb1846 --- /dev/null +++ b/lib/widgets/run/interface_general.dart @@ -0,0 +1,74 @@ +import 'package:animated_button_bar/animated_button_bar.dart'; +import 'package:flutter/material.dart'; + +import '../../models/settings.dart'; +import '../widgets/info_text.dart'; +import 'interface_converters.dart'; +import 'interface_processors.dart'; +import 'interface_utility.dart'; + +class WizardPage { + String title; + Widget widget; + String? tooltip; + WizardPage({ + required this.title, + required this.widget, + this.tooltip = "", + }); +} + +class InterfaceGeneral extends StatefulWidget { + const InterfaceGeneral({Key? key}) : super(key: key); + + @override + InterfaceGeneralState createState() => InterfaceGeneralState(); +} + +class InterfaceGeneralState extends State { + @override + void initState() { + super.initState(); + } + + @override + void dispose() { + super.dispose(); + } + + final List pages = [ + WizardPage(title: "Converters", widget: const InterfaceRunConverter(), tooltip: "Calculator, Currency, Color"), + WizardPage(title: "Processors", widget: const InterfaceRunProcessors(), tooltip: "Regex, Lorem, Json, Encoders"), + WizardPage(title: "Utility", widget: const InterfaceRunUtility(), tooltip: "Shortcuts, Timer"), + // WizardPage(title: "Image Work", widget: Container()), + ]; + int currentPage = 0; + @override + Widget build(BuildContext context) { + return Column( + mainAxisAlignment: Maa.start, + mainAxisSize: MainAxisSize.max, + children: [ + const InfoText("On triggers, last one is always regex aware!"), + SizedBox( + height: 80, + child: Padding( + padding: const EdgeInsets.all(1), + child: AnimatedButtonBar( + foregroundColor: Theme.of(context).colorScheme.primary, + radius: 8.0, + padding: const EdgeInsets.all(16.0), + invertedSelection: true, + children: List.generate( + pages.length, + (int i) => ButtonBarEntry( + onTap: () => setState(() => currentPage = i), child: Tooltip(message: pages[i].tooltip, verticalOffset: 20, child: Text(pages[i].title)))), + ), + ), + ), + currentPage < pages.length ? pages[currentPage].widget : Container(), + const SizedBox(height: 20) + ], + ); + } +} diff --git a/lib/widgets/run/interface_processors.dart b/lib/widgets/run/interface_processors.dart new file mode 100644 index 0000000..ac10aa0 --- /dev/null +++ b/lib/widgets/run/interface_processors.dart @@ -0,0 +1,134 @@ +import 'package:flutter/material.dart'; + +import '../../models/classes/boxes.dart'; +import '../../models/settings.dart'; +import '../widgets/run_shortcut_widget.dart'; +import '../widgets/text_box.dart'; + +class InterfaceRunProcessors extends StatefulWidget { + const InterfaceRunProcessors({Key? key}) : super(key: key); + + @override + InterfaceRunProcessorsState createState() => InterfaceRunProcessorsState(); +} + +class InterfaceRunProcessorsState extends State { + final List> runShortcuts = Boxes().runShortcuts; + @override + Widget build(BuildContext context) { + return Row( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Expanded( + child: Column(mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: [ + const Divider(height: 10, thickness: 1), + RunShortCutInfo( + value: globalSettings.run.regex, + onChanged: (String newStr) { + globalSettings.run.regex = newStr; + globalSettings.run.save(); + setState(() {}); + }, + title: "Regex", + link: "https://regex101.com", + tooltip: "Website to test regex skills", + info: "Default shortcut is rgx. It has 3 sub commands: setText, match, replace. Default is case insensitive.", + example: ["rgx setText This project has 10 bugs", r"rgx match (\d+) bugs", r"rgx replace /(\d+) bugs/ /0 bugs, $1 fixed/"]), + RunShortCutInfo( + value: globalSettings.run.lorem, + onChanged: (String newStr) { + globalSettings.run.lorem = newStr; + globalSettings.run.save(); + setState(() {}); + }, + title: "Lorem Ipsum Generator", + link: "https://loripsum.net/", + tooltip: "It uses loripsum.net.", + info: "Default Shortcut is lorem. You can specify number of pharagraphs and the length: short, medium, long, verylong", + example: ["3 short", "3 long headers", "3 short plaintext"]), + RunShortCutInfo( + value: globalSettings.run.encoders, + onChanged: (String newStr) { + globalSettings.run.encoders = newStr; + globalSettings.run.save(); + setState(() {}); + }, + title: "Encoders", + link: "https://multiencoder.net/", + tooltip: "For more encoders", + info: "Default is enc. You can use ! to encode and @ to decode, you can serialize them in [].\n Encoders are: url,base,rot13,hex,bin,ascii,@html", + example: ["!base test", "@url %20", "[@base,@rot13,!url] Z25vbnpy"]), + ]), + ), + Expanded( + child: Column( + children: [ + const Divider(height: 10, thickness: 1), + RunShortCutInfo( + value: globalSettings.run.shortcut, + onChanged: (String newStr) { + globalSettings.run.shortcut = newStr; + globalSettings.run.save(); + setState(() {}); + }, + title: "Shortcuts", + link: "https://github.com/far-se/tabame/", + tooltip: "No link", + info: "Default is s. Sub-commands are add/remove. You can add {params} to modify link.", + example: ["s add pub https://pub.dev/packages?q={params}", "s pub win32", "s remove pub"]), + ListTile( + leading: const Icon(Icons.add), + title: const Text("Add Shortcut"), + onTap: () => setState(() => runShortcuts.add(["name", "linl"])), + ), + ...List.generate(runShortcuts.length, (int index) { + return Row( + children: [ + const SizedBox(width: 17), + SizedBox( + child: InkWell( + child: const Icon(Icons.delete), + onTap: () { + runShortcuts.removeAt(index); + Boxes().runShortcuts = >[...runShortcuts]; + setState(() {}); + }, + ), + ), + const SizedBox(width: 10), + Expanded( + flex: 1, + child: TextInput( + labelText: "shortcut", + value: runShortcuts[index][0], + onChanged: (String e) { + if (e.isEmpty) return; + runShortcuts[index][0] = e; + Boxes().runShortcuts = >[...runShortcuts]; + setState(() {}); + }, + ), + ), + Expanded( + flex: 3, + child: TextInput( + value: runShortcuts[index][1], + labelText: "link", + onChanged: (String e) { + if (e.isEmpty) return; + runShortcuts[index][1] = e; + Boxes().runShortcuts = >[...runShortcuts]; + setState(() {}); + }, + ), + ) + ], + ); + }) + ], + )) + ], + ); + } +} diff --git a/lib/widgets/run/interface_utility.dart b/lib/widgets/run/interface_utility.dart new file mode 100644 index 0000000..e9d124e --- /dev/null +++ b/lib/widgets/run/interface_utility.dart @@ -0,0 +1,130 @@ +import 'package:flutter/material.dart'; + +import '../../models/classes/boxes.dart'; +import '../../models/settings.dart'; +import '../widgets/run_shortcut_widget.dart'; +import '../widgets/text_box.dart'; + +class InterfaceRunUtility extends StatefulWidget { + const InterfaceRunUtility({Key? key}) : super(key: key); + + @override + InterfaceRunUtilityState createState() => InterfaceRunUtilityState(); +} + +class InterfaceRunUtilityState extends State { + List> runKeys = Boxes().runKeys; + + @override + Widget build(BuildContext context) { + return Row(crossAxisAlignment: CrossAxisAlignment.start, children: [ + Expanded( + child: Column(mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: [ + const Divider(height: 10, thickness: 1), + RunShortCutInfo( + value: globalSettings.run.timer, + onChanged: (String newStr) { + globalSettings.run.timer = newStr; + globalSettings.run.save(); + setState(() {}); + }, + title: "Set a Timer", + link: "", + tooltip: "Sets Timer", + info: + "Sets a timer in minutes. Parameters: t [minutes] message. you can `t remove message`.\nAlso you can set which type of notification to receive:\na:Audio(default), m:MessageBox, n:Notification", + example: ["t 5 tea", "t 10 n shower", "t remove shower"]), + RunShortCutInfo( + value: globalSettings.run.setvar, + onChanged: (String newStr) { + globalSettings.run.setvar = newStr; + globalSettings.run.save(); + setState(() {}); + }, + title: "Set Variable", + link: "", + tooltip: "Sets Unique Var", + info: "Sets a unique var, this can be used with Remap keys.", + example: ["v vscode false", r"$vscode false"]), + RunShortCutInfo( + value: globalSettings.run.json, + onChanged: (String newStr) { + globalSettings.run.json = newStr; + globalSettings.run.save(); + setState(() {}); + }, + title: "Json Viewer", + link: "", + tooltip: "View Json", + info: "You do not need to paste the code in input, it will be automatically fetched from clipboard when you type the shortcut.", + example: ["json"]), + ]), + ), + Expanded( + child: Column(children: [ + RunShortCutInfo( + value: globalSettings.run.keys, + onChanged: (String newStr) { + globalSettings.run.keys = newStr; + globalSettings.run.save(); + setState(() {}); + }, + title: "Send Keys", + link: "https://docs.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes", + tooltip: "Special Key list, without VK_", + info: + "Default trigger is k.Sends Input as you saved below. You can use # to press down and ^ to release a key, to trigger special keys put them in {}. to release all use {|}", + example: ["{MEDIA_NEXT_TRACK}", "{#CTRL}{#SHIFT}W", "{#CTRL}A{|}deleted.", "{#CTRL}{#SHIFT}A{^SHIFT}C{|}{ESCAPE}"]), + ListTile( + leading: const Icon(Icons.add), + title: const Text("Add Key Shortcut"), + onTap: () => setState(() => runKeys.add(["name", "keys"])), + ), + ...List.generate(runKeys.length, (int index) { + return Row( + children: [ + const SizedBox(width: 17), + SizedBox( + child: InkWell( + child: const Icon(Icons.delete), + onTap: () { + runKeys.removeAt(index); + Boxes().runKeys = >[...runKeys]; + setState(() {}); + }, + ), + ), + const SizedBox(width: 10), + Expanded( + flex: 1, + child: TextInput( + labelText: "name", + value: runKeys[index][0], + onChanged: (String e) { + if (e.isEmpty) return; + runKeys[index][0] = e; + Boxes().runKeys = >[...runKeys]; + setState(() {}); + }, + ), + ), + Expanded( + flex: 3, + child: TextInput( + value: runKeys[index][1], + labelText: "Keys", + onChanged: (String e) { + if (e.isEmpty) return; + runKeys[index][1] = e; + Boxes().runKeys = >[...runKeys]; + setState(() {}); + }, + ), + ) + ], + ); + }) + ])) + ]); + } +} diff --git a/lib/widgets/widgets/info_widget.dart b/lib/widgets/widgets/info_widget.dart new file mode 100644 index 0000000..3da36b8 --- /dev/null +++ b/lib/widgets/widgets/info_widget.dart @@ -0,0 +1,20 @@ +// ignore_for_file: public_member_api_docs, sort_constructors_first +import 'package:flutter/material.dart'; + +class InfoWidget extends StatelessWidget { + final Function() onTap; + final String text; + const InfoWidget( + this.text, { + Key? key, + required this.onTap, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + return InkWell( + onTap: () => onTap(), + child: Tooltip(message: text, child: Icon(Icons.info_outline, color: Theme.of(context).toggleableActiveColor)), + ); + } +} diff --git a/lib/widgets/widgets/run_shortcut_widget.dart b/lib/widgets/widgets/run_shortcut_widget.dart new file mode 100644 index 0000000..f247903 --- /dev/null +++ b/lib/widgets/widgets/run_shortcut_widget.dart @@ -0,0 +1,94 @@ +import 'package:flutter/material.dart'; + +import '../../models/win32/win32.dart'; +import 'info_widget.dart'; +import 'text_box.dart'; + +class RunShortCutInfo extends StatelessWidget { + final Function(String newVal) onChanged; + + final String title; + final String value; + final String link; + final String tooltip; + final String info; + final List example; + const RunShortCutInfo({ + Key? key, + required this.onChanged, + required this.title, + required this.value, + required this.link, + required this.tooltip, + required this.info, + required this.example, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + return Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + ListTile(onTap: () {}, title: Text(title, style: Theme.of(context).textTheme.titleLarge)), + Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + ListTile( + title: TextInput( + value: value, + labelText: "Shortcuts", + onChanged: (String newVal) { + if (newVal.isEmpty) return false; + final List listTriggers = newVal.split(';'); + if (listTriggers.length > 1) { + bool worked = true; + try { + RegExp(listTriggers.last, caseSensitive: false).hasMatch("Ciulama"); + } catch (e) { + print(e); + worked = false; + ScaffoldMessenger.of(context) + .showSnackBar(SnackBar(content: Text("Error: Regex Failed!\n$e"), duration: const Duration(seconds: 4), backgroundColor: Colors.red.shade600)); + } + if (!worked) return false; + } + onChanged(newVal); + }, + ), + leading: InfoWidget(tooltip, onTap: () => WinUtils.open(link)), + ), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 20), + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text("$info"), + const SizedBox(height: 5), + Wrap( + alignment: WrapAlignment.start, + children: List.generate( + example.length, + (int index) => Container( + padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 4), + margin: const EdgeInsets.symmetric(horizontal: 5, vertical: 2), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(20), + color: Theme.of(context).colorScheme.primary, + ), + child: Text( + example[index], + style: TextStyle(color: Theme.of(context).backgroundColor, fontSize: 12, height: 1.00001), + )))), + ], + ), + ), + const Divider(height: 10, thickness: 1) + ], + ), + ], + ); + } +} diff --git a/lib/widgets/widgets/text_box.dart b/lib/widgets/widgets/text_box.dart index ac17aa5..cdd7c16 100644 --- a/lib/widgets/widgets/text_box.dart +++ b/lib/widgets/widgets/text_box.dart @@ -5,8 +5,8 @@ class TextInput extends StatefulWidget { final String labelText; final String? hintText; final String? value; - final Function(String) onChanged; - final Function(String)? onUpdated; + final Function(String val) onChanged; + final Function(String val)? onUpdated; const TextInput({ Key? key, required this.labelText, diff --git a/lib/widgets/wizardly/search_text_widget.dart b/lib/widgets/wizardly/find_text.dart similarity index 99% rename from lib/widgets/wizardly/search_text_widget.dart rename to lib/widgets/wizardly/find_text.dart index 15dd443..36c7d94 100644 --- a/lib/widgets/wizardly/search_text_widget.dart +++ b/lib/widgets/wizardly/find_text.dart @@ -6,7 +6,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_markdown/flutter_markdown.dart'; import '../../models/classes/boxes.dart'; -import '../../models/utils.dart'; +import '../../models/settings.dart'; import '../../models/win32/win32.dart'; import '../widgets/checkbox_widget.dart'; import '../widgets/info_text.dart'; diff --git a/lib/widgets/wizardly/file_size_widget.dart b/lib/widgets/wizardly/folder_size_scan.dart similarity index 96% rename from lib/widgets/wizardly/file_size_widget.dart rename to lib/widgets/wizardly/folder_size_scan.dart index d357160..2fadcba 100644 --- a/lib/widgets/wizardly/file_size_widget.dart +++ b/lib/widgets/wizardly/folder_size_scan.dart @@ -5,7 +5,7 @@ import 'dart:math'; import 'package:flutter/material.dart'; -import '../../models/utils.dart'; +import '../../models/settings.dart'; import '../../models/win32/win32.dart'; import '../widgets/info_text.dart'; import '../widgets/mouse_scroll_widget.dart'; @@ -166,6 +166,23 @@ class FileSizeWidgetState extends State { fit: FlexFit.loose, child: ElevatedButton( onPressed: () async { + if (currentFolder.contains(RegExp(r'^[A-Z]:\\$'))) { + currentFolder = ""; + + showDialog( + context: context, + builder: (BuildContext context) { + return AlertDialog( + content: Container(height: 100, child: const Text("Can't process Drive, only folders!")), + actions: [ + ElevatedButton( + onPressed: () => Navigator.of(context).pop(), child: Text("Ok", style: TextStyle(color: Color(globalSettings.theme.background)))), + ], + ); + }, + ).then((_) {}); + return; + } finishedProcessing = false; setState(() {}); if (currentFolder.isEmpty) return; diff --git a/lib/widgets/wizardly/project_overview.dart b/lib/widgets/wizardly/project_overview.dart index d871e2e..950b67d 100644 --- a/lib/widgets/wizardly/project_overview.dart +++ b/lib/widgets/wizardly/project_overview.dart @@ -8,7 +8,7 @@ import 'package:flutter_markdown/flutter_markdown.dart'; import 'package:intl/intl.dart'; import '../../models/classes/boxes.dart'; -import '../../models/utils.dart'; +import '../../models/settings.dart'; import '../widgets/checkbox_widget.dart'; import '../widgets/info_text.dart'; import '../widgets/text_box.dart'; @@ -236,7 +236,7 @@ Summing **${project.totalChars.decimal}** characters! If you wrote a book with 2 itemBuilder: (BuildContext context, int index) { return InkWell( onTap: () {}, - child: Text("${project.programmingLanguages[index][0]}: ${project.programmingLanguages[index][1]}"), + child: Text("${project.programmingLanguages[index][0]}: ${int.parse(project.programmingLanguages[index][1]).decimal}"), ); }), ) @@ -502,7 +502,7 @@ Summing **${project.totalChars.decimal}** characters! If you wrote a book with 2 } extension DecimalFormat on int { - get decimal => NumberFormat.decimalPattern().format(this); + String get decimal => NumberFormat.decimalPattern().format(this); } class TotalCode { diff --git a/lib/widgets/wizardly/file_name_widget.dart b/lib/widgets/wizardly/rename_files.dart similarity index 86% rename from lib/widgets/wizardly/file_name_widget.dart rename to lib/widgets/wizardly/rename_files.dart index d0ab792..a658ece 100644 --- a/lib/widgets/wizardly/file_name_widget.dart +++ b/lib/widgets/wizardly/rename_files.dart @@ -6,7 +6,7 @@ import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:intl/intl.dart'; -import '../../models/utils.dart'; +import '../../models/settings.dart'; import '../../pages/interface.dart'; import '../widgets/info_text.dart'; import '../widgets/mouse_scroll_widget.dart'; @@ -87,6 +87,32 @@ class FileNameWidgetState extends State { await for (FileSystemEntity entity in stream) { loadedFiles.add(entity.path); } + if (loadedFiles.length > 500) { + showDialog( + context: context, + builder: (BuildContext context) { + return AlertDialog( + content: Container( + height: 50, + child: Center( + child: Text("Too many files, maximum 500 is recomended and you are trying to load ${loadedFiles.length}!", + style: const TextStyle(fontSize: 20)))), + actions: [ + ElevatedButton( + onPressed: () { + filesHaveBeenLoaded = true; + if (mounted) setState(() {}); + Navigator.of(context).pop(); + }, + child: Text("Process", style: TextStyle(color: Theme.of(context).backgroundColor))), + ElevatedButton( + onPressed: () => Navigator.of(context).pop(), child: Text("Cancel", style: TextStyle(color: Theme.of(context).backgroundColor))), + ], + ); + }, + ).then((_) {}); + return; + } filesHaveBeenLoaded = true; if (mounted) setState(() {}); }, @@ -250,6 +276,7 @@ class FileNameWidgetState extends State { ], ); }), + if (filesHaveBeenLoaded) Padding( padding: const EdgeInsets.symmetric(horizontal: 10), @@ -267,28 +294,31 @@ class FileNameWidgetState extends State { }, ), const Divider(height: 5, thickness: 1), - ...List.generate(loadedFiles.length, (int index) { - final String file = loadedFiles[index].replaceFirst("${Directory(loadedFiles[index]).parent.path}\\", ""); - final String fullPathFile = loadedFiles[index]; - String newFile = getNewFileName(file); - return ListTileFile( - checkbox: !excludedFiles.contains(fullPathFile), - oldName: file, - newName: newFile, - onCheckPressed: (bool val) { - if (val == false) { - excludedFiles.add(fullPathFile); - } else { - excludedFiles.remove(fullPathFile); - } - setState(() {}); - }, - onRenamePressed: () { - renameFile(fullPathFile, newFile); - setState(() {}); - }, - ); - }) + ListView.builder( + shrinkWrap: true, + itemCount: loadedFiles.length, + itemBuilder: (BuildContext context, int index) { + final String file = loadedFiles[index].replaceFirst("${Directory(loadedFiles[index]).parent.path}\\", ""); + final String fullPathFile = loadedFiles[index]; + String newFile = getNewFileName(file); + return ListTileFile( + checkbox: !excludedFiles.contains(fullPathFile), + oldName: file, + newName: newFile, + onCheckPressed: (bool val) { + if (val == false) { + excludedFiles.add(fullPathFile); + } else { + excludedFiles.remove(fullPathFile); + } + setState(() {}); + }, + onRenamePressed: () { + renameFile(fullPathFile, newFile); + setState(() {}); + }, + ); + }) ], ), ), diff --git a/tabamewin32/lib/tabamewin32.dart b/tabamewin32/lib/tabamewin32.dart index 42d42aa..eff112c 100644 --- a/tabamewin32/lib/tabamewin32.dart +++ b/tabamewin32/lib/tabamewin32.dart @@ -361,7 +361,7 @@ Future setStartOnSystemStartup(bool enabled, {String? exePath, int showCmd 'exePath': exePath, 'enabled': enabled, 'showCmd': showCmd, - 'args': "-strudel", + 'args': args, }; await audioMethodChannel.invokeMethod('setStartOnSystemStartup', arguments); return;