From 0a0e2f403b63af5b8154b46c86b53d310d17f5a7 Mon Sep 17 00:00:00 2001 From: robert3141 Date: Sun, 22 Sep 2019 10:52:39 +0100 Subject: [PATCH 1/5] Added files for web update --- ios/Flutter/flutter_export_environment.sh | 10 ++++ lib/main.dart | 1 + pubspec.lock | 69 +++++++++++++++++++---- pubspec.yaml | 2 +- web/index.html | 10 ++++ 5 files changed, 81 insertions(+), 11 deletions(-) create mode 100644 ios/Flutter/flutter_export_environment.sh create mode 100644 web/index.html diff --git a/ios/Flutter/flutter_export_environment.sh b/ios/Flutter/flutter_export_environment.sh new file mode 100644 index 0000000..7071c6a --- /dev/null +++ b/ios/Flutter/flutter_export_environment.sh @@ -0,0 +1,10 @@ +#!/bin/sh +# This is a generated file; do not edit or check into version control. +export "FLUTTER_ROOT=C:\src\flutter" +export "FLUTTER_APPLICATION_PATH=C:\Users\Robert\AndroidStudioProjects\Flashcards\master\flashcards" +export "FLUTTER_TARGET=lib\main.dart" +export "FLUTTER_BUILD_DIR=build" +export "SYMROOT=${SOURCE_ROOT}/../build\ios" +export "FLUTTER_FRAMEWORK_DIR=C:\src\flutter\bin\cache\artifacts\engine\ios" +export "FLUTTER_BUILD_NAME=6.2.1" +export "FLUTTER_BUILD_NUMBER=22" diff --git a/lib/main.dart b/lib/main.dart index 2162e1f..79847e6 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -77,6 +77,7 @@ class Strings{ static String editCardsCardNo = "Card Number: "; static String editCardsFront = "Front of Card"; static String editCardsRear = "Back of Card"; + static String editDelete = "Deleting Card"; //Error Messages static String errorImport = "Error Importing Flashcards:\n"; diff --git a/pubspec.lock b/pubspec.lock index e139db1..a91fd94 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -1,20 +1,34 @@ # Generated by pub # See https://dart.dev/tools/pub/glossary#lockfile packages: + archive: + dependency: transitive + description: + name: archive + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.10" + args: + dependency: transitive + description: + name: args + url: "https://pub.dartlang.org" + source: hosted + version: "1.5.2" async: dependency: transitive description: name: async url: "https://pub.dartlang.org" source: hosted - version: "2.2.0" + version: "2.3.0" boolean_selector: dependency: transitive description: name: boolean_selector url: "https://pub.dartlang.org" source: hosted - version: "1.0.4" + version: "1.0.5" charcode: dependency: transitive description: @@ -29,6 +43,20 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.14.11" + convert: + dependency: transitive + description: + name: convert + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.1" + crypto: + dependency: transitive + description: + name: crypto + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.3" cupertino_icons: dependency: "direct main" description: @@ -49,7 +77,7 @@ packages: name: file_picker url: "https://pub.dartlang.org" source: hosted - version: "1.3.8" + version: "1.4.1" flip_card: dependency: "direct main" description: @@ -68,12 +96,19 @@ packages: name: flutter_material_color_picker url: "https://pub.dartlang.org" source: hosted - version: "1.0.3" + version: "1.0.5" flutter_test: dependency: "direct dev" description: flutter source: sdk version: "0.0.0" + image: + dependency: transitive + description: + name: image + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.4" matcher: dependency: transitive description: @@ -87,28 +122,35 @@ packages: name: meta url: "https://pub.dartlang.org" source: hosted - version: "1.1.6" + version: "1.1.7" path: dependency: transitive description: name: path url: "https://pub.dartlang.org" source: hosted - version: "1.6.2" + version: "1.6.4" pedantic: dependency: transitive description: name: pedantic url: "https://pub.dartlang.org" source: hosted - version: "1.7.0" + version: "1.8.0+1" + petitparser: + dependency: transitive + description: + name: petitparser + url: "https://pub.dartlang.org" + source: hosted + version: "2.4.0" quiver: dependency: transitive description: name: quiver url: "https://pub.dartlang.org" source: hosted - version: "2.0.3" + version: "2.0.5" shared_preferences: dependency: "direct main" description: @@ -148,7 +190,7 @@ packages: name: string_scanner url: "https://pub.dartlang.org" source: hosted - version: "1.0.4" + version: "1.0.5" term_glyph: dependency: transitive description: @@ -177,6 +219,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.0.8" + xml: + dependency: transitive + description: + name: xml + url: "https://pub.dartlang.org" + source: hosted + version: "3.5.0" sdks: - dart: ">=2.2.2 <3.0.0" + dart: ">=2.4.0 <3.0.0" flutter: ">=1.5.0 <2.0.0" diff --git a/pubspec.yaml b/pubspec.yaml index 8e48d54..ed91b95 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -11,7 +11,7 @@ description: Uses text file to shuffe flashcards. # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. # Read more about iOS versioning at # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html -version: 6.2.0+21 +version: 6.2.1+22 environment: sdk: ">=2.1.0 <3.0.0" diff --git a/web/index.html b/web/index.html new file mode 100644 index 0000000..258535f --- /dev/null +++ b/web/index.html @@ -0,0 +1,10 @@ + + + + + Flashcards + + + + + From 5e775ababe3354bebbdb8290a8dca7ad393dbd2e Mon Sep 17 00:00:00 2001 From: robert3141 Date: Sun, 22 Sep 2019 10:59:21 +0100 Subject: [PATCH 2/5] Solve issue #35 --- lib/main.dart | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/main.dart b/lib/main.dart index 79847e6..6994c74 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -78,6 +78,7 @@ class Strings{ static String editCardsFront = "Front of Card"; static String editCardsRear = "Back of Card"; static String editDelete = "Deleting Card"; + static String editDeleting = "Are you sure you want to delete this?"; //Error Messages static String errorImport = "Error Importing Flashcards:\n"; @@ -87,7 +88,6 @@ class Strings{ static String errorEdit = "Error Editing Flashcards:\n"; static String errorLoad = "Error Loading Flashcards:\n"; static String errorDelete = "Error Deleting Flashcards:\n"; - static String errorDeleting = "Are you sure you want to delete this?"; static String errorNewCard = "Error Getting Next Flashcard:\n"; static String errorLoadPrefs = "Error Loading Settings:\n"; static String errorSettingsOrdered = "Error Changing Ordered Cards:\n"; @@ -390,8 +390,8 @@ class _MyHomePageState extends State { showDialog( context: context, builder: (BuildContext context) => AlertDialog( - title: Text(Strings.errorDelete), - content: Text(Strings.errorDeleting), + title: Text(Strings.editDelete), + content: Text(Strings.editDeleting), actions: [ FlatButton( child: Text(Strings.errorCancel), @@ -1197,8 +1197,8 @@ class _EditCardsState extends State { showDialog( context: context, builder: (BuildContext context) => AlertDialog( - title: Text(Strings.errorEditDelete), - content: Text(Strings.errorDeleting), + title: Text(Strings.editDelete), + content: Text(Strings.editDeleting), actions: [ FlatButton( child: Text(Strings.errorCancel), From 92445608d0614ddcf3af146438058da4b13a1599 Mon Sep 17 00:00:00 2001 From: robert3141 Date: Sun, 22 Sep 2019 11:27:55 +0100 Subject: [PATCH 3/5] fix issue #32 --- android/gradle.properties | 1 + lib/main.dart | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/android/gradle.properties b/android/gradle.properties index 8bd86f6..7be3d8b 100644 --- a/android/gradle.properties +++ b/android/gradle.properties @@ -1 +1,2 @@ org.gradle.jvmargs=-Xmx1536M +android.enableR8=true diff --git a/lib/main.dart b/lib/main.dart index 6994c74..d075873 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -925,7 +925,7 @@ class _FlashcardsPage extends MaterialPageRoute { //generate random Random _rng = new Random(); int _randomNumber = 0; - int _amountOfFlashcards = _currentFileData.length ~/ 2 - 1; + int _amountOfFlashcards = _currentFileData.length ~/ 2; // make random flashcard as next in list _randomNumber = _rng.nextInt(_amountOfFlashcards) * 2; From 8b71b8763dcf74a7116e290dc24bdf3acf56435b Mon Sep 17 00:00:00 2001 From: robert3141 Date: Sun, 22 Sep 2019 11:49:01 +0100 Subject: [PATCH 4/5] issue #33 fixed --- lib/main.dart | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/lib/main.dart b/lib/main.dart index d075873..c87c28b 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -585,7 +585,7 @@ class _MyHomePageState extends State { final _tabPages = [ //Main Tab Container( - child: Column( + child: Column( mainAxisAlignment: MainAxisAlignment.start, children: [ Card( @@ -713,8 +713,7 @@ class _MyHomePageState extends State { //Settings Tab Container( - child: Column( - mainAxisAlignment: MainAxisAlignment.start, + child: ListView( children: [ // Cards Ordered InkWell( @@ -824,7 +823,7 @@ class _MyHomePageState extends State { ), ), ], - ) + ), ), ]; @@ -968,7 +967,7 @@ class _FlashcardsPage extends MaterialPageRoute { controller: _scrollControl, itemBuilder: (BuildContext context, int index) { return FlipCard( - key: UniqueKey(), + //key: UniqueKey(), direction: FlipDirection.HORIZONTAL, speed: 1500, front: InkWell( From dec64ae3fbcb27dce4394a52d33980e645a3b72a Mon Sep 17 00:00:00 2001 From: robert3141 Date: Sun, 22 Sep 2019 13:35:05 +0100 Subject: [PATCH 5/5] Added webmain.dart to work on #36. However compiling seems to be infinite --- lib/webmain.dart | 1353 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1353 insertions(+) create mode 100644 lib/webmain.dart diff --git a/lib/webmain.dart b/lib/webmain.dart new file mode 100644 index 0000000..5b8ab19 --- /dev/null +++ b/lib/webmain.dart @@ -0,0 +1,1353 @@ +import 'dart:io'; +import 'dart:math'; +import 'dart:async'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:shared_preferences/shared_preferences.dart'; +import 'package:flip_card/flip_card.dart'; +import 'package:dynamic_theme/dynamic_theme.dart'; +import 'package:flutter_material_color_picker/flutter_material_color_picker.dart'; + +Future main() async { + runApp(new MyApp()); +} + +// +// CONSTANTS +// + +// Default settings +final cardHeight = 100.0; +final cardWidth = 0.9; +final defaultPadding = 12.0; +final defaultCardAmount = 50; +final defaultCardsOrdered = false; +final defaultThemeColor = Colors.blue; +final defaultBrightness = Brightness.light; + +//prefs for flashcards page +int amountOfCards; +bool cardsOrdered; + +class Strings{ + //British strings: + + //App Interface Main + static String appName = "Flashcards"; + static String tabTitleMain = "Main"; + static String tabTitleSettings = "Settings"; + static String tabTitleFlashcards = "Flashcards"; + static String tabTitleEditCards = "Edit Cards"; + static String paddingAsText = " "; + + //Default cards + static String addNewCards = "Add New Flashcards"; + static String newFileName = "New File"; + static String exampleFileName = "Example File"; + static String exampleFileLength = "3"; + static String exampleFileData = "card1a&card1b&card2a&card2b&card3a&card3b&"; + + //Dialog Options + static String importFlashcards = "Import File"; + static String openFlashcardsFile = "Open File"; + static String createFlashcards = "Create New"; + static String editFlashcards = "Edit"; + static String loadFlashcards = "Load"; + static String deleteFlashcards = "Delete"; + static String errorOk = "OK"; + static String errorCancel = "CANCEL"; + + //Shared prefs storage names + static String prefsFlashcardTitles = "Titles"; //Strings List + static String prefsFlashcardLength = "Amount"; //Strings List + static String prefsFlashcardData = "Data"; //Strings List + static String prefsAmountOfCards = "Number"; //Integer + static String prefsCardsOrdered = "Ordered"; //Boolean + + //Settings Options + static String settingsCardsOrdered = "Order Cards"; + static String settingsAmountOfCards = "Amount Of Cards (In shuffle)"; + static String settingsDarkTheme = "Dark Theme"; + static String settingsThemeColour = "Theme Colour (In Light Theme)"; + + //Edit Cards Options + static String editCardsFileName = "File name: "; + static String editCardsAddCard = "Add New Flashcard"; + static String editCardsCardNo = "Card Number: "; + static String editCardsFront = "Front of Card"; + static String editCardsRear = "Back of Card"; + static String editDelete = "Deleting Card"; + static String editDeleting = "Are you sure you want to delete this?"; + + //Error Messages + static String errorImport = "Error Importing Flashcards:\n"; + static String errorNoFile = "The app did not receive the file.\n Are you sure you selected a file?"; + static String errorNotSupported = "The file is not supported.\n Are you sure the .txt file is UTF-8?"; + static String errorCreate = "Error Creating Flashcards:\n"; + static String errorEdit = "Error Editing Flashcards:\n"; + static String errorLoad = "Error Loading Flashcards:\n"; + static String errorDelete = "Error Deleting Flashcards:\n"; + static String errorNewCard = "Error Getting Next Flashcard:\n"; + static String errorLoadPrefs = "Error Loading Settings:\n"; + static String errorSettingsOrdered = "Error Changing Ordered Cards:\n"; + static String errorSettingsAmount = "Error Changing Amount of Cards:\n"; + static String errorSettingsDark = "Error Changing Dark Theme:\n"; + static String errorSettingsTheme = "Error Changing Theme Colour:\n"; + static String errorSplitString = "Internal Error:\n"; + static String errorEditTitle = "Error Editing Title:\n"; + static String errorEditNewCard = "Error Adding New Flashcard:\n"; + static String errorEditFlashcard = "Error Editing Flashcard:\n"; + static String errorEditNoAnd = "You used the '&' character. \n This cannot be used in this app unfortunately"; + static String errorEditClicked = "Error displaying Flashcard Editor:\n"; + static String errorEditPrefs = "Error Saving Changes:\n"; + static String errorEditDelete = "Error Deleting Card:\n"; + static String errorWeb = "Web Version"; + static String errorWebVersion = "Web Version does not currently support this feature"; + +} + +//GLOBAL VARS +List _flashcardFiles = ['${Strings.exampleFileName}']; +List _flashcardLengths = ['${Strings.exampleFileLength}']; + + + +class MyApp extends StatefulWidget { + + // This widget is the root of your application. + @override + _MyAppState createState() => _MyAppState(); +} + + +class _MyAppState extends State { + @override + Widget build(BuildContext context) { + var routes = { + EditCards.routeName: (BuildContext context) => new EditCards(['1','2'],0), + }; + + return new DynamicTheme( + defaultBrightness: defaultBrightness, + data: (brightness) => new ThemeData( + primarySwatch: defaultThemeColor, + brightness: brightness, + ), + themedWidgetBuilder: (context, theme) { + return new MaterialApp( + title: Strings.appName, + theme: theme, + darkTheme: new ThemeData( + primarySwatch: defaultThemeColor, + brightness: Brightness.dark, + ), + home: new MyHomePage(title: Strings.appName,), + routes: routes, + ); + }, + ); + } +} + + +class MyHomePage extends StatefulWidget { + MyHomePage({Key key, this.title}) : super(key: key); + + // This widget is the home page of your application. It is stateful, meaning + // that it has a State object (defined below) that contains fields that affect + // how it looks. + + // This class is the configuration for the state. It holds the values (in this + // case the title) provided by the parent (in this case the App widget) and + // used by the build method of the State. Fields in a Widget subclass are + // always marked "final". + + final String title; + + @override + _MyHomePageState createState() => _MyHomePageState(); +} + +class _MyHomePageState extends State { + //set variables for class + int _currentTabIndex = 0; + var _tabTitle = Strings.tabTitleMain; + bool _cardsAmountEnabled = defaultCardsOrdered; + final _controllerAmountOfCards = TextEditingController(); + + // + // FUNCTIONS: + // + + void outputErrors(String _error,_e){ + setState(() { + showDialog( + context: context, + builder: (BuildContext context) => AlertDialog( + title: Text(_error), + content: Text(_e.toString()), + actions: [ + FlatButton( + child: Text(Strings.errorOk), + onPressed: () => Navigator.pop(context), + ) + ], + ), + ); + }); + } + + void clickImportFlashcards() async { + try { + //not supported + outputErrors(Strings.errorWeb, Strings.errorWebVersion); + + } catch(e) { + //in case of error output error + if (e == FileSystemException) { + outputErrors(Strings.errorImport, Strings.errorNotSupported); + } else { + outputErrors(Strings.errorImport, e); + } + } + } + + void clickOpenFlashcards() async { + try { + //not supported + outputErrors(Strings.errorWeb, Strings.errorWebVersion); + + } catch(e) { + outputErrors(Strings.errorLoad, e); + } + } + + void clickCreateFlashcards() async { + try{ + // Get file from shared prefs + int _newFileNumber = 0; + SharedPreferences _prefs = await SharedPreferences.getInstance(); + List _flashcardsData = _prefs.getStringList(Strings.prefsFlashcardData); + List _flashcardLengths = _prefs.getStringList(Strings.prefsFlashcardLength); + List _flashcardTitle = _prefs.getStringList(Strings.prefsFlashcardTitles); + + //add file to sharedPrefs + // flashcardData + if (_flashcardsData != null) { + _flashcardsData.add(Strings.exampleFileData); + _newFileNumber = _flashcardsData.length - 1; + } else { + _flashcardsData = [Strings.exampleFileData]; + } + await _prefs.setStringList(Strings.prefsFlashcardData, _flashcardsData); + // flashcardLengths + if (_flashcardLengths != null) { + _flashcardLengths.add(Strings.exampleFileLength); + } else { + _flashcardLengths = [Strings.exampleFileLength]; + } + await _prefs.setStringList(Strings.prefsFlashcardLength, _flashcardLengths); + //flashcardTitle + if (_flashcardTitle != null) { + _flashcardTitle.add(Strings.newFileName); + } else { + _flashcardTitle = [Strings.newFileName]; + } + await _prefs.setStringList(Strings.prefsFlashcardTitles, _flashcardTitle); + + //split from file + List _currentFlashcards = splitter(Strings.exampleFileData, "&"); + + //load edit page + Navigator.push(context, _EditCardsPage(_currentFlashcards, _newFileNumber)); + + } catch(e){ + //in case of error output error + outputErrors(Strings.errorCreate, e); + } + } + + void clickEditFlashcards(int _fileNumber) async { + try{ + //Get file from shared prefs + SharedPreferences _prefs = await SharedPreferences.getInstance(); + List _flashcardData = _prefs.getStringList(Strings.prefsFlashcardData); + + //add example file to shared prefs + if (_flashcardData == null) { + _flashcardData = [Strings.exampleFileData]; + _prefs.setStringList(Strings.prefsFlashcardData, [Strings.exampleFileData]); + + //add title and amount of cards + _prefs.setStringList(Strings.prefsFlashcardTitles, [Strings.exampleFileName]); + _prefs.setStringList(Strings.prefsFlashcardLength, [Strings.exampleFileLength]); + } + + //split from file + List _currentFlashcards = splitter(_flashcardData[_fileNumber], "&"); + + //load edit page + Navigator.push(context, _EditCardsPage(_currentFlashcards, _fileNumber)); + + //update UI + setState(() { + + }); + } catch(e){ + //in case of error output error + outputErrors(Strings.errorEdit, e); + } + } + + void clickLoadFlashcards(int _fileNumber) async { + try{ + //Get file from shared prefs + SharedPreferences _prefs = await SharedPreferences.getInstance(); + List _flashcardsData = _prefs.getStringList(Strings.prefsFlashcardData) ?? [Strings.exampleFileData]; + List _currentFlashcards = splitter(_flashcardsData[_fileNumber], "&"); + + //load flashcards page + Navigator.push(context, _FlashcardsPage(_currentFlashcards)); + + } catch(e){ + //in case of error output error + outputErrors(Strings.errorLoad, e); + } + } + + void clickDeleteFlashcards(int _fileNumber) { + try { + showDialog( + context: context, + builder: (BuildContext context) => AlertDialog( + title: Text(Strings.editDelete), + content: Text(Strings.editDeleting), + actions: [ + FlatButton( + child: Text(Strings.errorCancel), + onPressed: () { + Navigator.of(context).pop(); + }, + ), + FlatButton( + child: Text(Strings.errorOk), + onPressed: () async { + //load prefs + SharedPreferences _prefs = await SharedPreferences.getInstance(); + + //get from shared prefs + List _flashcardsData = _prefs.getStringList(Strings.prefsFlashcardData); + + //check not example file + if (_flashcardsData != null) { + //get from shared prefs + _flashcardFiles = _prefs.getStringList(Strings.prefsFlashcardTitles); + _flashcardLengths = _prefs.getStringList(Strings.prefsFlashcardLength); + + //remove file + _flashcardsData.removeAt(_fileNumber); + _prefs.setStringList(Strings.prefsFlashcardData, _flashcardsData); + + //remove title + _flashcardFiles.removeAt(_fileNumber); + _prefs.setStringList(Strings.prefsFlashcardTitles, _flashcardFiles); + + //remove number + _flashcardLengths.removeAt(_fileNumber); + _prefs.setStringList(Strings.prefsFlashcardLength, _flashcardLengths); + + //reload interface + Navigator.pop(context); + Navigator.pop(context); + setState(() { + + }); + } + }, + ) + ], + ), + ); + } catch(e) { + outputErrors(Strings.errorDelete, e); + } + } + + void loadFromPreferences() async { + try { + //variables + SharedPreferences _prefs = await SharedPreferences.getInstance(); + + //set variables + _flashcardFiles = _prefs.getStringList(Strings.prefsFlashcardTitles)?? [Strings.exampleFileName]; + _flashcardLengths = _prefs.getStringList(Strings.prefsFlashcardLength)?? [Strings.exampleFileLength]; + amountOfCards = _prefs.getInt(Strings.prefsAmountOfCards) ?? defaultCardAmount; + _controllerAmountOfCards.text = amountOfCards.toString(); + cardsOrdered = _prefs.getBool(Strings.prefsCardsOrdered) ?? defaultCardsOrdered; + _cardsAmountEnabled = !cardsOrdered; + } catch(e) { + outputErrors(Strings.errorLoadPrefs, e); + } + } + + // + // PREFERENCE UPDATES + // + + void settingsOrderedCards(_orderedCard) async { + try { + //set up prefs and save to prefs + SharedPreferences _prefs = await SharedPreferences.getInstance(); + _prefs.setBool(Strings.prefsCardsOrdered, _orderedCard); + cardsOrdered = _orderedCard; + setState(() { + cardsOrdered = _orderedCard; + _cardsAmountEnabled = !_orderedCard; + }); + } catch(e) { + outputErrors(Strings.errorSettingsOrdered, e); + } + } + + void settingsCardAmount(_cardAmountInput) async { + if (num.tryParse(_cardAmountInput.toString()) != null){ + //set up prefs and save to prefs + SharedPreferences _prefs = await SharedPreferences.getInstance(); + _prefs.setInt(Strings.prefsAmountOfCards, num.parse(_cardAmountInput.toString())); + } + } + + void settingsDarkTheme(_darkTheme) { + try { + //set up prefs and save to prefs + DynamicTheme.of(context).setBrightness(_darkTheme? Brightness.dark : Brightness.light); + } catch(e) { + outputErrors(Strings.errorSettingsDark, e); + } + } + + void settingsThemeColor() { + try { + //local var + Color _tempColor = Theme.of(context).primaryColor; + showDialog( + context: context, + builder: (_) { + return AlertDialog( + title: Text(Strings.settingsThemeColour), + content: MaterialColorPicker( + selectedColor: Theme.of(context).primaryColor, + allowShades: true, + onColorChange: (newColor) { + _tempColor = Color(newColor.value); + }, + + onMainColorChange: (newColor) { + _tempColor = Color(newColor.value); + }, + ), + actions: [ + FlatButton( + child: Text(Strings.errorCancel), + onPressed: (){ + Navigator.of(context).pop(); + }, + ), + FlatButton( + child: Text(Strings.errorOk), + onPressed: (){ + DynamicTheme.of(context).setBrightness(Brightness.light); + DynamicTheme.of(context).setThemeData(new ThemeData(primaryColor: _tempColor, accentColor: _tempColor)); + Navigator.of(context).pop(); + }, + ), + ], + ); + } + ); + } catch(e) { + outputErrors(Strings.errorSettingsTheme, e); + } + } + + List splitter(String _splitText,String _splitChar) { + //local variables + List _fileList = [""]; + try { + var _tempString = ""; + bool _firstTime = true; + + for (var i = 0; i < _splitText.length; i++) { + if (_splitText[i] == _splitChar){ + if (_tempString != null){ + if(_firstTime){ + _fileList[0] = _tempString; + _firstTime = false; + } else { + _fileList.add(_tempString); + } + } + _tempString = null; + } else { + if(_tempString == null){ + _tempString = _splitText[i]; + } else { + _tempString += _splitText[i]; + } + } + } + + if (_tempString != null){ + _fileList.add(_tempString); + } + } catch(e) { + outputErrors(Strings.errorSplitString, e); + } + + return _fileList; + } + + + @override + Widget build(BuildContext context) { + //build the page with the flashcards + loadFromPreferences(); + final _tabPages = [ + //Main Tab + Container( + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Card( + child: Container( + height: cardHeight, + child: InkWell( + splashColor: Theme.of(context).primaryColor, + onTap: (){ + setState(() { + //Add Cards dialog + showDialog( + context: context, + builder: (BuildContext context) => SimpleDialog( + title: Text(Strings.addNewCards), + children: [ + ListTile( + leading: Icon(Icons.folder_open), + title: Text(Strings.importFlashcards), + onTap: (){ + clickImportFlashcards(); + }, + ), + ListTile( + leading: Icon(Icons.library_books), + title: Text(Strings.openFlashcardsFile), + onTap: (){ + clickOpenFlashcards(); + }, + ), + ListTile( + leading: Icon(Icons.control_point), + title: Text(Strings.createFlashcards), + onTap: (){ + clickCreateFlashcards(); + }, + ), + ], + ), + ); + }); + }, + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text(Strings.paddingAsText + Strings.addNewCards,overflow: TextOverflow.ellipsis,style: TextStyle(fontWeight: FontWeight.bold)), + Icon(Icons.add), + ], + ), + ), + ), + ), + + Expanded( + child: ListView.builder( + itemCount: _flashcardFiles.length, + itemBuilder: (BuildContext context, int index){ + return Card( + child: Container( + height: cardHeight, + child: InkWell( + splashColor: Theme.of(context).primaryColor, + onTap: (){ + //open cards dialog + setState(() { + //Add Cards dialog + showDialog( + context: context, + builder: (BuildContext context) => SimpleDialog( + title: Text(_flashcardFiles[index]), + children: [ + ListTile( + leading: Icon(Icons.edit), + title: Text(Strings.editFlashcards), + onTap: (){ + clickEditFlashcards(index); + }, + ), + ListTile( + leading: Icon(Icons.content_copy), + title: Text(Strings.loadFlashcards), + onTap: (){ + clickLoadFlashcards(index); + }, + ), + ListTile( + leading: Icon(Icons.delete_forever), + title: Text(Strings.deleteFlashcards), + onTap: (){ + clickDeleteFlashcards(index); + }, + ) + ], + ), + ); + }); + }, + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Flexible( + child: Container( + padding: EdgeInsets.only(right: 4.0), + child: Text(Strings.paddingAsText + _flashcardFiles[index],overflow: TextOverflow.ellipsis, style: TextStyle(fontWeight: FontWeight.bold)), + + ), + ), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text(_flashcardLengths[index],overflow: TextOverflow.ellipsis), + Icon(Icons.content_copy), + ], + ), + ], + ), + ), + ), + ); + }, + ), + ), + ], + ), + ), + + //Settings Tab + Container( + child: ListView( + children: [ + // Cards Ordered + InkWell( + splashColor: Theme.of(context).primaryColor, + onTap: (){ + settingsOrderedCards(!cardsOrdered); + }, + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Padding(padding: EdgeInsets.only(left: defaultPadding),), + Icon(Icons.reorder), + Text(Strings.paddingAsText + Strings.settingsCardsOrdered, style: TextStyle(fontWeight: FontWeight.bold),), + ], + ), + Switch(value: cardsOrdered, onChanged: settingsOrderedCards,), + ], + ), + ), + Divider(), + //Cards to show + InkWell( + splashColor: Theme.of(context).primaryColor, + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Padding(padding: EdgeInsets.only(left: defaultPadding),), + Icon(Icons.shuffle), + Text( + Strings.paddingAsText + Strings.settingsAmountOfCards, + style: TextStyle(fontWeight: FontWeight.bold), + ), + ], + ), + + Expanded( + child: Padding( + padding: EdgeInsets.all(defaultPadding), + child: TextField( + decoration: InputDecoration(contentPadding: EdgeInsets.all(defaultPadding)), + enabled: _cardsAmountEnabled, + keyboardType: TextInputType.number, + inputFormatters: [WhitelistingTextInputFormatter.digitsOnly], + onChanged: settingsCardAmount, + controller: _controllerAmountOfCards, + ), + ), + ), + ], + ), + ), + Divider(), + //set brightness + InkWell( + splashColor: Theme.of(context).primaryColor, + onTap: (){ + settingsDarkTheme(Theme.of(context).brightness == Brightness.light); + }, + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Padding(padding: EdgeInsets.only(left: defaultPadding),), + Icon(Icons.brightness_3), + Text( + Strings.paddingAsText + Strings.settingsDarkTheme, + style: TextStyle(fontWeight: FontWeight.bold), + ), + ], + ), + + Switch(value: Theme.of(context).brightness == Brightness.dark, onChanged: settingsDarkTheme,), + ], + ), + ), + Divider(), + //set theme + InkWell( + splashColor: Theme.of(context).primaryColor, + onTap: (){ + settingsThemeColor(); + }, + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Padding(padding: EdgeInsets.only(left: defaultPadding),), + Icon(Icons.color_lens), + Text( + Strings.paddingAsText + Strings.settingsThemeColour, + style: TextStyle(fontWeight: FontWeight.bold), + ), + ], + ), + CircleAvatar(backgroundColor: Theme.of(context).accentColor,), + ], + ), + ), + ], + ), + ), + ]; + + final _appBar = AppBar( + title: Text(_tabTitle), + centerTitle: true, + ); + + final bottomNavBar = BottomNavigationBar( + currentIndex: _currentTabIndex, + type: BottomNavigationBarType.fixed, + items: [ + BottomNavigationBarItem( + icon: Icon(Icons.content_copy), + title: Text(Strings.tabTitleFlashcards), + + ), + + BottomNavigationBarItem( + icon: Icon(Icons.settings), + title: Text(Strings.tabTitleSettings), + ), + ], + onTap: (int index){ + setState(() { + _currentTabIndex = index; + switch (index) { + case 0: + _tabTitle = Strings.tabTitleMain; + break; + case 1: + _tabTitle = Strings.tabTitleSettings; + break; + + } + }); + }, + ); + + return Scaffold( + body: _tabPages[_currentTabIndex], + bottomNavigationBar: bottomNavBar, + appBar: _appBar, + ); + } +} + +class _FlashcardsPage extends MaterialPageRoute { + + _FlashcardsPage(List _currentFileData) : super(builder: (BuildContext context){ + + //set variables for class + List _cardFront = [""]; + List _cardRear = [""]; + double _screenWidth = MediaQuery.of(context).size.width; + ScrollController _scrollControl = new ScrollController(); + + // + // FUNCTIONS + // + + void outputErrors(String _error,_e){ + showDialog( + context: context, + builder: (BuildContext context) => AlertDialog( + title: Text(_error), + content: Text(_e.toString()), + actions: [ + FlatButton( + child: Text(Strings.errorOk), + onPressed: () => Navigator.pop(context), + ) + ], + ), + ); + } + + void newCard() { + try { + //cards ordered? + if (cardsOrdered){ + //Cards need to be displayed in an ordered fashion + + //loop through array and add the flashcards + _cardFront[0] = _currentFileData[0]; + _cardRear[0] = _currentFileData[1]; + for (var i = 2; i < _currentFileData.length; i++) { + //add to front if even and rear if odd + if (i % 2 == 0) { + _cardFront.add(_currentFileData[i]); + } else { + _cardRear.add(_currentFileData[i]); + } + } + } else { + //Cards can be outputted randomly with a limit + + //generate random + Random _rng = new Random(); + int _randomNumber = 0; + int _amountOfFlashcards = _currentFileData.length ~/ 2; + + // make random flashcard as next in list + _randomNumber = _rng.nextInt(_amountOfFlashcards) * 2; + _cardFront[0] = _currentFileData[_randomNumber]; + _cardRear[0] = _currentFileData[_randomNumber + 1]; + for (var i = 1; i < amountOfCards; i++) { + _randomNumber = _rng.nextInt(_amountOfFlashcards) * 2; + _cardFront.add(_currentFileData[_randomNumber]); + _cardRear.add(_currentFileData[_randomNumber + 1]); + } + + } + + + } catch(e) { + outputErrors(Strings.errorNewCard, e); + } + } + + // + // LOAD INTERFACE + // + newCard(); + return Scaffold( + appBar: AppBar( + title: Text(Strings.tabTitleFlashcards), + elevation: 1.0, + ), + body: Builder( + builder: (BuildContext context) => Container( + color: Theme.of(context).primaryColor, + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Expanded( + flex: 4, + child: ListView.builder( + itemCount: _cardFront.length,//currentFileData.length ~/2 -1, + scrollDirection: Axis.horizontal, + controller: _scrollControl, + itemBuilder: (BuildContext context, int index) { + return FlipCard( + //key: UniqueKey(), + direction: FlipDirection.HORIZONTAL, + speed: 1500, + front: InkWell( + child: Card( + child: Container( + width: _screenWidth * cardWidth, + decoration: BoxDecoration( + borderRadius: BorderRadius.all(Radius.circular(8.0)) + ), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Padding( + padding: EdgeInsets.all(defaultPadding), + child: Text(_cardFront[index]), + ), + ], + ), + ), + ), + ), + back: InkWell( + child: Card( + child: Container( + width: _screenWidth * cardWidth, + decoration: BoxDecoration( + borderRadius: BorderRadius.all(Radius.circular(8.0)) + ), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Padding( + padding: EdgeInsets.all(defaultPadding), + child: Text(_cardRear[index]), + ), + ], + ), + ), + ), + ), + ); + }, + ), + ), + /*Expanded( + flex: 1, + child: Container( + child: Row( + crossAxisAlignment: CrossAxisAlignment.stretch, + //mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + Expanded( + child: InkWell( + child: Card( + child: Icon(Icons.arrow_back_ios), + ), + ), + ), + Expanded( + child: InkWell( + child: Card( + child: Icon(Icons.arrow_forward_ios), + ), + ), + ), + ], + ), + ), + )*/ //Adding buttons later + ], + ), + ), + + ), + ); + }); +} + +class _EditCardsPage extends MaterialPageRoute { + + _EditCardsPage(List _currentFileData, int _currentFileNo) : super(builder: (BuildContext context){ + return Scaffold( + appBar: AppBar( + title:Text(Strings.tabTitleEditCards), + elevation: 1.0, + ), + body: Builder( + builder: (BuildContext context) => EditCards(_currentFileData,_currentFileNo), + ), + ); + }); + +} +class EditCards extends StatefulWidget { + /*EditCards({ + Key key, + int index, +}) : super (key: key);*/ + List _currentFileData; + int _currentFileNo; + + EditCards( + List currentFlashcardData, + int currentFileNo, + ){ + this._currentFileData = currentFlashcardData; + this._currentFileNo = currentFileNo; + } + + static const String routeName = "/EditCards"; + + @override + _EditCardsState createState() => new _EditCardsState(); +} + +class _EditCardsState extends State { + + @override + void initState() { + super.initState(); + } + + + @override + Widget build(BuildContext context) { + + + // LOCAL VARS + final _controllerFront = TextEditingController(); + final _controllerRear = TextEditingController(); + final _controllerTitle = TextEditingController(); + List _currentFileData = widget._currentFileData; + int _currentFileNo = widget._currentFileNo; + + // + // FUNCTIONS + // + + void outputErrors(String _error,_e){ + showDialog( + context: context, + builder: (BuildContext context) => AlertDialog( + title: Text(_error), + content: Text(_e.toString()), + actions: [ + FlatButton( + child: Text(Strings.errorOk), + onPressed: () => Navigator.pop(context), + ) + ], + ), + ); + } + + void _onLoad() async { + try{ + //get shared prefs + SharedPreferences _prefs = await SharedPreferences.getInstance(); + + //get title + _controllerTitle.text = _prefs.getStringList(Strings.prefsFlashcardTitles)[_currentFileNo]; + } catch(e) { + outputErrors(Strings.errorLoadPrefs, e); + } + } + + void _updatePrefs() async { + try { + //local vars + String _currentFileDataString = "" ; + + //compress string to list + for (var i = 0; i < _currentFileData.length; i++) { + _currentFileDataString += _currentFileData[i] + "&"; + } + + //load prefs + SharedPreferences _prefs = await SharedPreferences.getInstance(); + + //get string list + List _currentFlashcardData = _prefs.getStringList(Strings.prefsFlashcardData); + + //update string list + _currentFlashcardData[_currentFileNo] = _currentFileDataString; + + //save to prefs + _prefs.setStringList(Strings.prefsFlashcardData, _currentFlashcardData); + } catch(e) { + outputErrors(Strings.errorEditPrefs, e); + } + } + + void _cardChanged(String _newCard, int _index, bool _frontOfCard) async { + try { + //check first that & not used + bool andUsed = false; + for (var i = 0; i < _newCard.length; i++) { + if (_newCard[i] == "&") { + andUsed = true; + } + } + if (andUsed) { + //output error + outputErrors(Strings.errorEditFlashcard, Strings.errorEditNoAnd); + return; + } + + //update current card + if(_frontOfCard){ + _currentFileData[_index * 2] = _newCard; + } else { + _currentFileData[_index * 2 + 1] = _newCard; + } + + //update prefs + _updatePrefs(); + + } catch(e) { + outputErrors(Strings.errorEditFlashcard, e); + } + } + + void _clickDeleteFlashcard(int _index) { + try { + //show warning + showDialog( + context: context, + builder: (BuildContext context) => AlertDialog( + title: Text(Strings.editDelete), + content: Text(Strings.editDeleting), + actions: [ + FlatButton( + child: Text(Strings.errorCancel), + onPressed: (){ + Navigator.of(context).pop(); + }, + ), + FlatButton( + child: Text(Strings.errorOk), + onPressed: () async { + //delete card + debugPrint('_index=$_index'); + for (var i =0; i < _currentFileData.length; i++) { + debugPrint("_currentFileData[$i]=" + _currentFileData[i]); + } + setState(() { + _currentFileData.removeAt(_index * 2); + _currentFileData.removeAt(_index * 2); + }); + + //close dialogs + Navigator.of(context).pop(); + Navigator.of(context).pop(); + + //update prefs + _updatePrefs(); + + //update card amount + SharedPreferences _prefs = await SharedPreferences.getInstance(); + List _amountOfCards =_prefs.getStringList(Strings.prefsFlashcardLength); + _amountOfCards[_currentFileNo] = (int.parse(_amountOfCards[_currentFileNo]) - 1).toString(); + _prefs.setStringList(Strings.prefsFlashcardLength, _amountOfCards); + }, + ) + ], + ), + ); + } catch(e) { + outputErrors(Strings.errorEditDelete, e); + } + } + + void _cardClicked(int index) { + try { + //set text of dialog + _controllerFront.text = _currentFileData[index * 2]; + _controllerRear.text = _currentFileData[index * 2 + 1]; + + //open cards dialog + showDialog( + context: context, + builder: (BuildContext context) => SimpleDialog( + title: Text(Strings.editCardsCardNo + (index + 1).toString()), + children: [ + Padding( + padding: EdgeInsets.all(defaultPadding), + child: TextField( + decoration: InputDecoration(hintText: Strings.editCardsFront), + onChanged: (_newCard){ + _cardChanged(_newCard, index, true); + }, + controller: _controllerFront, + ), + ), + Padding( + padding: EdgeInsets.all(defaultPadding), + child: TextField( + decoration: InputDecoration(hintText: Strings.editCardsRear), + onChanged: (_newCard){ + _cardChanged(_newCard, index, false); + }, + controller: _controllerRear, + ), + ), + ListTile( + leading: Icon(Icons.delete_forever), + title: Text(Strings.deleteFlashcards), + onTap: (){ + _clickDeleteFlashcard(index); + }, + ), + Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + FlatButton( + child: Text(Strings.errorOk), + onPressed: () => Navigator.pop(context), + ), + ], + ), + ], + ), + ); + } catch(e) { + outputErrors(Strings.errorEditClicked, e); + } + } + + void _titleChanged(String _newTitle) async { + try { + //get shared prefs + SharedPreferences _prefs = await SharedPreferences.getInstance(); + + //get titles list + List _titlesList = _prefs.getStringList(Strings.prefsFlashcardTitles); + + //set titles list + _titlesList[_currentFileNo] = _newTitle; + + //save to prefs + _prefs.setStringList(Strings.prefsFlashcardTitles, _titlesList); + _flashcardFiles = _titlesList; + } catch(e) { + outputErrors(Strings.errorEditTitle, e); + } + } + + void _newCardAdded() async { + try{ + //add new card + setState(() { + _currentFileData.add(' '); + _currentFileData.add(' '); + }); + + //update prefs + _updatePrefs(); + + //update card amount + SharedPreferences _prefs = await SharedPreferences.getInstance(); + List _amountOfCards =_prefs.getStringList(Strings.prefsFlashcardLength); + _amountOfCards[_currentFileNo] = (int.parse(_amountOfCards[_currentFileNo]) + 1).toString(); + _prefs.setStringList(Strings.prefsFlashcardLength, _amountOfCards); + + //popup edit new card interface + _cardClicked(_currentFileData.length ~/ 2 - 1); + + } catch(e) { + outputErrors(Strings.errorEditNewCard, e); + } + } + + // + // LOAD INTERFACE + // + _onLoad(); + return new Builder(builder: (BuildContext context) => Container( + color: Theme.of(context).primaryColor, + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Container( + height: cardHeight, + child: InkWell( + splashColor: Theme.of(context).primaryColor, + onTap: () {}, + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + Text(Strings.paddingAsText + Strings.editCardsFileName, style: TextStyle(color: Color(0xFFFFFFFF)),), + Expanded( + child: Padding( + padding: EdgeInsets.all(defaultPadding), + child: TextField( + onChanged: _titleChanged, + controller: _controllerTitle, + style: TextStyle(color: Color(0xFFFFFFFF)), + ), + ), + ), + ], + ), + ), + ), + Card( + child: Container( + height: cardHeight, + child: InkWell( + splashColor: Theme.of(context).primaryColor, + onTap: () { + _newCardAdded(); + }, + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + Text(Strings.paddingAsText + Strings.editCardsAddCard), + Icon(Icons.add), + ], + ), + ), + ), + ), + Expanded( + child: ListView.builder( + itemCount: _currentFileData.length ~/ 2, + itemBuilder: (BuildContext context, int index){ + return Card( + child: Container( + height: cardHeight, + child: InkWell( + splashColor: Theme.of(context).primaryColor, + onTap: (){ + _cardClicked(index); + }, + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text(Strings.paddingAsText + _currentFileData[index * 2], overflow: TextOverflow.ellipsis,), + Divider(), + Text(_currentFileData[index * 2 + 1] + Strings.paddingAsText, overflow: TextOverflow.ellipsis,), + ], + ), + ), + ), + ); + }, + ), + ), + ], + ), + ),); + } +}