From 559db70b1965a21fbf48dadd5ff9f97ccbe17139 Mon Sep 17 00:00:00 2001 From: Deniz <49831545+creeperkafasi@users.noreply.github.com> Date: Fri, 29 Sep 2023 22:31:38 +0300 Subject: [PATCH] Added some keyboard shortcuts: ctrl+d to switch dark mode (global) ctrl+f to open search escape to dissmiss dialogs --- lib/home.dart | 426 ++++++++++++++++++++++++++------------------------ lib/main.dart | 11 ++ 2 files changed, 232 insertions(+), 205 deletions(-) diff --git a/lib/home.dart b/lib/home.dart index 191b7c6..561ff18 100644 --- a/lib/home.dart +++ b/lib/home.dart @@ -22,227 +22,243 @@ class HomePage extends StatefulWidget { class _HomePageState extends State { @override Widget build(BuildContext context) { - return Builder(builder: (context) { - return Scaffold( - appBar: AppBar( - title: const Text("Miteru"), - actions: [ - Builder(builder: (context) { - final brightness = Theme.of(context).brightness; - return IconButton( - onPressed: () async { - final prefs = await SharedPreferences.getInstance(); - setState(() { - prefs.setBool( - "brightness", !(prefs.getBool("brightness") ?? true)); - widget.refreshFunc(); - }); - }, - icon: Icon( - (brightness == Brightness.dark) - ? Icons.dark_mode - : Icons.light_mode, + return Shortcuts( + shortcuts: { + const CharacterActivator("f", control: true): VoidCallbackIntent( + () => showSearch(context: context, delegate: AnimeSearchDelegate()), + ), + }, + child: Focus( + autofocus: true, + child: Builder(builder: (context) { + return Scaffold( + appBar: AppBar( + title: const Text("Miteru"), + actions: [ + Builder(builder: (context) { + final brightness = Theme.of(context).brightness; + return IconButton( + onPressed: () async { + final prefs = await SharedPreferences.getInstance(); + setState(() { + prefs.setBool("brightness", + !(prefs.getBool("brightness") ?? true)); + widget.refreshFunc(); + }); + }, + icon: Icon( + (brightness == Brightness.dark) + ? Icons.dark_mode + : Icons.light_mode, + ), + ); + }), + IconButton( + onPressed: () { + showSearch( + context: context, delegate: AnimeSearchDelegate()); + }, + icon: const Icon(Icons.search), ), - ); - }), - IconButton( - onPressed: () { - showSearch(context: context, delegate: AnimeSearchDelegate()); - }, - icon: const Icon(Icons.search), + ], ), - ], - ), - drawer: Drawer( - child: Padding( - padding: const EdgeInsets.all(8.0), - child: ListView( - children: [ - Padding( - padding: const EdgeInsets.all(8.0), - child: Center( - child: Text( - "見てる", - style: TextStyle( - color: Theme.of(context).colorScheme.primary, - fontWeight: FontWeight.bold, - fontSize: 40, + drawer: Drawer( + child: Padding( + padding: const EdgeInsets.all(8.0), + child: ListView( + children: [ + Padding( + padding: const EdgeInsets.all(8.0), + child: Center( + child: Text( + "見てる", + style: TextStyle( + color: Theme.of(context).colorScheme.primary, + fontWeight: FontWeight.bold, + fontSize: 40, + ), + ), ), ), - ), - ), - const Divider(), - TextButton.icon( - onPressed: () => Navigator.push( - context, - MaterialPageRoute( - builder: (context) => const TrackingScreen(), + const Divider(), + TextButton.icon( + onPressed: () => Navigator.push( + context, + MaterialPageRoute( + builder: (context) => const TrackingScreen(), + ), + ), + label: const Text("Tracking"), + icon: const Icon(Icons.remove_red_eye_outlined), ), - ), - label: const Text("Tracking"), - icon: const Icon(Icons.remove_red_eye_outlined), + ], ), - ], + ), ), - ), - ), - body: RefreshIndicator( - onRefresh: () async { - setState(() {}); - }, - child: ListView( - children: [ - HomePageShelf( - title: "Popular Today", - icon: const Icon(Icons.emoji_emotions_outlined), - color: Colors.pink, - shelfItems: Future.sync(() async { - final resJson = await AllanimeAPI.queryPopular(); - return (resJson["data"]["queryPopular"]["recommendations"] - as List) - .map( - (e) => InkWell( - onTap: () => Navigator.push( - context, - MaterialPageRoute( - builder: (context) => - ShowOverview(showData: e["anyCard"]), - ), - ), - child: Padding( - padding: const EdgeInsets.all(8.0), - child: SizedBox( - width: 100, - child: Column( - children: [ - ClipRRect( - borderRadius: BorderRadius.circular(8.0), - child: Image.network( - e["anyCard"]["thumbnail"], - height: 130, - ), - ), - Text( - (e["anyCard"]["englishName"] ?? - e["anyCard"]["name"]) - .toString(), - overflow: TextOverflow.ellipsis, + body: RefreshIndicator( + onRefresh: () async { + setState(() {}); + }, + child: ListView( + children: [ + HomePageShelf( + title: "Popular Today", + icon: const Icon(Icons.emoji_emotions_outlined), + color: Colors.pink, + shelfItems: Future.sync(() async { + final resJson = await AllanimeAPI.queryPopular(); + return (resJson["data"]["queryPopular"]["recommendations"] + as List) + .map( + (e) => InkWell( + onTap: () => Navigator.push( + context, + MaterialPageRoute( + builder: (context) => + ShowOverview(showData: e["anyCard"]), + ), + ), + child: Padding( + padding: const EdgeInsets.all(8.0), + child: SizedBox( + width: 100, + child: Column( + children: [ + ClipRRect( + borderRadius: + BorderRadius.circular(8.0), + child: Image.network( + e["anyCard"]["thumbnail"], + height: 130, + ), + ), + Text( + (e["anyCard"]["englishName"] ?? + e["anyCard"]["name"]) + .toString(), + overflow: TextOverflow.ellipsis, + ), + ], ), - ], + ), ), ), - ), - ), - ) - .toList(); - }), - ), - HomePageShelf( - title: "Recent Uploads", - icon: const Icon(Icons.history), - color: Colors.lime, - shelfItems: Future.sync(() async { - // Searching with an empty query returns all shows sorted by recent - final items = - (await AllanimeAPI.search("", origin: "JP"))["data"] - ["shows"]["edges"] as List; - // Filter out the garbage - items.removeWhere( - (element) => - (double.parse((element["score"] ?? 0).toString()) <= - 6.5), - ); - return (items) - .map( - (e) => InkWell( - onTap: () => Navigator.push( - context, - MaterialPageRoute( - builder: (context) => ShowOverview(showData: e), - ), - ), - child: Padding( - padding: const EdgeInsets.all(8.0), - child: SizedBox( - width: 100, - child: Column( - children: [ - ClipRRect( - borderRadius: BorderRadius.circular(8.0), - child: Image.network( - e["thumbnail"], - height: 130, - ), - ), - Text( - (e["englishName"] ?? e["name"]).toString(), - overflow: TextOverflow.ellipsis, + ) + .toList(); + }), + ), + HomePageShelf( + title: "Recent Uploads", + icon: const Icon(Icons.history), + color: Colors.lime, + shelfItems: Future.sync(() async { + // Searching with an empty query returns all shows sorted by recent + final items = + (await AllanimeAPI.search("", origin: "JP"))["data"] + ["shows"]["edges"] as List; + // Filter out the garbage + items.removeWhere( + (element) => + (double.parse((element["score"] ?? 0).toString()) <= + 6.5), + ); + return (items) + .map( + (e) => InkWell( + onTap: () => Navigator.push( + context, + MaterialPageRoute( + builder: (context) => + ShowOverview(showData: e), + ), + ), + child: Padding( + padding: const EdgeInsets.all(8.0), + child: SizedBox( + width: 100, + child: Column( + children: [ + ClipRRect( + borderRadius: + BorderRadius.circular(8.0), + child: Image.network( + e["thumbnail"], + height: 130, + ), + ), + Text( + (e["englishName"] ?? e["name"]) + .toString(), + overflow: TextOverflow.ellipsis, + ), + ], ), - ], + ), ), ), - ), - ), - ) - .toList(); - }), - ), - HomePageShelf( - title: "Kitsu tracker", - icon: const Icon(Icons.remove_red_eye_outlined), - shelfItems: Future.sync(() async { - final prefs = await SharedPreferences.getInstance(); - if (prefs.getString("kitsu-User") == null) { - throw Exception("Kitsu user not set"); - } - final lib = await KitsuApi.getUserLibrary( - prefs.getString("kitsu-User") ?? "", - filters: { - "status": "current", - "kind": "anime", - }, - ); - return (lib["data"] as List) - .map( - kitsuButton, - ) - .toList(); - }), - color: Colors.orange, - onErrorWidget: (error) => Container( - color: Theme.of(context).colorScheme.error.withOpacity(0.5), - width: MediaQuery.of(context).size.width, - height: 168, - child: Center( - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - Text( - "$error", - style: TextStyle( - color: Theme.of(context).colorScheme.onError, - ), - ), - ElevatedButton.icon( - onPressed: () => Navigator.push( - context, - MaterialPageRoute( - builder: (context) => const TrackingScreen(), + ) + .toList(); + }), + ), + HomePageShelf( + title: "Kitsu tracker", + icon: const Icon(Icons.remove_red_eye_outlined), + shelfItems: Future.sync(() async { + final prefs = await SharedPreferences.getInstance(); + if (prefs.getString("kitsu-User") == null) { + throw Exception("Kitsu user not set"); + } + final lib = await KitsuApi.getUserLibrary( + prefs.getString("kitsu-User") ?? "", + filters: { + "status": "current", + "kind": "anime", + }, + ); + return (lib["data"] as List) + .map( + kitsuButton, + ) + .toList(); + }), + color: Colors.orange, + onErrorWidget: (error) => Container( + color: + Theme.of(context).colorScheme.error.withOpacity(0.5), + width: MediaQuery.of(context).size.width, + height: 168, + child: Center( + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + "$error", + style: TextStyle( + color: Theme.of(context).colorScheme.onError, + ), ), - ), - icon: const Icon(Icons.remove_red_eye_outlined), - label: const Text("Open Tracking Menu"), + ElevatedButton.icon( + onPressed: () => Navigator.push( + context, + MaterialPageRoute( + builder: (context) => const TrackingScreen(), + ), + ), + icon: const Icon(Icons.remove_red_eye_outlined), + label: const Text("Open Tracking Menu"), + ), + ], ), - ], + ), ), - ), - ), - ) - ], - ), - ), - ); - }); + ) + ], + ), + ), + ); + }), + ), + ); } FutureBuilder kitsuButton(e) => FutureBuilder( diff --git a/lib/main.dart b/lib/main.dart index 053ce24..6ea6a22 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,6 +1,7 @@ import 'dart:io'; import 'package:flutter/scheduler.dart'; +import 'package:flutter/services.dart'; import 'package:fvp/fvp.dart'; import 'package:miteru/home.dart'; import 'package:flutter/material.dart'; @@ -48,6 +49,16 @@ class _AnimeAppState extends State { return MaterialApp( debugShowCheckedModeBanner: false, debugShowMaterialGrid: false, + shortcuts: { + ...WidgetsApp.defaultShortcuts, + const CharacterActivator("d", control: true): + VoidCallbackIntent(() async { + final prefs = await SharedPreferences.getInstance(); + prefs.setBool("brightness", !(prefs.getBool("brightness") ?? true)); + refresh(); + }), + LogicalKeySet(LogicalKeyboardKey.escape): const DismissIntent(), + }, title: "Miteru", theme: ThemeData.from( colorScheme: ColorScheme.fromSeed(