Merge branch 'dev' into 'master'
bugfixes no. 1 Closes #7, #6, #2, #3, #1, #5, and #4 See merge request odweta/hlaskovnik_reimagined!2
This commit is contained in:
@@ -20,12 +20,11 @@ android {
|
|||||||
}
|
}
|
||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
|
|
||||||
applicationId = "app.odweta.novehlasky"
|
applicationId = "app.odweta.novehlasky"
|
||||||
// You can update the following values to match your application needs.
|
// You can update the following values to match your application needs.
|
||||||
// For more information, see: https://flutter.dev/to/review-gradle-config.
|
// For more information, see: https://flutter.dev/to/review-gradle-config.
|
||||||
minSdk = flutter.minSdkVersion
|
minSdk = flutter.minSdkVersion
|
||||||
targetSdk = flutter.targetSdkVersion
|
targetSdk = 33
|
||||||
versionCode = flutter.versionCode
|
versionCode = flutter.versionCode
|
||||||
versionName = flutter.versionName
|
versionName = flutter.versionName
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,8 @@
|
|||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
package="app.odweta.novehlasky">
|
||||||
|
<uses-permission android:name="android.permission.INTERNET"/>
|
||||||
|
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
|
||||||
|
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
|
||||||
<application
|
<application
|
||||||
android:label="frontend"
|
android:label="frontend"
|
||||||
android:name="${applicationName}"
|
android:name="${applicationName}"
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
package com.example.frontend
|
package app.odweta.novehlasky
|
||||||
|
|
||||||
import io.flutter.embedding.android.FlutterActivity
|
import io.flutter.embedding.android.FlutterActivity
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,9 @@ import 'pages/flashcards.dart';
|
|||||||
import 'pages/leaderboard.dart';
|
import 'pages/leaderboard.dart';
|
||||||
//import 'pages/settings.dart';
|
//import 'pages/settings.dart';
|
||||||
|
|
||||||
void main() {
|
void main() async {
|
||||||
|
WidgetsFlutterBinding.ensureInitialized();
|
||||||
|
final isDark = await loadDarkMode();
|
||||||
runApp(
|
runApp(
|
||||||
MultiProvider(
|
MultiProvider(
|
||||||
providers: [
|
providers: [
|
||||||
@@ -24,7 +26,7 @@ void main() {
|
|||||||
create: (_) => QuoteProvider()
|
create: (_) => QuoteProvider()
|
||||||
),
|
),
|
||||||
ChangeNotifierProvider(
|
ChangeNotifierProvider(
|
||||||
create: (_) => ThemeProvider()
|
create: (_) => ThemeProvider(isDark: isDark)
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
child: HlaskovnikFrontendApp()
|
child: HlaskovnikFrontendApp()
|
||||||
|
|||||||
@@ -1,9 +1,6 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
import 'package:frontend/provider/quote_provider.dart';
|
import 'package:frontend/provider/quote_provider.dart';
|
||||||
|
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
import 'package:frontend/values/strings.dart';
|
import 'package:frontend/values/strings.dart';
|
||||||
import 'package:frontend/values/constants.dart';
|
import 'package:frontend/values/constants.dart';
|
||||||
|
|
||||||
@@ -12,10 +9,10 @@ class FlashcardsPage extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
//return const Center(child: Text('flashcards! flip flip'));
|
|
||||||
final provider = Provider.of<QuoteProvider>(context);
|
final provider = Provider.of<QuoteProvider>(context);
|
||||||
if (provider.randomQuoteText == "dummy" ||
|
|
||||||
provider.randomQuoteText == "quote text") { provider.nextRandomQuote(); } // initialize the random quote variable
|
final screenWidth = MediaQuery.of(context).size.width;
|
||||||
|
|
||||||
return Card(
|
return Card(
|
||||||
margin: const EdgeInsets.all(Constants.edgeInset),
|
margin: const EdgeInsets.all(Constants.edgeInset),
|
||||||
child: Padding(
|
child: Padding(
|
||||||
@@ -23,43 +20,65 @@ class FlashcardsPage extends StatelessWidget {
|
|||||||
child: Column(
|
child: Column(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
children: [
|
children: [
|
||||||
|
const Spacer(),
|
||||||
|
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.all(Constants.edgeInset*2),
|
padding: const EdgeInsets.all(Constants.edgeInset),
|
||||||
child: Text(provider.randomQuoteText,
|
child: Text(
|
||||||
|
provider.randomQuoteText,
|
||||||
|
textAlign: TextAlign.center,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 35,
|
fontSize: screenWidth * 0.06, // responsive text
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Column(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.end,
|
const Spacer(),
|
||||||
|
|
||||||
|
// Buttons side by side
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||||
children: [
|
children: [
|
||||||
Padding(
|
Expanded(
|
||||||
|
child: Padding(
|
||||||
padding: const EdgeInsets.all(Constants.edgeInset),
|
padding: const EdgeInsets.all(Constants.edgeInset),
|
||||||
child: TextButton.icon(
|
child: TextButton.icon(
|
||||||
onPressed: provider.flipRandomQuote,
|
onPressed: provider.flipRandomQuote,
|
||||||
icon: Icon(Icons.repeat,
|
icon: const Icon(
|
||||||
size: 35,
|
Icons.repeat,
|
||||||
|
size: 28,
|
||||||
),
|
),
|
||||||
label: Text(Strings.flipFlashcard,
|
label: Text(
|
||||||
|
Strings.flipFlashcard,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 35,
|
fontSize: screenWidth * 0.045,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
style: TextButton.styleFrom(
|
||||||
|
padding: const EdgeInsets.symmetric(vertical: 16),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Padding(
|
Expanded(
|
||||||
|
child: Padding(
|
||||||
padding: const EdgeInsets.all(Constants.edgeInset),
|
padding: const EdgeInsets.all(Constants.edgeInset),
|
||||||
child: TextButton.icon(
|
child: TextButton.icon(
|
||||||
onPressed: provider.nextRandomQuote,
|
onPressed: provider.nextRandomQuote,
|
||||||
icon: Icon(Icons.arrow_right_alt,
|
icon: const Icon(
|
||||||
size: 35,
|
Icons.arrow_right_alt,
|
||||||
|
size: 28,
|
||||||
),
|
),
|
||||||
label: Text(Strings.nextFlashcard,
|
label: Text(
|
||||||
|
Strings.nextFlashcard,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 35,
|
fontSize: screenWidth * 0.045,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
style: TextButton.styleFrom(
|
||||||
|
padding: const EdgeInsets.symmetric(vertical: 16),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -3,24 +3,42 @@ import 'package:frontend/provider/quote_provider.dart';
|
|||||||
import 'package:frontend/values/constants.dart';
|
import 'package:frontend/values/constants.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
class LeaderboardPage extends StatelessWidget {
|
class LeaderboardPage extends StatefulWidget {
|
||||||
const LeaderboardPage({super.key});
|
const LeaderboardPage({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<LeaderboardPage> createState() => _LeaderboardPageState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _LeaderboardPageState extends State<LeaderboardPage> {
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
|
||||||
|
// reset filter once, only when page is created
|
||||||
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
|
final provider = context.read<QuoteProvider>();
|
||||||
|
provider.resetLeaderboardFilter();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final provider = context.watch<QuoteProvider>();
|
final provider = context.watch<QuoteProvider>();
|
||||||
|
|
||||||
return Center(
|
return Center(
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
Expanded(
|
Expanded(
|
||||||
child: ListView.builder(
|
child: ListView.builder(
|
||||||
padding: EdgeInsets.all(Constants.edgeInset),
|
padding: EdgeInsets.all(Constants.edgeInset),
|
||||||
itemCount: provider.filteredQuotes.length,
|
itemCount: provider.sortedAuthorCounts.length,
|
||||||
itemBuilder: (context, index) {
|
itemBuilder: (context, index) {
|
||||||
return
|
return
|
||||||
Card(
|
Card(
|
||||||
color: provider.getLeaderboardEntryBgColor(context, index),
|
color: provider.getLeaderboardEntryBgColor(context, index),
|
||||||
child: ListTile(
|
child: ListTile(
|
||||||
|
onTap: () { provider.showListPageFilteredByAuthor(context, index); },
|
||||||
contentPadding: EdgeInsets.symmetric(
|
contentPadding: EdgeInsets.symmetric(
|
||||||
vertical: 0,
|
vertical: 0,
|
||||||
horizontal: Constants.edgeInset,
|
horizontal: Constants.edgeInset,
|
||||||
|
|||||||
@@ -8,9 +8,14 @@ import 'package:provider/provider.dart';
|
|||||||
|
|
||||||
import 'package:frontend/values/constants.dart';
|
import 'package:frontend/values/constants.dart';
|
||||||
|
|
||||||
class ListPage extends StatelessWidget {
|
class ListPage extends StatefulWidget {
|
||||||
const ListPage({super.key});
|
const ListPage({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<ListPage> createState() => _ListPageState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _ListPageState extends State<ListPage> {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final provider = context.watch<QuoteProvider>();
|
final provider = context.watch<QuoteProvider>();
|
||||||
@@ -40,9 +45,7 @@ class ListPage extends StatelessWidget {
|
|||||||
Center(
|
Center(
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.only(
|
padding: const EdgeInsets.only(
|
||||||
left: Constants.edgeInset,
|
top: Constants.edgeInset*2
|
||||||
right: Constants.edgeInset,
|
|
||||||
top: Constants.edgeInset
|
|
||||||
),
|
),
|
||||||
child: Text(
|
child: Text(
|
||||||
'${Strings.allQuotesCount} – $quoteCount',
|
'${Strings.allQuotesCount} – $quoteCount',
|
||||||
@@ -56,7 +59,7 @@ class ListPage extends StatelessWidget {
|
|||||||
filterBar(context, provider, themeProvider),
|
filterBar(context, provider, themeProvider),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: ListView.builder(
|
child: ListView.builder(
|
||||||
padding: EdgeInsets.all(Constants.edgeInset),
|
padding: EdgeInsets.all(Constants.edgeInset/2),
|
||||||
itemCount: provider.filteredQuotes.length,
|
itemCount: provider.filteredQuotes.length,
|
||||||
itemBuilder: (context, index) {
|
itemBuilder: (context, index) {
|
||||||
final quote = provider.filteredQuotes[index];
|
final quote = provider.filteredQuotes[index];
|
||||||
@@ -275,12 +278,15 @@ class ListPage extends StatelessWidget {
|
|||||||
ListTile(
|
ListTile(
|
||||||
title: Text(Strings.exportSelectedQuotes),
|
title: Text(Strings.exportSelectedQuotes),
|
||||||
trailing: Icon(Icons.import_export),
|
trailing: Icon(Icons.import_export),
|
||||||
onTap: () {
|
onTap: () async {
|
||||||
provider.exportQuotesToFile();
|
|
||||||
Navigator.pop(context);
|
Navigator.pop(context);
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
final scaffoldMessenger = ScaffoldMessenger.of(context);
|
||||||
|
final success = await provider.exportWithSAF();
|
||||||
|
// Make sure the context is still valid
|
||||||
|
if (!mounted) return;
|
||||||
|
scaffoldMessenger.showSnackBar(
|
||||||
SnackBar(
|
SnackBar(
|
||||||
content: Text(Strings.fileExportedSuccessfully),
|
content: Text(success ? Strings.fileExportedSuccessfully + provider.exportDir : "export [x]"),
|
||||||
duration: const Duration(seconds: 3),
|
duration: const Duration(seconds: 3),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@@ -288,8 +294,8 @@ class ListPage extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
ListTile(
|
ListTile(
|
||||||
title: Text(Strings.userPrefersDarkMode),
|
title: Text(Strings.userPrefersDarkMode),
|
||||||
onTap: () { themeProvider.setDarkMode(!themeProvider.isDark); },
|
trailing: Consumer<ThemeProvider>(
|
||||||
trailing: Row(
|
builder: (context, themeProvider, _) => Row(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
Padding(
|
Padding(
|
||||||
@@ -298,13 +304,14 @@ class ListPage extends StatelessWidget {
|
|||||||
onChanged: (value) {
|
onChanged: (value) {
|
||||||
themeProvider.setDarkMode(value);
|
themeProvider.setDarkMode(value);
|
||||||
},
|
},
|
||||||
value: themeProvider.isDark
|
value: themeProvider.isDark,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Icon(Icons.dark_mode),
|
Icon(Icons.dark_mode),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,6 +1,14 @@
|
|||||||
// gets all quotes from the database and returns them in a list
|
// gets all quotes from the database and returns them in a list
|
||||||
|
|
||||||
|
import 'package:file_saver/file_saver.dart';
|
||||||
|
|
||||||
import 'package:path_provider/path_provider.dart';
|
import 'package:path_provider/path_provider.dart';
|
||||||
|
import 'package:flutter/foundation.dart'; // for kIsWeb
|
||||||
|
|
||||||
|
import 'dart:convert';
|
||||||
|
import 'dart:typed_data';
|
||||||
|
import 'package:go_router/go_router.dart';
|
||||||
|
import 'package:file_picker/file_picker.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
import 'package:frontend/model/quote.dart';
|
import 'package:frontend/model/quote.dart';
|
||||||
@@ -64,12 +72,10 @@ class QuoteProvider extends ChangeNotifier {
|
|||||||
filterController.text = '';
|
filterController.text = '';
|
||||||
}
|
}
|
||||||
|
|
||||||
Quote randomQuote = Quote(
|
late Quote randomQuote;
|
||||||
id: 0,
|
|
||||||
body: "quote text",
|
|
||||||
author: "dummy"
|
|
||||||
);
|
|
||||||
bool randomQuoteDeterminator = true;
|
bool randomQuoteDeterminator = true;
|
||||||
|
|
||||||
|
String exportDir = "";
|
||||||
String get randomQuoteText {
|
String get randomQuoteText {
|
||||||
if (randomQuoteDeterminator) {
|
if (randomQuoteDeterminator) {
|
||||||
return randomQuote.body;
|
return randomQuote.body;
|
||||||
@@ -84,6 +90,7 @@ class QuoteProvider extends ChangeNotifier {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void nextRandomQuote() {
|
void nextRandomQuote() {
|
||||||
|
if (filteredQuotes.isEmpty) return;
|
||||||
final random = Random();
|
final random = Random();
|
||||||
randomQuote = filteredQuotes[random.nextInt(filteredQuotes.length)];
|
randomQuote = filteredQuotes[random.nextInt(filteredQuotes.length)];
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
@@ -111,17 +118,20 @@ class QuoteProvider extends ChangeNotifier {
|
|||||||
|
|
||||||
Future<void> readQuotes() async {
|
Future<void> readQuotes() async {
|
||||||
_loading = true;
|
_loading = true;
|
||||||
_error = null;
|
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
_quotes = await repo.readQuotes();
|
_quotes = await repo.readQuotes();
|
||||||
|
populateAuthors();
|
||||||
|
|
||||||
|
if (_quotes.isNotEmpty) {
|
||||||
|
nextRandomQuote();
|
||||||
|
}
|
||||||
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
_error = e.toString();
|
_error = e.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
populateAuthors();
|
|
||||||
|
|
||||||
_loading = false;
|
_loading = false;
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
@@ -169,30 +179,28 @@ class QuoteProvider extends ChangeNotifier {
|
|||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<bool> exportWithSAF() async {
|
||||||
Future<Directory> _getSaveDirectory() async {
|
try {
|
||||||
if (Platform.isWindows || Platform.isLinux || Platform.isMacOS) {
|
|
||||||
final path = Platform.isWindows
|
|
||||||
? Platform.environment['USERPROFILE']
|
|
||||||
: Platform.environment['HOME'];
|
|
||||||
|
|
||||||
return Directory(path!);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Mobile fallback
|
|
||||||
return await getApplicationDocumentsDirectory();
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> exportQuotesToFile() async {
|
|
||||||
final dir = await _getSaveDirectory();
|
|
||||||
|
|
||||||
final datetime = DateTime.now().toUtc().toString()
|
final datetime = DateTime.now().toUtc().toString()
|
||||||
.replaceAll(" ", "T")
|
.replaceAll(" ", "T")
|
||||||
.replaceAll(":", "-")
|
.replaceAll(":", "-")
|
||||||
.replaceAll(RegExp(r"\..*"), "");
|
.replaceAll(RegExp(r"\..*"), "");
|
||||||
|
final filename = 'hlasky_$datetime.txt';
|
||||||
|
final content = filteredQuotes.map((q) => "${q.body} – ${q.author}").join('\n') + '\n';
|
||||||
|
final bytes = Uint8List.fromList(utf8.encode(content));
|
||||||
|
|
||||||
final file = File('${dir.path}/hlasky_$datetime.txt');
|
// Show folder picker
|
||||||
await file.writeAsString("${filteredQuotes.join("\n")}\n");
|
final folderPath = await FilePicker.platform.getDirectoryPath();
|
||||||
|
if (folderPath == null) return false; // user cancelled
|
||||||
|
exportDir = folderPath;
|
||||||
|
|
||||||
|
final file = File('$folderPath/$filename');
|
||||||
|
await file.writeAsBytes(bytes);
|
||||||
|
|
||||||
|
return true; // export successful
|
||||||
|
} catch (e) {
|
||||||
|
return false; // something went wrong
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Color getLeaderboardEntryBgColor(BuildContext context, int index) {
|
Color getLeaderboardEntryBgColor(BuildContext context, int index) {
|
||||||
@@ -218,4 +226,18 @@ class QuoteProvider extends ChangeNotifier {
|
|||||||
return Theme.of(context).textTheme.bodyMedium!.color!;
|
return Theme.of(context).textTheme.bodyMedium!.color!;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void showListPageFilteredByAuthor(BuildContext context, int index) {
|
||||||
|
filterController.text = sortedAuthorCounts[index].key;
|
||||||
|
filterBy = 0; // filter by author
|
||||||
|
// navigate to the main page
|
||||||
|
GoRouter.of(context).go('/');
|
||||||
|
Future.microtask(() => notifyListeners());
|
||||||
|
}
|
||||||
|
|
||||||
|
void resetLeaderboardFilter() {
|
||||||
|
filterController.text = '';
|
||||||
|
filterBy = 0;
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -13,22 +13,16 @@ Future<bool> loadDarkMode() async {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class ThemeProvider extends ChangeNotifier {
|
class ThemeProvider extends ChangeNotifier {
|
||||||
bool _isDark = false;
|
bool _isDark;
|
||||||
|
|
||||||
bool get isDark => _isDark;
|
bool get isDark => _isDark;
|
||||||
|
|
||||||
ThemeProvider() {
|
ThemeProvider({required bool isDark}) : _isDark = isDark;
|
||||||
_load(); // load saved value on startup
|
|
||||||
}
|
|
||||||
|
|
||||||
void _load() async {
|
void setDarkMode(bool value) {
|
||||||
_isDark = await loadDarkMode();
|
if (_isDark == value) return; // avoid unnecessary rebuilds
|
||||||
notifyListeners();
|
|
||||||
}
|
|
||||||
|
|
||||||
void setDarkMode(bool value) async {
|
|
||||||
_isDark = value;
|
_isDark = value;
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
await saveDarkMode(value);
|
saveDarkMode(value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -21,9 +21,9 @@ class Strings {
|
|||||||
|
|
||||||
static const String flipFlashcard = "Otočit flashkartu";
|
static const String flipFlashcard = "Otočit flashkartu";
|
||||||
static const String nextFlashcard = "Další flashkarta";
|
static const String nextFlashcard = "Další flashkarta";
|
||||||
|
//
|
||||||
//static const String importQuotesFromFile = "Importovat hlášky ze souboru";
|
//static const String importQuotesFromFile = "Importovat hlášky ze souboru";
|
||||||
static const String fileExportedSuccessfully = "Soubor byl úspěšně vyexportován.";
|
static const String fileExportedSuccessfully = "Soubor byl úspěšně vyexportován do: ";
|
||||||
static const String noUndo = "Tuto akci nelze odčinit.";
|
static const String noUndo = "Tuto akci nelze odčinit.";
|
||||||
static const String filterQuery = "Filtrovací požadavek";
|
static const String filterQuery = "Filtrovací požadavek";
|
||||||
static const String allQuotesCount = "Celkový počet hlášek";
|
static const String allQuotesCount = "Celkový počet hlášek";
|
||||||
|
|||||||
@@ -6,6 +6,10 @@
|
|||||||
|
|
||||||
#include "generated_plugin_registrant.h"
|
#include "generated_plugin_registrant.h"
|
||||||
|
|
||||||
|
#include <file_saver/file_saver_plugin.h>
|
||||||
|
|
||||||
void fl_register_plugins(FlPluginRegistry* registry) {
|
void fl_register_plugins(FlPluginRegistry* registry) {
|
||||||
|
g_autoptr(FlPluginRegistrar) file_saver_registrar =
|
||||||
|
fl_plugin_registry_get_registrar_for_plugin(registry, "FileSaverPlugin");
|
||||||
|
file_saver_plugin_register_with_registrar(file_saver_registrar);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
#
|
#
|
||||||
|
|
||||||
list(APPEND FLUTTER_PLUGIN_LIST
|
list(APPEND FLUTTER_PLUGIN_LIST
|
||||||
|
file_saver
|
||||||
)
|
)
|
||||||
|
|
||||||
list(APPEND FLUTTER_FFI_PLUGIN_LIST
|
list(APPEND FLUTTER_FFI_PLUGIN_LIST
|
||||||
|
|||||||
@@ -5,8 +5,12 @@
|
|||||||
import FlutterMacOS
|
import FlutterMacOS
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
|
import file_picker
|
||||||
|
import file_saver
|
||||||
import shared_preferences_foundation
|
import shared_preferences_foundation
|
||||||
|
|
||||||
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
||||||
|
FilePickerPlugin.register(with: registry.registrar(forPlugin: "FilePickerPlugin"))
|
||||||
|
FileSaverPlugin.register(with: registry.registrar(forPlugin: "FileSaverPlugin"))
|
||||||
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
|
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,14 @@
|
|||||||
# Generated by pub
|
# Generated by pub
|
||||||
# See https://dart.dev/tools/pub/glossary#lockfile
|
# See https://dart.dev/tools/pub/glossary#lockfile
|
||||||
packages:
|
packages:
|
||||||
|
args:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: args
|
||||||
|
sha256: d0481093c50b1da8910eb0bb301626d4d8eb7284aa739614d2b394ee09e3ea04
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.7.0"
|
||||||
async:
|
async:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -49,6 +57,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.19.1"
|
version: "1.19.1"
|
||||||
|
cross_file:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: cross_file
|
||||||
|
sha256: "28bb3ae56f117b5aec029d702a90f57d285cd975c3c5c281eaca38dbc47c5937"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.3.5+2"
|
||||||
crypto:
|
crypto:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -65,6 +81,30 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.9"
|
version: "1.0.9"
|
||||||
|
dbus:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: dbus
|
||||||
|
sha256: d0c98dcd4f5169878b6cf8f6e0a52403a9dff371a3e2f019697accbf6f44a270
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.7.12"
|
||||||
|
dio:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: dio
|
||||||
|
sha256: aff32c08f92787a557dd5c0145ac91536481831a01b4648136373cddb0e64f8c
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "5.9.2"
|
||||||
|
dio_web_adapter:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: dio_web_adapter
|
||||||
|
sha256: "2f9e64323a7c3c7ef69567d5c800424a11f8337b8b228bad02524c9fb3c1f340"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.1.2"
|
||||||
fake_async:
|
fake_async:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -89,6 +129,22 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "7.0.1"
|
version: "7.0.1"
|
||||||
|
file_picker:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: file_picker
|
||||||
|
sha256: "57d9a1dd5063f85fa3107fb42d1faffda52fdc948cefd5fe5ea85267a5fc7343"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "10.3.10"
|
||||||
|
file_saver:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: file_saver
|
||||||
|
sha256: "9d93db09bd4da9e43238f9dd485360fc51a5c138eea5ef5f407ec56e58079ac0"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.3.1"
|
||||||
flutter:
|
flutter:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description: flutter
|
description: flutter
|
||||||
@@ -102,6 +158,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "6.0.0"
|
version: "6.0.0"
|
||||||
|
flutter_plugin_android_lifecycle:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: flutter_plugin_android_lifecycle
|
||||||
|
sha256: "38d1c268de9097ff59cf0e844ac38759fc78f76836d37edad06fa21e182055a0"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.0.34"
|
||||||
flutter_test:
|
flutter_test:
|
||||||
dependency: "direct dev"
|
dependency: "direct dev"
|
||||||
description: flutter
|
description: flutter
|
||||||
@@ -216,6 +280,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.17.0"
|
version: "1.17.0"
|
||||||
|
mime:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: mime
|
||||||
|
sha256: "41a20518f0cb1256669420fdba0cd90d21561e560ac240f26ef8322e45bb7ed6"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.0.0"
|
||||||
native_toolchain_c:
|
native_toolchain_c:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -296,6 +368,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.3.0"
|
version: "2.3.0"
|
||||||
|
petitparser:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: petitparser
|
||||||
|
sha256: "91bd59303e9f769f108f8df05e371341b15d59e995e6806aefab827b58336675"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "7.0.2"
|
||||||
platform:
|
platform:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -469,6 +549,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.1.1"
|
version: "1.1.1"
|
||||||
|
win32:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: win32
|
||||||
|
sha256: d7cb55e04cd34096cd3a79b3330245f54cb96a370a1c27adb3c84b917de8b08e
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "5.15.0"
|
||||||
xdg_directories:
|
xdg_directories:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -477,6 +565,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.1.0"
|
version: "1.1.0"
|
||||||
|
xml:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: xml
|
||||||
|
sha256: "971043b3a0d3da28727e40ed3e0b5d18b742fa5a68665cca88e74b7876d5e025"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "6.6.1"
|
||||||
yaml:
|
yaml:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|||||||
@@ -39,6 +39,8 @@ dependencies:
|
|||||||
http: ^1.2.0
|
http: ^1.2.0
|
||||||
path_provider:
|
path_provider:
|
||||||
shared_preferences: ^2.1.1
|
shared_preferences: ^2.1.1
|
||||||
|
file_picker: ^10.3.10
|
||||||
|
file_saver: ^0.3.1
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
|
|||||||
@@ -6,6 +6,9 @@
|
|||||||
|
|
||||||
#include "generated_plugin_registrant.h"
|
#include "generated_plugin_registrant.h"
|
||||||
|
|
||||||
|
#include <file_saver/file_saver_plugin.h>
|
||||||
|
|
||||||
void RegisterPlugins(flutter::PluginRegistry* registry) {
|
void RegisterPlugins(flutter::PluginRegistry* registry) {
|
||||||
|
FileSaverPluginRegisterWithRegistrar(
|
||||||
|
registry->GetRegistrarForPlugin("FileSaverPlugin"));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
#
|
#
|
||||||
|
|
||||||
list(APPEND FLUTTER_PLUGIN_LIST
|
list(APPEND FLUTTER_PLUGIN_LIST
|
||||||
|
file_saver
|
||||||
)
|
)
|
||||||
|
|
||||||
list(APPEND FLUTTER_FFI_PLUGIN_LIST
|
list(APPEND FLUTTER_FFI_PLUGIN_LIST
|
||||||
|
|||||||
Reference in New Issue
Block a user