2023-06-29 22:41:11 +00:00
import ' dart:io ' ;
2024-03-20 22:56:13 +00:00
import ' package:go_router/go_router.dart ' ;
2024-02-06 20:38:52 +00:00
import ' package:tetra_stats/data_objects/tetrio.dart ' ;
2024-06-11 20:51:57 +00:00
import ' package:tetra_stats/main.dart ' show packageInfo , teto , prefs ;
2023-06-29 22:41:11 +00:00
import ' package:file_selector/file_selector.dart ' ;
import ' package:file_picker/file_picker.dart ' ;
2023-07-20 20:56:00 +00:00
import ' package:flutter/foundation.dart ' ;
2023-06-17 21:50:52 +00:00
import ' package:flutter/material.dart ' ;
2023-06-29 22:41:11 +00:00
import ' package:path_provider/path_provider.dart ' ;
2023-07-10 17:42:20 +00:00
import ' package:tetra_stats/gen/strings.g.dart ' ;
2023-06-17 21:50:52 +00:00
import ' package:tetra_stats/services/crud_exceptions.dart ' ;
2023-10-18 21:50:41 +00:00
import ' package:tetra_stats/utils/open_in_browser.dart ' ;
2023-10-09 18:48:50 +00:00
import ' package:window_manager/window_manager.dart ' ;
late String oldWindowTitle ;
2024-06-04 22:14:34 +00:00
TextStyle subtitleStyle = const TextStyle ( fontFamily: " Eurostile Round Condensed " , color: Colors . grey ) ;
2023-06-17 21:50:52 +00:00
class SettingsView extends StatefulWidget {
2024-01-13 18:49:36 +00:00
const SettingsView ( { super . key } ) ;
2023-06-17 21:50:52 +00:00
@ override
State < StatefulWidget > createState ( ) = > SettingsState ( ) ;
}
class SettingsState extends State < SettingsView > {
String defaultNickname = " Checking... " ;
2024-03-06 22:34:15 +00:00
late bool showPositions ;
2024-06-04 22:14:34 +00:00
late bool updateInBG ;
2023-06-17 21:50:52 +00:00
final TextEditingController _playertext = TextEditingController ( ) ;
@ override
void initState ( ) {
2023-10-10 20:20:27 +00:00
if ( ! kIsWeb & & ! Platform . isAndroid & & ! Platform . isIOS ) {
2023-10-09 18:48:50 +00:00
windowManager . getTitle ( ) . then ( ( value ) = > oldWindowTitle = value ) ;
windowManager . setTitle ( " Tetra Stats: ${ t . settings } " ) ;
}
2023-06-17 21:50:52 +00:00
_getPreferences ( ) ;
super . initState ( ) ;
}
2023-10-09 18:48:50 +00:00
@ override
void dispose ( ) {
2023-10-10 20:20:27 +00:00
if ( ! kIsWeb & & ! Platform . isAndroid & & ! Platform . isIOS ) windowManager . setTitle ( oldWindowTitle ) ;
2023-10-09 18:48:50 +00:00
super . dispose ( ) ;
2023-06-17 21:50:52 +00:00
}
2024-06-11 20:51:57 +00:00
void _getPreferences ( ) {
2024-05-04 21:17:26 +00:00
showPositions = prefs . getBool ( " showPositions " ) ? ? false ;
2024-06-04 22:14:34 +00:00
updateInBG = prefs . getBool ( " updateInBG " ) ? ? false ;
2023-06-17 21:50:52 +00:00
_setDefaultNickname ( prefs . getString ( " player " ) ) ;
}
Future < void > _setDefaultNickname ( String ? n ) async {
if ( n ! = null ) {
try {
defaultNickname = await teto . getNicknameByID ( n ) ;
} on TetrioPlayerNotExist {
defaultNickname = n ;
}
} else {
2024-05-04 21:17:26 +00:00
defaultNickname = " dan63047 " ;
2023-06-17 21:50:52 +00:00
}
setState ( ( ) { } ) ;
}
Future < void > _setPlayer ( String player ) async {
await prefs . setString ( ' player ' , player ) ;
await _setDefaultNickname ( player ) ;
}
2024-02-06 20:38:52 +00:00
Future < void > _removePlayer ( ) async {
await prefs . remove ( ' player ' ) ;
2024-04-20 22:37:31 +00:00
await _setDefaultNickname ( " 6098518e3d5155e6ec429cdc " ) ;
2024-02-06 20:38:52 +00:00
}
2023-06-17 21:50:52 +00:00
@ override
Widget build ( BuildContext context ) {
2023-07-10 17:42:20 +00:00
final t = Translations . of ( context ) ;
List < DropdownMenuItem < AppLocale > > ? locales = < DropdownMenuItem < AppLocale > > [ ] ;
for ( var v in AppLocale . values ) {
locales . add ( DropdownMenuItem < AppLocale > (
value: v , child: Text ( t . locales [ v . languageTag ] ! ) ) ) ;
}
2023-06-17 21:50:52 +00:00
return Scaffold (
appBar: AppBar (
2023-07-12 15:14:25 +00:00
title: Text ( t . settings ) ,
2023-06-17 21:50:52 +00:00
) ,
backgroundColor: Colors . black ,
body: SafeArea (
child: ListView (
children: [
ListTile (
2023-07-12 15:14:25 +00:00
title: Text ( t . exportDB ) ,
2024-06-04 22:14:34 +00:00
subtitle: Text ( t . exportDBDescription , style: subtitleStyle ) ,
2023-06-29 22:41:11 +00:00
onTap: ( ) {
2023-07-20 20:56:00 +00:00
if ( kIsWeb ) {
ScaffoldMessenger . of ( context ) . showSnackBar ( SnackBar ( content: Text ( t . notForWeb ) ) ) ;
} else if ( Platform . isAndroid ) {
2023-06-29 22:41:11 +00:00
var downloadFolder = Directory ( " /storage/emulated/0/Download " ) ;
File exportedDB = File ( " ${ downloadFolder . path } /TetraStats.db " ) ;
getApplicationDocumentsDirectory ( ) . then ( ( value ) {
exportedDB . writeAsBytes ( File ( " ${ value . path } /TetraStats.db " ) . readAsBytesSync ( ) ) ;
showDialog (
context: context ,
builder: ( BuildContext context ) = > AlertDialog (
2023-07-12 15:14:25 +00:00
title: Text ( t . androidExportAlertTitle ,
style: const TextStyle (
2023-06-29 22:41:11 +00:00
fontFamily: " Eurostile Round Extended " ) ) ,
content: SingleChildScrollView (
2023-07-12 15:14:25 +00:00
child: ListBody ( children: [ Text ( t . androidExportText ( exportedDB: exportedDB ) ) ] ) ,
2023-06-29 22:41:11 +00:00
) ,
actions: < Widget > [
TextButton (
2023-07-12 15:14:25 +00:00
child: Text ( t . popupActions . ok ) ,
2023-06-29 22:41:11 +00:00
onPressed: ( ) {
Navigator . of ( context ) . pop ( ) ;
} ,
) ,
] ,
) ) ;
} ) ;
2023-07-20 20:56:00 +00:00
} else if ( Platform . isLinux | | Platform . isWindows ) {
showDialog (
context: context ,
builder: ( BuildContext context ) = > AlertDialog (
title: Text ( t . desktopExportAlertTitle ,
style: const TextStyle (
fontFamily: " Eurostile Round Extended " ) ) ,
content: SingleChildScrollView (
child: ListBody ( children: [
Text ( t . desktopExportText )
] ) ,
) ,
actions: < Widget > [
TextButton (
child: Text ( t . popupActions . ok ) ,
onPressed: ( ) {
Navigator . of ( context ) . pop ( ) ;
} ,
) ,
] ,
) ) ;
2023-06-29 22:41:11 +00:00
}
} ,
) ,
ListTile (
2023-07-12 15:14:25 +00:00
title: Text ( t . importDB ) ,
2024-06-04 22:14:34 +00:00
subtitle: Text ( t . importDBDescription , style: subtitleStyle ) ,
2023-06-29 22:41:11 +00:00
onTap: ( ) {
2023-07-20 20:56:00 +00:00
if ( kIsWeb ) {
ScaffoldMessenger . of ( context ) . showSnackBar ( SnackBar ( content: Text ( t . notForWeb ) ) ) ;
} else if ( Platform . isAndroid ) {
2023-06-29 22:41:11 +00:00
FilePicker . platform . pickFiles (
type: FileType . any ,
) . then ( ( value ) {
if ( value ! = null ) {
var newDB = value . paths [ 0 ] ! ;
teto . close ( ) . then ( ( value ) {
if ( ! newDB . endsWith ( " db " ) ) {
2023-07-12 15:14:25 +00:00
return ScaffoldMessenger . of ( context ) . showSnackBar ( SnackBar ( content: Text ( t . importWrongFileType ) ) ) ;
2023-06-29 22:41:11 +00:00
}
getApplicationDocumentsDirectory ( ) . then ( ( value ) {
var oldDB = File ( " ${ value . path } /TetraStats.db " ) ;
oldDB . writeAsBytes ( File ( newDB ) . readAsBytesSync ( ) , flush: true ) . then ( ( value ) {
teto . open ( ) ;
2023-07-12 15:14:25 +00:00
ScaffoldMessenger . of ( context ) . showSnackBar ( SnackBar ( content: Text ( t . importSuccess ) ) ) ;
2023-06-29 22:41:11 +00:00
} ) ;
} ) ;
} ) ;
} else {
2023-07-12 15:14:25 +00:00
ScaffoldMessenger . of ( context ) . showSnackBar ( SnackBar ( content: Text ( t . importCancelled ) ) ) ;
2023-06-29 22:41:11 +00:00
}
} ) ;
} else {
const XTypeGroup typeGroup = XTypeGroup (
label: ' Tetra Stats Database ' ,
extensions: < String > [ ' db ' ] ,
) ;
openFile ( acceptedTypeGroups: < XTypeGroup > [ typeGroup ] ) . then ( ( value ) {
if ( value ! = null ) {
var newDB = value . path ;
teto . close ( ) . then ( ( value ) {
getApplicationDocumentsDirectory ( ) . then ( ( value ) {
var oldDB = File ( " ${ value . path } /TetraStats.db " ) ;
oldDB . writeAsBytes ( File ( newDB ) . readAsBytesSync ( ) ) . then ( ( value ) {
teto . open ( ) ;
2023-07-12 15:14:25 +00:00
ScaffoldMessenger . of ( context ) . showSnackBar ( SnackBar ( content: Text ( t . importSuccess ) ) ) ;
2023-06-29 22:41:11 +00:00
} ) ;
} ) ;
} ) ;
} else {
2023-07-12 15:14:25 +00:00
ScaffoldMessenger . of ( context ) . showSnackBar ( SnackBar ( content: Text ( t . importCancelled ) ) ) ;
2023-06-29 22:41:11 +00:00
}
} ) ;
}
} ,
2023-06-17 21:50:52 +00:00
) ,
ListTile (
2023-07-12 15:14:25 +00:00
title: Text ( t . yourID ) ,
2024-06-04 22:14:34 +00:00
subtitle: Text ( t . yourIDText , style: subtitleStyle ) ,
2023-06-17 21:50:52 +00:00
trailing: Text ( defaultNickname ) ,
onTap: ( ) = > showDialog (
context: context ,
builder: ( BuildContext context ) = > AlertDialog (
2023-07-12 15:14:25 +00:00
title: Text ( t . yourIDAlertTitle ,
style: const TextStyle (
2023-06-29 22:41:11 +00:00
fontFamily: " Eurostile Round Extended " ) ) ,
2023-06-17 21:50:52 +00:00
content: SingleChildScrollView (
child: ListBody ( children: [
2023-07-12 15:14:25 +00:00
Text ( t . yourIDText ) ,
2023-06-17 21:50:52 +00:00
TextField ( controller: _playertext , maxLength: 25 )
] ) ,
) ,
actions: < Widget > [
TextButton (
2023-07-12 15:14:25 +00:00
child: Text ( t . popupActions . cancel ) ,
2023-06-17 21:50:52 +00:00
onPressed: ( ) {
Navigator . of ( context ) . pop ( ) ;
} ,
) ,
TextButton (
2023-07-12 15:14:25 +00:00
child: Text ( t . popupActions . submit ) ,
2024-02-06 20:38:52 +00:00
onPressed: ( ) async {
if ( _playertext . text . isEmpty ) {
_removePlayer ( ) ;
Navigator . of ( context ) . pop ( ) ;
return ;
}
late TetrioPlayer user ;
try {
user = await teto . fetchPlayer ( _playertext . text . toLowerCase ( ) . trim ( ) ) ;
} on Exception {
if ( context . mounted ) ScaffoldMessenger . of ( context ) . showSnackBar ( SnackBar ( content: Text ( t . errors . noSuchUser ) ) ) ;
return ;
}
_setPlayer ( user . userId ) ;
if ( context . mounted ) Navigator . of ( context ) . pop ( ) ;
2023-06-17 21:50:52 +00:00
setState ( ( ) { } ) ;
} ,
)
] ,
) ) ,
) ,
2023-07-10 17:42:20 +00:00
ListTile (
2023-07-12 15:14:25 +00:00
title: Text ( t . language ) ,
2024-06-04 22:14:34 +00:00
subtitle: Text ( " By default, the system language will be selected (if available among Tetra Stats locales, otherwise English) " , style: subtitleStyle ) ,
2023-07-10 17:42:20 +00:00
trailing: DropdownButton (
items: locales ,
value: LocaleSettings . currentLocale ,
2023-07-15 16:22:25 +00:00
onChanged: ( value ) {
LocaleSettings . setLocale ( value ! ) ;
if ( value . languageCode = = Platform . localeName . substring ( 0 , 2 ) ) {
prefs . remove ( ' locale ' ) ;
} else {
prefs . setString ( ' locale ' , value . languageCode ) ;
}
} ,
2023-07-10 17:42:20 +00:00
) ,
) ,
2024-03-20 22:56:13 +00:00
ListTile ( title: Text ( t . customization ) ,
2024-05-04 20:04:48 +00:00
subtitle: Text ( t . customizationDescription , style: const TextStyle ( fontFamily: " Eurostile Round Condensed " , color: Colors . grey ) ) ,
2024-01-13 18:49:36 +00:00
trailing: const Icon ( Icons . arrow_right ) ,
2023-10-19 21:45:07 +00:00
onTap: ( ) {
2024-06-11 16:30:13 +00:00
context . go ( " /settings/customization " ) ;
2023-10-19 21:45:07 +00:00
} , ) ,
2024-06-04 22:14:34 +00:00
ListTile ( title: Text ( " Update stats in the background " ) ,
2024-06-11 20:51:57 +00:00
subtitle: Text ( " While tetra stats is running, it can update stats of the current player when cache expires " , style: const TextStyle ( fontFamily: " Eurostile Round Condensed " , color: Colors . grey ) ) ,
2024-06-04 22:14:34 +00:00
trailing: Switch ( value: updateInBG , onChanged: ( bool value ) {
prefs . setBool ( " updateInBG " , value ) ;
setState ( ( ) {
updateInBG = value ;
} ) ;
} ) , ) ,
2024-03-20 22:56:13 +00:00
ListTile ( title: Text ( t . lbStats ) ,
2024-05-04 20:04:48 +00:00
subtitle: Text ( t . lbStatsDescription , style: const TextStyle ( fontFamily: " Eurostile Round Condensed " , color: Colors . grey ) ) ,
2024-03-06 22:34:15 +00:00
trailing: Switch ( value: showPositions , onChanged: ( bool value ) {
prefs . setBool ( " showPositions " , value ) ;
2024-03-04 22:05:59 +00:00
setState ( ( ) {
2024-03-06 22:34:15 +00:00
showPositions = value ;
2024-03-04 22:05:59 +00:00
} ) ;
} ) , ) ,
2023-06-17 21:50:52 +00:00
const Divider ( ) ,
ListTile (
2023-07-20 20:56:00 +00:00
onTap: ( ) {
2023-10-18 21:50:41 +00:00
launchInBrowser ( Uri . https ( " github.com " , " dan63047/TetraStats " ) ) ;
2023-07-20 20:56:00 +00:00
} ,
2024-05-28 21:05:01 +00:00
title: Text ( t . aboutApp , style: const TextStyle ( fontWeight: FontWeight . w500 ) , ) ,
2023-10-09 18:48:50 +00:00
subtitle: Text ( t . aboutAppText ( appName: packageInfo . appName , packageName: packageInfo . packageName , version: packageInfo . version , buildNumber: packageInfo . buildNumber ) ) ,
2024-03-20 22:56:13 +00:00
trailing: const Icon ( Icons . arrow_right )
2023-06-17 21:50:52 +00:00
) ,
] ,
) ) ,
) ;
}
}