mirrored_repositories/Flutter-Wordle
/*
 * @Author       : Linloir
 * @Date         : 2022-03-05 20:21:34
 * @LastEditTime : 2022-03-14 18:01:15
 * @Description  : 
 */
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:wordle/event_bus.dart';
import 'package:wordle/loading_page.dart';
import 'package:wordle/single_selection.dart';
import 'package:wordle/selection_group.dart';
import 'package:wordle/scroll_behav.dart';
import 'package:path_provider/path_provider.dart';
import 'package:wordle/instruction_pannel.dart';
import 'dart:io';
import 'dart:math';

Future<void> loadSettings() async {
  Directory documentsDirectory = await getApplicationDocumentsDirectory();
  String documentsPath = documentsDirectory.path + Platform.pathSeparator;
  File settings = File(documentsPath + "settings.txt");
  if(!(await settings.exists())) {
    var defaultSettings = "5\nCET4\nLight";
    settings.writeAsString(defaultSettings);
  }
  List<String> dicBooks = ["validation.txt", "CET4.txt"];
  for(String dicName in dicBooks) {
    if(!(await File(documentsPath + dicName).exists())) {
      //Copy file
      ByteData data = await rootBundle.load("assets/CET4.txt");
      List<int> bytes = data.buffer.asUint8List(data.offsetInBytes, data.lengthInBytes);
      await File(documentsPath + dicName).writeAsBytes(bytes, flush: true);
    }
  }
}

void main(){
  runApp(const MyApp());
}

class MyApp extends StatefulWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {

  var brightness = Brightness.light;

  void _onThemeChange(dynamic args) {
    setState(() {
      brightness = brightness == Brightness.light ? Brightness.dark : Brightness.light;
    });
  }

  @override
  void initState() {
    super.initState();
    //loadSettings();
    mainBus.onBus(event: "ToggleTheme", onEvent: _onThemeChange);
  }

  @override
  void dispose(){
    mainBus.offBus(event: "ToggleTheme", callBack: _onThemeChange);
    super.dispose();
  }
  
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      scrollBehavior: MyScrollBehavior(),
      title: 'Wordle',
      theme: ThemeData(
        primarySwatch: Colors.grey,
        brightness: brightness,
      ),
      routes: {
        "/": (context) => const HomePage(),
      },
      initialRoute: "/",
    );
  }
}

class HomePage extends StatefulWidget {
  const HomePage({Key? key}) : super(key: key);

  @override
  State<HomePage> createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  //bool _ignorance = false;

  Future<void> readSettings() async {
    return;
  }

  @override
  Widget build(BuildContext context) {
    return FutureBuilder(
      future: readSettings(),
      builder: (context, snapshot) {
        if(snapshot.connectionState == ConnectionState.done) {
          var mode = Theme.of(context).brightness;
          return Scaffold(
            body: Align(
              alignment: Alignment.center,
              child: Container(
                constraints: const BoxConstraints(maxWidth: 960.0),
                child: Column(
                  children: [
                    Container(
                      constraints: const BoxConstraints(minHeight: 100.0),
                      child: Row(
                        crossAxisAlignment: CrossAxisAlignment.end,
                        children: [
                          Align(
                            alignment: Alignment.bottomLeft,
                            child: Padding(
                              padding: const EdgeInsets.only(left: 30.0, bottom: 10.0),
                              child: Text('WORDLE', style: TextStyle(fontSize: 30.0, fontWeight: FontWeight.w300, color: mode == Brightness.light ? Colors.grey[850]! : Colors.white)),
                            ),
                          ),
                          const Spacer(),
                          Align(
                            alignment: Alignment.bottomRight,
                            child: Padding(
                              padding: const EdgeInsets.only(right: 30.0, bottom: 10.0),
                              child: Row(
                                children: [
                                  AnimatedSwitcher(
                                    duration: const Duration(milliseconds: 750),
                                    reverseDuration: const Duration(milliseconds: 750),
                                    switchInCurve: Curves.bounceOut,
                                    switchOutCurve: Curves.bounceIn,
                                    transitionBuilder: (child, animation) {
                                      var rotateAnimation = Tween<double>(begin: 0, end: 2 * pi).animate(animation);
                                      var opacAnimation = Tween<double>(begin: 0, end: 1).animate(animation);
                                      return AnimatedBuilder(
                                        animation: rotateAnimation,
                                        builder: (context, child) {
                                          return Transform(
                                            transform: Matrix4.rotationZ(rotateAnimation.status == AnimationStatus.reverse ? 2 * pi - rotateAnimation.value : rotateAnimation.value),
                                            alignment: Alignment.center,
                                            child: Opacity(
                                              opacity: opacAnimation.value,
                                              child: child,
                                            ),
                                          );
                                        },
                                        child: child,
                                      );
                                    },
                                    child: IconButton(
                                      key: ValueKey(mode),
                                      icon: mode == Brightness.light ? const Icon(Icons.dark_mode_outlined) : const Icon(Icons.dark_mode),
                                      onPressed: () => mainBus.emit(event: "ToggleTheme", args: []),
                                    ),
                                  ),
                                  IconButton(
                                    icon: const Icon(Icons.help_outline_outlined),
                                    //color: Colors.black,
                                    onPressed: (){
                                      showInstructionDialog(context: context);
                                    },
                                  ),
                                ]
                              )
                            ),
                          )
                        ],
                      ),
                    ),
                    const Expanded(
                      child: Padding(
                        padding: EdgeInsets.symmetric(horizontal: 20.0),
                        child: OfflinePage(),
                      ),
                    ),
                  ],
                ),
              ),
            ),
          );
        }
        else {
          return const Text('');
        }
      },
    );
  }
}

class OfflinePage extends StatefulWidget {
  const OfflinePage({Key? key}) : super(key: key);

  @override
  State<OfflinePage> createState() => _OfflinePageState();
}

class _OfflinePageState extends State<OfflinePage> {
  int wordLen = 5;
  int maxChances = 6;
  int dicBookIndex = 0;
  var dicBook = [["All", "Full wordlist", "A", Colors.indigo], ["HighSchool", "HighSchool wordlist", "H", Colors.amber],
                ["CET4", "CET4 wordlist", "4", Colors.green[400]], ["CET6", "CET6 wordlist", "6", Colors.teal[400]],
                ["CET4 + 6", "CET4&6 wordlist", "46", Colors.teal[600]], ["TOEFL Slim", "TOEFL without CET4&6", "T", Colors.blue[400]],
                ["TOEFL", "Full TOEFL wordlist", "T", Colors.cyan[400]], ["GRE Slim", "GRE without CET4&6", "G", Colors.pink[200]]];
  late final List<Widget> dicBookSelections;
  var wordLenSelectionColors = [Colors.green[300], Colors.green[500], Colors.teal[300], Colors.teal[500], Colors.pink[300]];
  var chancesSelectionColors = [Colors.deepOrange[600], Colors.orange[400], Colors.cyan, Colors.blue[400], Colors.blue[600], Colors.teal[400], Colors.teal[600], Colors.green[700]];

  @override
  void initState() {
    super.initState();
    dicBookSelections = [
      for(int i = 0; i < dicBook.length; i++)
        generateSelectionBox(
          id: i,
          width: 190,
          height: 240,
          padding: const EdgeInsets.fromLTRB(15.0, 25.0, 15.0, 0.0),
          color: dicBook[i][3]! as Color,
          primaryText: dicBook[i][0] as String,
          primaryTextSize: 20.0,
          secondaryText: dicBook[i][1] as String,
          secondaryTextSize: 14.0,
          decorationText: dicBook[i][2] as String,
          alignment: Alignment.topLeft,
        )
    ];
  }



  @override
  Widget build(BuildContext context) {
    return SizedBox(
      width: double.infinity,
      child: SingleChildScrollView(
        scrollDirection: Axis.vertical,
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Container(
              width: double.infinity,
              height: 150.0,
              decoration: BoxDecoration(
                color: wordLenSelectionColors[wordLen - 4]!.withOpacity(0.2),
                borderRadius: BorderRadius.circular(10.0),
              ),
              alignment: Alignment.centerLeft,
              padding: const EdgeInsets.all(10.0),
              margin: const EdgeInsets.symmetric(horizontal: 10.0, vertical: 10.0),
              child: Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: [
                  Padding(
                    padding: const EdgeInsets.fromLTRB(15.0, 10.0, 0.0, 10.0),
                    child: Text(
                      'Word Length',
                      style: TextStyle(
                        fontSize: 22.0,
                        fontWeight: FontWeight.bold,
                        color: wordLenSelectionColors[wordLen - 4]!,
                      ),
                    ),
                  ),
                  SelectionGroupProvider(
                    defaultSelection: 5,
                    onChanged: (sel) => setState(() => wordLen = sel),
                    selections: SingleChildScrollView(
                      scrollDirection: Axis.horizontal,
                      child: Row(
                        children: [
                          for(int i = 4; i <= 8; i++)
                            generateSelectionBox(
                              id: i,
                              width: 80.0,
                              height: 80.0,
                              color: wordLenSelectionColors[i - 4]!,
                              primaryText: '$i',
                              primaryTextSize: 25.0,
                            ),
                        ],
                      ),
                    ),
                  ),
                ],
              ),
            ),
            Container(
              width: double.infinity,
              height: 150.0,
              decoration: BoxDecoration(
                color: chancesSelectionColors[maxChances - 1]!.withOpacity(0.2),
                borderRadius: BorderRadius.circular(10.0),
              ),
              alignment: Alignment.centerLeft,
              padding: const EdgeInsets.all(10.0),
              margin: const EdgeInsets.symmetric(horizontal: 10.0, vertical: 10.0),
              child: Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: [
                  Padding(
                    padding: const EdgeInsets.fromLTRB(15.0, 10.0, 0.0, 10.0),
                    child: Text(
                      'Max Attempts',
                      style: TextStyle(
                        fontSize: 22.0,
                        fontWeight: FontWeight.bold,
                        color: chancesSelectionColors[maxChances - 1]!,
                      ),
                    ),
                  ),
                  SelectionGroupProvider(
                    defaultSelection: 6,
                    onChanged: (sel) => setState(() => maxChances = sel),
                    selections: SingleChildScrollView(
                      scrollDirection: Axis.horizontal,
                      child: Row(
                        children: [
                          for(int i = 1; i <= 8; i++)
                            generateSelectionBox(
                              id: i,
                              width: 80.0,
                              height: 80.0,
                              color: chancesSelectionColors[i - 1]!,
                              primaryText: '$i',
                              primaryTextSize: 25.0,
                            ),
                        ],
                      ),
                    ),
                  ),
                ],
              ),
            ),
            Container(
              width: double.infinity,
              decoration: BoxDecoration(
                color: (dicBook[dicBookIndex][3]! as Color).withOpacity(0.2),
                borderRadius: BorderRadius.circular(10.0),
              ),
              margin: const EdgeInsets.all(10.0),
              padding: const EdgeInsets.all(15.0),
              child: Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: [
                  Padding(
                    padding: const EdgeInsets.fromLTRB(15.0, 10.0, 0.0, 10.0),
                    child: Text(
                      'Word List',
                      style: TextStyle(
                        fontSize: 22.0,
                        fontWeight: FontWeight.bold,
                        color: (dicBook[dicBookIndex][3]! as Color),
                      ),
                    ),
                  ),
                  SelectionGroupProvider(
                    defaultSelection: 0,
                    onChanged: (sel) => setState(() => dicBookIndex = sel),
                    selections: SingleChildScrollView(
                      scrollDirection: Axis.horizontal,
                      child: Row(
                        children: dicBookSelections,
                      ),
                    ),
                  ),
                ],
              ),
            ),
            Padding(
              padding: const EdgeInsets.only(bottom: 10.0),
              child: Row(
                children: [
                  Expanded(
                    child: Container(
                      decoration: BoxDecoration(
                        color: Colors.teal.withOpacity(0.2),
                        borderRadius: BorderRadius.circular(10.0),
                      ),
                      margin: const EdgeInsets.all(10.0),
                      child: InkWell(
                        onTap: (){
                          Navigator.of(context).push(MaterialPageRoute(builder: (context) {
                            return LoadingPage(dicName: dicBook[dicBookIndex][0] as String, wordLen: wordLen, maxChances: maxChances, gameMode: 0);
                          }));
                        },
                        borderRadius: BorderRadius.circular(10.0),
                        child: Container(
                          alignment: Alignment.center,
                          padding: const EdgeInsets.symmetric(horizontal: 30.0, vertical: 30.0),
                          child: const Text(
                            'Start Normal',
                            style: TextStyle(
                              fontSize: 22.0,
                              fontWeight: FontWeight.bold,
                              color: Colors.teal,
                            ),
                          ),
                        ),
                      ),
                    ),
                  ),
                  // Expanded(
                  //   child: Container(
                  //     decoration: BoxDecoration(
                  //       color: Colors.pink[200]!.withOpacity(0.2),
                  //       borderRadius: BorderRadius.circular(10.0),
                  //     ),
                  //     margin: const EdgeInsets.all(10.0),
                  //     child: InkWell(
                  //       onTap: (){},
                  //       borderRadius: BorderRadius.circular(10.0),
                  //       child: Container(
                  //         alignment: Alignment.center,
                  //         padding: const EdgeInsets.symmetric(horizontal: 30.0, vertical: 30.0),
                  //         child: Text(
                  //           'Start Hard',
                  //           style: TextStyle(
                  //             fontSize: 22.0,
                  //             fontWeight: FontWeight.bold,
                  //             color: Colors.pink[400],
                  //           ),
                  //         ),
                  //       ),
                  //     ),
                  //   ),
                  // ),
                ],
              ),
            ),
          ],
        ),
      ),
    );
  }
}