2.0.1
Co-authored-by: Richard Pavlikán <richardpavlikan@gmail.com>
This commit is contained in:
		
							parent
							
								
									95b26b4063
								
							
						
					
					
						commit
						f7eaf804bd
					
				
					 32 changed files with 4664 additions and 1487 deletions
				
			
		| 
						 | 
				
			
			@ -2,40 +2,20 @@ import 'package:cloud_firestore/cloud_firestore.dart';
 | 
			
		|||
import 'package:denikprogramatora/okna/app.dart';
 | 
			
		||||
import 'package:denikprogramatora/okna/settings.dart';
 | 
			
		||||
import 'package:denikprogramatora/okna/signin_page.dart';
 | 
			
		||||
import 'package:denikprogramatora/utils/datum_cas.dart';
 | 
			
		||||
import 'package:denikprogramatora/utils/devicecontainer.dart';
 | 
			
		||||
import 'package:denikprogramatora/utils/input_decoration.dart';
 | 
			
		||||
import 'package:denikprogramatora/utils/loading_widget.dart';
 | 
			
		||||
import 'package:denikprogramatora/utils/months.dart';
 | 
			
		||||
import 'package:denikprogramatora/utils/my_category.dart';
 | 
			
		||||
import 'package:denikprogramatora/utils/my_container.dart';
 | 
			
		||||
import 'package:denikprogramatora/utils/new_record_dialog.dart';
 | 
			
		||||
import 'package:denikprogramatora/utils/programmer.dart';
 | 
			
		||||
import 'package:denikprogramatora/utils/show_info_dialog.dart';
 | 
			
		||||
import 'package:denikprogramatora/utils/vzhled.dart';
 | 
			
		||||
import 'package:firebase_auth/firebase_auth.dart';
 | 
			
		||||
import 'package:flutter/foundation.dart';
 | 
			
		||||
import 'package:flutter/material.dart';
 | 
			
		||||
import 'package:flutter/services.dart';
 | 
			
		||||
import 'package:responsive_sizer/responsive_sizer.dart';
 | 
			
		||||
import 'package:url_launcher/url_launcher_string.dart';
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
        Copyright (C) 2022 Matyáš Caras a Richard Pavlikán
 | 
			
		||||
 | 
			
		||||
        This program is free software: you can redistribute it and/or modify
 | 
			
		||||
        it under the terms of the GNU Affero General Public License as
 | 
			
		||||
        published by the Free Software Foundation, either version 3 of the
 | 
			
		||||
        License, or (at your option) any later version.
 | 
			
		||||
 | 
			
		||||
        This program is distributed in the hope that it will be useful,
 | 
			
		||||
        but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
        MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
        GNU Affero General Public License for more details.
 | 
			
		||||
 | 
			
		||||
        You should have received a copy of the GNU Affero General Public License
 | 
			
		||||
        along with this program.  If not, see <https://www.gnu.org/licenses/>.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
class AllRecordsPage extends StatefulWidget {
 | 
			
		||||
  const AllRecordsPage({super.key});
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -49,30 +29,7 @@ class _AllRecordsPageState extends State<AllRecordsPage> {
 | 
			
		|||
  int selectedDay = DateTime.now().day;
 | 
			
		||||
  int year = DateTime.now().year;
 | 
			
		||||
 | 
			
		||||
  List<MyCategory> categories = [MyCategory("Nic", "nic")];
 | 
			
		||||
  List<Programmer> programmers = [
 | 
			
		||||
    const Programmer("Nic", "nic"),
 | 
			
		||||
    Programmer(name, userUid)
 | 
			
		||||
  ];
 | 
			
		||||
  List filterJazyky = [
 | 
			
		||||
    {"jazyk": "Nic", "barva": 0xff8200f3},
 | 
			
		||||
  ];
 | 
			
		||||
 | 
			
		||||
  late String selectedCategory;
 | 
			
		||||
  late String selectedProgrammer;
 | 
			
		||||
  bool newestToOldest = true;
 | 
			
		||||
  late String selectedJazyk;
 | 
			
		||||
  DateTime fromDate =
 | 
			
		||||
      DateTime(DateTime.now().year, DateTime.now().month, DateTime.now().day);
 | 
			
		||||
  DateTime toDate =
 | 
			
		||||
      DateTime(DateTime.now().year, DateTime.now().month, DateTime.now().day);
 | 
			
		||||
 | 
			
		||||
  bool searchByFromDate = false;
 | 
			
		||||
  bool searchByToDate = false;
 | 
			
		||||
 | 
			
		||||
  int timeHour = 0;
 | 
			
		||||
  int timeMinute = 0;
 | 
			
		||||
  int review = 0;
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  void initState() {
 | 
			
		||||
| 
						 | 
				
			
			@ -86,29 +43,14 @@ class _AllRecordsPageState extends State<AllRecordsPage> {
 | 
			
		|||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    name = FirebaseAuth.instance.currentUser!.displayName!;
 | 
			
		||||
 | 
			
		||||
    ref.collection("programmers").get().then((value) {
 | 
			
		||||
      for (var snap in value.docs) {
 | 
			
		||||
        var data = snap.data();
 | 
			
		||||
 | 
			
		||||
        programmers.add(Programmer(data["name"], snap.id));
 | 
			
		||||
      }
 | 
			
		||||
    ref.get().then((value) {
 | 
			
		||||
      setState(() {
 | 
			
		||||
        name = FirebaseAuth.instance.currentUser!.displayName ??
 | 
			
		||||
            value[
 | 
			
		||||
                "name"]; // fallback když uživatel je vytvořen skrz firebase admin
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    ref.collection("categories").get().then((value) {
 | 
			
		||||
      for (var snap in value.docs) {
 | 
			
		||||
        var data = snap.data();
 | 
			
		||||
        categories.add(MyCategory(data["name"], snap.id));
 | 
			
		||||
      }
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    filterJazyky.addAll(jazyky);
 | 
			
		||||
 | 
			
		||||
    selectedCategory = categories[0].id;
 | 
			
		||||
    selectedProgrammer = programmers[0].id;
 | 
			
		||||
    selectedJazyk = "Nic";
 | 
			
		||||
 | 
			
		||||
    mesic = months[DateTime.now().month - 1];
 | 
			
		||||
 | 
			
		||||
    setState(() {
 | 
			
		||||
| 
						 | 
				
			
			@ -148,7 +90,7 @@ class _AllRecordsPageState extends State<AllRecordsPage> {
 | 
			
		|||
                                      onPressed: () => showAboutDialog(
 | 
			
		||||
                                          context: context,
 | 
			
		||||
                                          applicationName: "Kodelog",
 | 
			
		||||
                                          applicationVersion: "1.1.0",
 | 
			
		||||
                                          applicationVersion: "2.0.1",
 | 
			
		||||
                                          applicationLegalese:
 | 
			
		||||
                                              "©️ 2023 Matyáš Caras a Richard Pavlikán,\n vydáno pod licencí AGPLv3",
 | 
			
		||||
                                          children: [
 | 
			
		||||
| 
						 | 
				
			
			@ -248,465 +190,115 @@ class _AllRecordsPageState extends State<AllRecordsPage> {
 | 
			
		|||
                          Expanded(
 | 
			
		||||
                            child: MyContainer(
 | 
			
		||||
                              width: 90.w,
 | 
			
		||||
                              child: DeviceContainer(
 | 
			
		||||
                                mainAxisAlignmentDesktop:
 | 
			
		||||
                                    MainAxisAlignment.spaceBetween,
 | 
			
		||||
                                children: [
 | 
			
		||||
                                  SizedBox(
 | 
			
		||||
                                    width:
 | 
			
		||||
                                        (Device.screenType == ScreenType.mobile)
 | 
			
		||||
                                            ? 80.w
 | 
			
		||||
                                            : 40.w,
 | 
			
		||||
                                    child: Column(
 | 
			
		||||
                              child: Center(
 | 
			
		||||
                                child: Column(
 | 
			
		||||
                                  children: [
 | 
			
		||||
                                    Row(
 | 
			
		||||
                                      mainAxisAlignment:
 | 
			
		||||
                                          MainAxisAlignment.center,
 | 
			
		||||
                                      children: [
 | 
			
		||||
                                        const Text("Filtr",
 | 
			
		||||
                                            style: Vzhled.nadpis),
 | 
			
		||||
                                        const SizedBox(height: 15),
 | 
			
		||||
                                        Row(
 | 
			
		||||
                                          children: [
 | 
			
		||||
                                            Flexible(
 | 
			
		||||
                                              child: Text(
 | 
			
		||||
                                                  "Záznamy seřazené od ${newestToOldest ? "nejnovějších po nejstarší" : "nejstarších po nejnovější"}"),
 | 
			
		||||
                                            ),
 | 
			
		||||
                                            TextButton(
 | 
			
		||||
                                              onPressed: () {
 | 
			
		||||
                                                setState(() {
 | 
			
		||||
                                                  newestToOldest =
 | 
			
		||||
                                                      !newestToOldest;
 | 
			
		||||
                                                });
 | 
			
		||||
                                              },
 | 
			
		||||
                                              child: const Text(
 | 
			
		||||
                                                "Změnit",
 | 
			
		||||
                                                style: Vzhled.textBtn,
 | 
			
		||||
                                              ),
 | 
			
		||||
                                            )
 | 
			
		||||
                                          ],
 | 
			
		||||
                                        ),
 | 
			
		||||
                                        const SizedBox(height: 15),
 | 
			
		||||
                                        DeviceContainer(
 | 
			
		||||
                                          children: [
 | 
			
		||||
                                            const Text("Kategorie"),
 | 
			
		||||
                                            const SizedBox(width: 15),
 | 
			
		||||
                                            DropdownButton(
 | 
			
		||||
                                              value: selectedCategory,
 | 
			
		||||
                                              items: categories.map((e) {
 | 
			
		||||
                                                return DropdownMenuItem(
 | 
			
		||||
                                                    value: e.id,
 | 
			
		||||
                                                    child: Text(e.name));
 | 
			
		||||
                                              }).toList(),
 | 
			
		||||
                                              onChanged: (value) {
 | 
			
		||||
                                                setState(() {
 | 
			
		||||
                                                  selectedCategory = value!;
 | 
			
		||||
                                                });
 | 
			
		||||
                                              },
 | 
			
		||||
                                            ),
 | 
			
		||||
                                          ],
 | 
			
		||||
                                        ),
 | 
			
		||||
                                        const SizedBox(height: 15),
 | 
			
		||||
                                        DeviceContainer(
 | 
			
		||||
                                          children: [
 | 
			
		||||
                                            const Text("Jazyk"),
 | 
			
		||||
                                            const SizedBox(width: 15),
 | 
			
		||||
                                            DropdownButton(
 | 
			
		||||
                                              value: selectedJazyk,
 | 
			
		||||
                                              dropdownColor:
 | 
			
		||||
                                                  Vzhled.backgroundColor,
 | 
			
		||||
                                              items: filterJazyky
 | 
			
		||||
                                                  .map(
 | 
			
		||||
                                                    (e) => DropdownMenuItem(
 | 
			
		||||
                                                      value: e["jazyk"],
 | 
			
		||||
                                                      child: Text(e["jazyk"]),
 | 
			
		||||
                                                    ),
 | 
			
		||||
                                                  )
 | 
			
		||||
                                                  .toList(),
 | 
			
		||||
                                              onChanged: (value) {
 | 
			
		||||
                                                setState(() {
 | 
			
		||||
                                                  selectedJazyk =
 | 
			
		||||
                                                      (value as String?)!;
 | 
			
		||||
                                                });
 | 
			
		||||
                                              },
 | 
			
		||||
                                            ),
 | 
			
		||||
                                          ],
 | 
			
		||||
                                        ),
 | 
			
		||||
                                        const SizedBox(height: 15),
 | 
			
		||||
                                        DeviceContainer(
 | 
			
		||||
                                          children: [
 | 
			
		||||
                                            const Text("Programátor"),
 | 
			
		||||
                                            const SizedBox(width: 15),
 | 
			
		||||
                                            DropdownButton(
 | 
			
		||||
                                              value: selectedProgrammer,
 | 
			
		||||
                                              items: programmers.map((e) {
 | 
			
		||||
                                                return DropdownMenuItem(
 | 
			
		||||
                                                    value: e.id,
 | 
			
		||||
                                                    child: Text(e.name));
 | 
			
		||||
                                              }).toList(),
 | 
			
		||||
                                              onChanged: (value) {
 | 
			
		||||
                                                setState(() {
 | 
			
		||||
                                                  selectedProgrammer = value!;
 | 
			
		||||
                                                });
 | 
			
		||||
                                              },
 | 
			
		||||
                                            ),
 | 
			
		||||
                                          ],
 | 
			
		||||
                                        ),
 | 
			
		||||
                                        const SizedBox(height: 15),
 | 
			
		||||
                                        DeviceContainer(
 | 
			
		||||
                                          children: [
 | 
			
		||||
                                            const Text("Strávený čas"),
 | 
			
		||||
                                            const SizedBox(width: 15),
 | 
			
		||||
                                            SizedBox(
 | 
			
		||||
                                              width: 75,
 | 
			
		||||
                                              child: TextField(
 | 
			
		||||
                                                decoration:
 | 
			
		||||
                                                    inputDecoration("Hodin"),
 | 
			
		||||
                                                onChanged: (value) {
 | 
			
		||||
                                                  setState(() {
 | 
			
		||||
                                                    timeHour =
 | 
			
		||||
                                                        value.trim().isEmpty
 | 
			
		||||
                                                            ? 0
 | 
			
		||||
                                                            : int.parse(value);
 | 
			
		||||
                                                  });
 | 
			
		||||
                                                },
 | 
			
		||||
                                                keyboardType:
 | 
			
		||||
                                                    TextInputType.number,
 | 
			
		||||
                                                inputFormatters: <
 | 
			
		||||
                                                    TextInputFormatter>[
 | 
			
		||||
                                                  FilteringTextInputFormatter
 | 
			
		||||
                                                      .digitsOnly
 | 
			
		||||
                                                ],
 | 
			
		||||
                                              ),
 | 
			
		||||
                                            ),
 | 
			
		||||
                                            const SizedBox(width: 15),
 | 
			
		||||
                                            SizedBox(
 | 
			
		||||
                                              width: 75,
 | 
			
		||||
                                              child: TextField(
 | 
			
		||||
                                                decoration:
 | 
			
		||||
                                                    inputDecoration("Minut"),
 | 
			
		||||
                                                onChanged: (value) {
 | 
			
		||||
                                                  setState(() {
 | 
			
		||||
                                                    timeMinute =
 | 
			
		||||
                                                        value.trim().isEmpty
 | 
			
		||||
                                                            ? 0
 | 
			
		||||
                                                            : int.parse(value);
 | 
			
		||||
                                                  });
 | 
			
		||||
                                                },
 | 
			
		||||
                                                keyboardType:
 | 
			
		||||
                                                    TextInputType.number,
 | 
			
		||||
                                                inputFormatters: <
 | 
			
		||||
                                                    TextInputFormatter>[
 | 
			
		||||
                                                  FilteringTextInputFormatter
 | 
			
		||||
                                                      .digitsOnly
 | 
			
		||||
                                                ],
 | 
			
		||||
                                              ),
 | 
			
		||||
                                            ),
 | 
			
		||||
                                            const SizedBox(width: 15),
 | 
			
		||||
                                            if (timeMinute != 0 ||
 | 
			
		||||
                                                timeHour != 0)
 | 
			
		||||
                                              TextButton(
 | 
			
		||||
                                                onPressed: () {
 | 
			
		||||
                                                  setState(() {
 | 
			
		||||
                                                    timeMinute = 0;
 | 
			
		||||
                                                    timeHour = 0;
 | 
			
		||||
                                                  });
 | 
			
		||||
                                                },
 | 
			
		||||
                                                child: const Text(
 | 
			
		||||
                                                  "Zrušit filtr",
 | 
			
		||||
                                                  style: Vzhled.textBtn,
 | 
			
		||||
                                                ),
 | 
			
		||||
                                              )
 | 
			
		||||
                                          ],
 | 
			
		||||
                                        ),
 | 
			
		||||
                                        const SizedBox(height: 15),
 | 
			
		||||
                                        DeviceContainer(
 | 
			
		||||
                                          children: [
 | 
			
		||||
                                            const Text("Hodnocení"),
 | 
			
		||||
                                            const SizedBox(width: 15),
 | 
			
		||||
                                            Row(
 | 
			
		||||
                                              mainAxisAlignment:
 | 
			
		||||
                                                  MainAxisAlignment
 | 
			
		||||
                                                      .spaceBetween,
 | 
			
		||||
                                              children: List.generate(
 | 
			
		||||
                                                5,
 | 
			
		||||
                                                (index) {
 | 
			
		||||
                                                  return IconButton(
 | 
			
		||||
                                                    onPressed: () {
 | 
			
		||||
                                                      setState(() {
 | 
			
		||||
                                                        review = index + 1;
 | 
			
		||||
                                                      });
 | 
			
		||||
                                                    },
 | 
			
		||||
                                                    icon: Icon(Icons.star,
 | 
			
		||||
                                                        color: (index + 1) <=
 | 
			
		||||
                                                                review
 | 
			
		||||
                                                            ? Colors.yellow
 | 
			
		||||
                                                            : Colors.grey),
 | 
			
		||||
                                                  );
 | 
			
		||||
                                                },
 | 
			
		||||
                                              ),
 | 
			
		||||
                                            ),
 | 
			
		||||
                                            if (review != 0)
 | 
			
		||||
                                              TextButton(
 | 
			
		||||
                                                onPressed: () {
 | 
			
		||||
                                                  setState(() {
 | 
			
		||||
                                                    review = 0;
 | 
			
		||||
                                                  });
 | 
			
		||||
                                                },
 | 
			
		||||
                                                child: const Text(
 | 
			
		||||
                                                  "Zrušit filtr",
 | 
			
		||||
                                                  style: Vzhled.textBtn,
 | 
			
		||||
                                                ),
 | 
			
		||||
                                              )
 | 
			
		||||
                                          ],
 | 
			
		||||
                                        ),
 | 
			
		||||
                                        const SizedBox(height: 15),
 | 
			
		||||
                                        Row(
 | 
			
		||||
                                          children: [
 | 
			
		||||
                                            const Text("Od: "),
 | 
			
		||||
                                            const SizedBox(width: 15),
 | 
			
		||||
                                            TextButton(
 | 
			
		||||
                                              onPressed: () {
 | 
			
		||||
                                                showDatePicker(
 | 
			
		||||
                                                        context: context,
 | 
			
		||||
                                                        initialDate: fromDate,
 | 
			
		||||
                                                        firstDate: DateTime(
 | 
			
		||||
                                                            DateTime.now()
 | 
			
		||||
                                                                    .year -
 | 
			
		||||
                                                                5),
 | 
			
		||||
                                                        lastDate: DateTime(
 | 
			
		||||
                                                            DateTime.now()
 | 
			
		||||
                                                                    .year +
 | 
			
		||||
                                                                5))
 | 
			
		||||
                                                    .then((value) {
 | 
			
		||||
                                                  setState(() {
 | 
			
		||||
                                                    fromDate = value!;
 | 
			
		||||
                                                    searchByFromDate = true;
 | 
			
		||||
                                                  });
 | 
			
		||||
                                                }).onError(
 | 
			
		||||
                                                        (error, stackTrace) =>
 | 
			
		||||
                                                            null);
 | 
			
		||||
                                              },
 | 
			
		||||
                                              child: Text(searchByFromDate
 | 
			
		||||
                                                  ? "${fromDate.day}.${fromDate.month}.${fromDate.year}"
 | 
			
		||||
                                                  : "Vybrat den"),
 | 
			
		||||
                                            ),
 | 
			
		||||
                                            const SizedBox(width: 15),
 | 
			
		||||
                                            if (searchByFromDate)
 | 
			
		||||
                                              TextButton(
 | 
			
		||||
                                                onPressed: () {
 | 
			
		||||
                                                  setState(() {
 | 
			
		||||
                                                    searchByFromDate = false;
 | 
			
		||||
                                                  });
 | 
			
		||||
                                                },
 | 
			
		||||
                                                child: const Text(
 | 
			
		||||
                                                  ("Zrušit filtr"),
 | 
			
		||||
                                                  style: Vzhled.textBtn,
 | 
			
		||||
                                                ),
 | 
			
		||||
                                              ),
 | 
			
		||||
                                          ],
 | 
			
		||||
                                        ),
 | 
			
		||||
                                        const SizedBox(height: 5),
 | 
			
		||||
                                        Row(
 | 
			
		||||
                                          children: [
 | 
			
		||||
                                            const Text("Do: "),
 | 
			
		||||
                                            const SizedBox(width: 15),
 | 
			
		||||
                                            TextButton(
 | 
			
		||||
                                              onPressed: () {
 | 
			
		||||
                                                showDatePicker(
 | 
			
		||||
                                                        context: context,
 | 
			
		||||
                                                        initialDate: toDate,
 | 
			
		||||
                                                        firstDate: DateTime(
 | 
			
		||||
                                                            DateTime.now()
 | 
			
		||||
                                                                    .year -
 | 
			
		||||
                                                                5),
 | 
			
		||||
                                                        lastDate: DateTime(
 | 
			
		||||
                                                            DateTime.now()
 | 
			
		||||
                                                                    .year +
 | 
			
		||||
                                                                5))
 | 
			
		||||
                                                    .then((value) {
 | 
			
		||||
                                                  setState(() {
 | 
			
		||||
                                                    toDate = value!;
 | 
			
		||||
                                                    searchByToDate = true;
 | 
			
		||||
                                                  });
 | 
			
		||||
                                                }).onError(
 | 
			
		||||
                                                        (error, stackTrace) =>
 | 
			
		||||
                                                            null);
 | 
			
		||||
                                              },
 | 
			
		||||
                                              child: Text(searchByToDate
 | 
			
		||||
                                                  ? "${toDate.day}.${toDate.month}.${toDate.year}"
 | 
			
		||||
                                                  : "Vybrat den"),
 | 
			
		||||
                                            ),
 | 
			
		||||
                                            const SizedBox(width: 15),
 | 
			
		||||
                                            if (searchByToDate)
 | 
			
		||||
                                              TextButton(
 | 
			
		||||
                                                onPressed: () {
 | 
			
		||||
                                                  setState(() {
 | 
			
		||||
                                                    searchByToDate = false;
 | 
			
		||||
                                                  });
 | 
			
		||||
                                                },
 | 
			
		||||
                                                child: const Text(
 | 
			
		||||
                                                  ("Zrušit filtr"),
 | 
			
		||||
                                                  style: Vzhled.textBtn,
 | 
			
		||||
                                                ),
 | 
			
		||||
                                              ),
 | 
			
		||||
                                          ],
 | 
			
		||||
                                        ),
 | 
			
		||||
                                        Text(
 | 
			
		||||
                                            "Záznamy seřazené \nod ${newestToOldest ? "nejnovějších po nejstarší" : "nejstarších po nejnovější"}"),
 | 
			
		||||
                                        TextButton(
 | 
			
		||||
                                          onPressed: () {
 | 
			
		||||
                                            setState(() {
 | 
			
		||||
                                              newestToOldest = !newestToOldest;
 | 
			
		||||
                                            });
 | 
			
		||||
                                          },
 | 
			
		||||
                                          child: const Text(
 | 
			
		||||
                                            "Změnit",
 | 
			
		||||
                                            style: Vzhled.textBtn,
 | 
			
		||||
                                          ),
 | 
			
		||||
                                        )
 | 
			
		||||
                                      ],
 | 
			
		||||
                                    ),
 | 
			
		||||
                                  ),
 | 
			
		||||
                                  SizedBox(
 | 
			
		||||
                                    width:
 | 
			
		||||
                                        (Device.screenType == ScreenType.mobile)
 | 
			
		||||
                                            ? 80.w
 | 
			
		||||
                                            : 40.w,
 | 
			
		||||
                                    child: StreamBuilder(
 | 
			
		||||
                                      stream: ref
 | 
			
		||||
                                          .collection("records")
 | 
			
		||||
                                          .orderBy("fromDate",
 | 
			
		||||
                                              descending: newestToOldest)
 | 
			
		||||
                                          .snapshots(),
 | 
			
		||||
                                      builder: (context, snapshot) {
 | 
			
		||||
                                        if (snapshot.hasData) {
 | 
			
		||||
                                          var docs = snapshot.data!.docs;
 | 
			
		||||
                                    const SizedBox(height: 5),
 | 
			
		||||
                                    SizedBox(
 | 
			
		||||
                                      width: (Device.screenType ==
 | 
			
		||||
                                              ScreenType.mobile)
 | 
			
		||||
                                          ? 80.w
 | 
			
		||||
                                          : 40.w,
 | 
			
		||||
                                      child: StreamBuilder(
 | 
			
		||||
                                        stream: ref
 | 
			
		||||
                                            .collection("records")
 | 
			
		||||
                                            .orderBy("date",
 | 
			
		||||
                                                descending: newestToOldest)
 | 
			
		||||
                                            .snapshots(),
 | 
			
		||||
                                        builder: (context, snapshot) {
 | 
			
		||||
                                          if (snapshot.hasData) {
 | 
			
		||||
                                            var docs = snapshot.data!.docs;
 | 
			
		||||
 | 
			
		||||
                                          if (selectedProgrammer != "nic") {
 | 
			
		||||
                                            docs = docs
 | 
			
		||||
                                                .where((element) =>
 | 
			
		||||
                                                    element
 | 
			
		||||
                                                        .data()["programmer"] ==
 | 
			
		||||
                                                    selectedProgrammer)
 | 
			
		||||
                                                .toList();
 | 
			
		||||
                                          }
 | 
			
		||||
                                            return Column(
 | 
			
		||||
                                              children: List.generate(
 | 
			
		||||
                                                docs.length,
 | 
			
		||||
                                                (index) {
 | 
			
		||||
                                                  var data = docs[index].data();
 | 
			
		||||
 | 
			
		||||
                                          if (selectedCategory != "nic") {
 | 
			
		||||
                                            docs = docs
 | 
			
		||||
                                                .where((element) => (element
 | 
			
		||||
                                                            .data()[
 | 
			
		||||
                                                        "categories"] as List)
 | 
			
		||||
                                                    .contains(selectedCategory))
 | 
			
		||||
                                                .toList();
 | 
			
		||||
                                          }
 | 
			
		||||
 | 
			
		||||
                                          if (selectedJazyk != "Nic") {
 | 
			
		||||
                                            docs = docs
 | 
			
		||||
                                                .where((element) =>
 | 
			
		||||
                                                    element.data()["language"]
 | 
			
		||||
                                                        ["jazyk"] ==
 | 
			
		||||
                                                    selectedJazyk)
 | 
			
		||||
                                                .toList();
 | 
			
		||||
                                          }
 | 
			
		||||
 | 
			
		||||
                                          if (searchByFromDate) {
 | 
			
		||||
                                            docs = docs
 | 
			
		||||
                                                .where((d) =>
 | 
			
		||||
                                                    (d.data()["fromDate"]
 | 
			
		||||
                                                                as Timestamp)
 | 
			
		||||
                                                            .toDate()
 | 
			
		||||
                                                            .compareTo(
 | 
			
		||||
                                                                fromDate) ==
 | 
			
		||||
                                                        1 ||
 | 
			
		||||
                                                    (d.data()["fromDate"]
 | 
			
		||||
                                                                as Timestamp)
 | 
			
		||||
                                                            .toDate()
 | 
			
		||||
                                                            .compareTo(
 | 
			
		||||
                                                                fromDate) ==
 | 
			
		||||
                                                        0)
 | 
			
		||||
                                                .toList();
 | 
			
		||||
                                          }
 | 
			
		||||
 | 
			
		||||
                                          if (searchByToDate) {
 | 
			
		||||
                                            docs = docs
 | 
			
		||||
                                                .where((d) =>
 | 
			
		||||
                                                    (d.data()["toDate"]
 | 
			
		||||
                                                                as Timestamp)
 | 
			
		||||
                                                            .toDate()
 | 
			
		||||
                                                            .compareTo(
 | 
			
		||||
                                                                toDate) ==
 | 
			
		||||
                                                        -1 ||
 | 
			
		||||
                                                    (d.data()["toDate"]
 | 
			
		||||
                                                                as Timestamp)
 | 
			
		||||
                                                            .toDate()
 | 
			
		||||
                                                            .compareTo(
 | 
			
		||||
                                                                toDate) ==
 | 
			
		||||
                                                        0)
 | 
			
		||||
                                                .toList();
 | 
			
		||||
                                          }
 | 
			
		||||
 | 
			
		||||
                                          if (timeHour != 0 ||
 | 
			
		||||
                                              timeMinute != 0) {
 | 
			
		||||
                                            if (kDebugMode) {
 | 
			
		||||
                                              print(
 | 
			
		||||
                                                  "${timeHour == 0 ? "" : (timeHour == 1 ? "$timeHour hodina" : "$timeHour hodin")}${timeMinute == 0 ? "" : (timeMinute == 1 ? "a $timeMinute minuta" : " a $timeMinute minut")}");
 | 
			
		||||
                                            }
 | 
			
		||||
                                            docs = docs
 | 
			
		||||
                                                .where((element) => (element
 | 
			
		||||
                                                        .data()["codingTime"] ==
 | 
			
		||||
                                                    "${timeHour == 0 ? "" : (timeHour == 1 ? "$timeHour hodina" : "$timeHour hodin")}${timeMinute == 0 ? "" : (timeMinute == 1 ? "a $timeMinute minuta" : " a $timeMinute minut")}"))
 | 
			
		||||
                                                .toList();
 | 
			
		||||
                                          }
 | 
			
		||||
 | 
			
		||||
                                          if (review != 0) {
 | 
			
		||||
                                            docs = docs
 | 
			
		||||
                                                .where((element) =>
 | 
			
		||||
                                                    element.data()["review"] ==
 | 
			
		||||
                                                    review)
 | 
			
		||||
                                                .toList();
 | 
			
		||||
                                          }
 | 
			
		||||
 | 
			
		||||
                                          return Column(
 | 
			
		||||
                                            children: List.generate(
 | 
			
		||||
                                              docs.length,
 | 
			
		||||
                                              (index) {
 | 
			
		||||
                                                var data = docs[index].data();
 | 
			
		||||
 | 
			
		||||
                                                return Padding(
 | 
			
		||||
                                                  padding:
 | 
			
		||||
                                                      const EdgeInsets.all(8.0),
 | 
			
		||||
                                                  child: Container(
 | 
			
		||||
                                                    decoration: BoxDecoration(
 | 
			
		||||
                                                      borderRadius:
 | 
			
		||||
                                                          const BorderRadius
 | 
			
		||||
                                                              .all(
 | 
			
		||||
                                                        Radius.circular(4),
 | 
			
		||||
                                                  return Padding(
 | 
			
		||||
                                                    padding:
 | 
			
		||||
                                                        const EdgeInsets.all(
 | 
			
		||||
                                                            8.0),
 | 
			
		||||
                                                    child: Container(
 | 
			
		||||
                                                      decoration: BoxDecoration(
 | 
			
		||||
                                                        borderRadius:
 | 
			
		||||
                                                            const BorderRadius
 | 
			
		||||
                                                                .all(
 | 
			
		||||
                                                          Radius.circular(4),
 | 
			
		||||
                                                        ),
 | 
			
		||||
                                                        color: Color(data[
 | 
			
		||||
                                                                "programming_language"]
 | 
			
		||||
                                                            ["barva"]),
 | 
			
		||||
                                                      ),
 | 
			
		||||
                                                      color: Color(
 | 
			
		||||
                                                          data["language"]
 | 
			
		||||
                                                              ["barva"]),
 | 
			
		||||
                                                    ),
 | 
			
		||||
                                                    child: Material(
 | 
			
		||||
                                                      color: Colors.transparent,
 | 
			
		||||
                                                      child: InkWell(
 | 
			
		||||
                                                        onTap: () =>
 | 
			
		||||
                                                            showInfoDialog(
 | 
			
		||||
                                                                context,
 | 
			
		||||
                                                                data,
 | 
			
		||||
                                                                docs[index].id),
 | 
			
		||||
                                                        child: Padding(
 | 
			
		||||
                                                          padding:
 | 
			
		||||
                                                              const EdgeInsets
 | 
			
		||||
                                                                  .all(8.0),
 | 
			
		||||
                                                          child: Row(
 | 
			
		||||
                                                            children: [
 | 
			
		||||
                                                              Text(
 | 
			
		||||
                                                                  "${(data["fromDate"] as Timestamp).toDate().year}.${(data["fromDate"] as Timestamp).toDate().month}.${(data["fromDate"] as Timestamp).toDate().day} ${(data["fromDate"] as Timestamp).toDate().hour < 10 ? "0${(data["fromDate"] as Timestamp).toDate().hour}" : (data["fromDate"] as Timestamp).toDate().hour}:${(data["fromDate"] as Timestamp).toDate().minute < 10 ? "0${(data["fromDate"] as Timestamp).toDate().minute}" : (data["fromDate"] as Timestamp).toDate().minute}"),
 | 
			
		||||
                                                              const SizedBox(
 | 
			
		||||
                                                                width: 20,
 | 
			
		||||
                                                              ),
 | 
			
		||||
                                                              Text(
 | 
			
		||||
                                                                  " - ${data["language"]["jazyk"]}")
 | 
			
		||||
                                                            ],
 | 
			
		||||
                                                      child: Material(
 | 
			
		||||
                                                        color:
 | 
			
		||||
                                                            Colors.transparent,
 | 
			
		||||
                                                        child: InkWell(
 | 
			
		||||
                                                          onTap: () =>
 | 
			
		||||
                                                              showInfoDialog(
 | 
			
		||||
                                                                  context,
 | 
			
		||||
                                                                  data,
 | 
			
		||||
                                                                  docs[index]
 | 
			
		||||
                                                                      .id,
 | 
			
		||||
                                                                  name),
 | 
			
		||||
                                                          child: Padding(
 | 
			
		||||
                                                            padding:
 | 
			
		||||
                                                                const EdgeInsets
 | 
			
		||||
                                                                    .all(8.0),
 | 
			
		||||
                                                            child: Row(
 | 
			
		||||
                                                              children: [
 | 
			
		||||
                                                                Text((data["date"]
 | 
			
		||||
                                                                        as Timestamp)
 | 
			
		||||
                                                                    .toDate()
 | 
			
		||||
                                                                    .dateString),
 | 
			
		||||
                                                                const SizedBox(
 | 
			
		||||
                                                                  width: 20,
 | 
			
		||||
                                                                ),
 | 
			
		||||
                                                                Text(
 | 
			
		||||
                                                                  "${data["programming_language"]["jazyk"]}",
 | 
			
		||||
                                                                  style: const TextStyle(
 | 
			
		||||
                                                                      fontWeight:
 | 
			
		||||
                                                                          FontWeight
 | 
			
		||||
                                                                              .bold),
 | 
			
		||||
                                                                ),
 | 
			
		||||
                                                                Text(
 | 
			
		||||
                                                                    " - ${data["time_spent"]}")
 | 
			
		||||
                                                              ],
 | 
			
		||||
                                                            ),
 | 
			
		||||
                                                          ),
 | 
			
		||||
                                                        ),
 | 
			
		||||
                                                      ),
 | 
			
		||||
                                                    ),
 | 
			
		||||
                                                  ),
 | 
			
		||||
                                                );
 | 
			
		||||
                                              },
 | 
			
		||||
                                            ),
 | 
			
		||||
                                          );
 | 
			
		||||
                                        }
 | 
			
		||||
                                        return const LoadingWidget();
 | 
			
		||||
                                      },
 | 
			
		||||
                                                  );
 | 
			
		||||
                                                },
 | 
			
		||||
                                              ),
 | 
			
		||||
                                            );
 | 
			
		||||
                                          }
 | 
			
		||||
                                          return const LoadingWidget();
 | 
			
		||||
                                        },
 | 
			
		||||
                                      ),
 | 
			
		||||
                                    ),
 | 
			
		||||
                                  ),
 | 
			
		||||
                                ],
 | 
			
		||||
                                  ],
 | 
			
		||||
                                ),
 | 
			
		||||
                              ),
 | 
			
		||||
                            ),
 | 
			
		||||
                          ),
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -66,10 +66,15 @@ class _HlavniOknoState extends State<HlavniOkno> {
 | 
			
		|||
          (route) => false);
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    userUid = FirebaseAuth.instance.currentUser!.uid;
 | 
			
		||||
    name = FirebaseAuth.instance.currentUser!.displayName!;
 | 
			
		||||
 | 
			
		||||
    ref.get().then((value) {
 | 
			
		||||
      setState(() {
 | 
			
		||||
        name = FirebaseAuth.instance.currentUser!.displayName ??
 | 
			
		||||
            value[
 | 
			
		||||
                "name"]; // fallback když uživatel je vytvořen skrz firebase admin
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
    mesic = months[DateTime.now().month - 1];
 | 
			
		||||
 | 
			
		||||
    setState(() {
 | 
			
		||||
| 
						 | 
				
			
			@ -108,9 +113,9 @@ class _HlavniOknoState extends State<HlavniOkno> {
 | 
			
		|||
                                      onPressed: () => showAboutDialog(
 | 
			
		||||
                                          context: context,
 | 
			
		||||
                                          applicationName: "Kodelog",
 | 
			
		||||
                                          applicationVersion: "1.1.0",
 | 
			
		||||
                                          applicationVersion: "2.0.1",
 | 
			
		||||
                                          applicationLegalese:
 | 
			
		||||
                                              "©️ 2023 Matyáš Caras a Richard Pavlikán,\n vydáno pod licencí AGPLv3",
 | 
			
		||||
                                              "©️ 2023 Matyáš Caras a Richard Pavlikán" /*+",\n vydáno pod licencí AGPLv3"*/,
 | 
			
		||||
                                          children: [
 | 
			
		||||
                                            TextButton(
 | 
			
		||||
                                              child: const Text("Zdrojový kód"),
 | 
			
		||||
| 
						 | 
				
			
			@ -144,8 +149,8 @@ class _HlavniOknoState extends State<HlavniOkno> {
 | 
			
		|||
                              ),
 | 
			
		||||
                              MyContainer(
 | 
			
		||||
                                width: (Device.screenType == ScreenType.mobile)
 | 
			
		||||
                                    ? 95.w
 | 
			
		||||
                                    : 45.w,
 | 
			
		||||
                                    ? 90.w
 | 
			
		||||
                                    : 40.w,
 | 
			
		||||
                                child: DeviceContainer(
 | 
			
		||||
                                  mainAxisAlignmentDesktop:
 | 
			
		||||
                                      MainAxisAlignment.spaceBetween,
 | 
			
		||||
| 
						 | 
				
			
			@ -220,19 +225,12 @@ class _HlavniOknoState extends State<HlavniOkno> {
 | 
			
		|||
                                        if (snapshot.hasData) {
 | 
			
		||||
                                          var docs = snapshot.data!.docs;
 | 
			
		||||
                                          var jenMesic = docs
 | 
			
		||||
                                              .where((d) =>
 | 
			
		||||
                                                  DateTime.parse(
 | 
			
		||||
                                                          "$year-${(mesic.position + 1 < 10) ? "0${mesic.position + 1}" : mesic.position + 1}-${selectedDay < 10 ? "0$selectedDay" : selectedDay} 00:00:00")
 | 
			
		||||
                                                      .isBefore(
 | 
			
		||||
                                                          (d.data()["toDate"]
 | 
			
		||||
                                                                  as Timestamp)
 | 
			
		||||
                                                              .toDate()) &&
 | 
			
		||||
                                                  DateTime.parse(
 | 
			
		||||
                                                          "$year-${(mesic.position + 1 < 10) ? "0${mesic.position + 1}" : mesic.position + 1}-${selectedDay < 10 ? "0$selectedDay" : selectedDay} 23:59:59")
 | 
			
		||||
                                                      .isAfter(
 | 
			
		||||
                                                          (d.data()["fromDate"]
 | 
			
		||||
                                                                  as Timestamp)
 | 
			
		||||
                                                              .toDate()))
 | 
			
		||||
                                              .where((d) => DateTime.parse(
 | 
			
		||||
                                                      "$year-${(mesic.position + 1 < 10) ? "0${mesic.position + 1}" : mesic.position + 1}-${selectedDay < 10 ? "0$selectedDay" : selectedDay} 00:00:00")
 | 
			
		||||
                                                  .isAtSameMomentAs(
 | 
			
		||||
                                                      (d.data()["date"]
 | 
			
		||||
                                                              as Timestamp)
 | 
			
		||||
                                                          .toDate()))
 | 
			
		||||
                                              .toList() // vybere pouze záznamy, které probíhají ve vybraný den
 | 
			
		||||
                                            ..sort(
 | 
			
		||||
                                              razeni[vybraneRazeni],
 | 
			
		||||
| 
						 | 
				
			
			@ -262,9 +260,9 @@ class _HlavniOknoState extends State<HlavniOkno> {
 | 
			
		|||
                                                              .all(
 | 
			
		||||
                                                        Radius.circular(4),
 | 
			
		||||
                                                      ),
 | 
			
		||||
                                                      color: Color(
 | 
			
		||||
                                                          data["language"]
 | 
			
		||||
                                                              ["barva"]),
 | 
			
		||||
                                                      color: Color(data[
 | 
			
		||||
                                                              "programming_language"]
 | 
			
		||||
                                                          ["barva"]),
 | 
			
		||||
                                                    ),
 | 
			
		||||
                                                    child: Material(
 | 
			
		||||
                                                      color: Colors.transparent,
 | 
			
		||||
| 
						 | 
				
			
			@ -274,7 +272,8 @@ class _HlavniOknoState extends State<HlavniOkno> {
 | 
			
		|||
                                                                context,
 | 
			
		||||
                                                                data,
 | 
			
		||||
                                                                jenMesic[index]
 | 
			
		||||
                                                                    .id),
 | 
			
		||||
                                                                    .id,
 | 
			
		||||
                                                                name),
 | 
			
		||||
                                                        child: Padding(
 | 
			
		||||
                                                          padding:
 | 
			
		||||
                                                              const EdgeInsets
 | 
			
		||||
| 
						 | 
				
			
			@ -282,12 +281,14 @@ class _HlavniOknoState extends State<HlavniOkno> {
 | 
			
		|||
                                                          child: Row(
 | 
			
		||||
                                                            children: [
 | 
			
		||||
                                                              Text(
 | 
			
		||||
                                                                  "${(data["fromDate"] as Timestamp).toDate().hour < 10 ? "0${(data["fromDate"] as Timestamp).toDate().hour}" : (data["fromDate"] as Timestamp).toDate().hour}:${(data["fromDate"] as Timestamp).toDate().minute < 10 ? "0${(data["fromDate"] as Timestamp).toDate().minute}" : (data["fromDate"] as Timestamp).toDate().minute}"),
 | 
			
		||||
                                                              const SizedBox(
 | 
			
		||||
                                                                width: 20,
 | 
			
		||||
                                                                "${data["programming_language"]["jazyk"]}",
 | 
			
		||||
                                                                style: const TextStyle(
 | 
			
		||||
                                                                    fontWeight:
 | 
			
		||||
                                                                        FontWeight
 | 
			
		||||
                                                                            .bold),
 | 
			
		||||
                                                              ),
 | 
			
		||||
                                                              Text(
 | 
			
		||||
                                                                  " - ${data["language"]["jazyk"]}")
 | 
			
		||||
                                                                  " - ${data["time_spent"]}")
 | 
			
		||||
                                                            ],
 | 
			
		||||
                                                          ),
 | 
			
		||||
                                                        ),
 | 
			
		||||
| 
						 | 
				
			
			@ -308,7 +309,10 @@ class _HlavniOknoState extends State<HlavniOkno> {
 | 
			
		|||
                                      height: 50,
 | 
			
		||||
                                    ),
 | 
			
		||||
                                  SizedBox(
 | 
			
		||||
                                    width: 45.w,
 | 
			
		||||
                                    width:
 | 
			
		||||
                                        (Device.screenType == ScreenType.mobile)
 | 
			
		||||
                                            ? 60.w
 | 
			
		||||
                                            : 40.w,
 | 
			
		||||
                                    child: Column(
 | 
			
		||||
                                      children: [
 | 
			
		||||
                                        DeviceContainer(
 | 
			
		||||
| 
						 | 
				
			
			@ -504,9 +508,10 @@ class _HlavniOknoState extends State<HlavniOkno> {
 | 
			
		|||
                : 5),
 | 
			
		||||
        (index) {
 | 
			
		||||
          return Row(
 | 
			
		||||
            mainAxisAlignment: (Device.screenType == ScreenType.mobile)
 | 
			
		||||
                ? MainAxisAlignment.center
 | 
			
		||||
                : MainAxisAlignment.start,
 | 
			
		||||
            mainAxisAlignment: MainAxisAlignment.center,
 | 
			
		||||
            // (Device.screenType == ScreenType.mobile)
 | 
			
		||||
            //     ? MainAxisAlignment.center
 | 
			
		||||
            //     : MainAxisAlignment.start,
 | 
			
		||||
            children: List.generate(
 | 
			
		||||
              (Device.screenType == ScreenType.mobile) ? 3 : 7,
 | 
			
		||||
              (index) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,34 +1,21 @@
 | 
			
		|||
import 'package:denikprogramatora/okna/app.dart';
 | 
			
		||||
import 'package:denikprogramatora/okna/signin_page.dart';
 | 
			
		||||
import 'package:denikprogramatora/okna/users_page.dart';
 | 
			
		||||
import 'package:denikprogramatora/utils/devicecontainer.dart';
 | 
			
		||||
import 'package:denikprogramatora/utils/loading_widget.dart';
 | 
			
		||||
import 'package:firebase_auth/firebase_auth.dart';
 | 
			
		||||
import 'package:flutter/material.dart';
 | 
			
		||||
import 'package:responsive_sizer/responsive_sizer.dart';
 | 
			
		||||
import 'package:url_launcher/url_launcher_string.dart';
 | 
			
		||||
// ignore: avoid_web_libraries_in_flutter
 | 
			
		||||
import 'dart:html' as html;
 | 
			
		||||
 | 
			
		||||
import '../utils/csv.dart';
 | 
			
		||||
import '../utils/my_container.dart';
 | 
			
		||||
import '../utils/new_record_dialog.dart';
 | 
			
		||||
import '../utils/vzhled.dart';
 | 
			
		||||
import 'all_records.dart';
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
        Copyright (C) 2022 Matyáš Caras a Richard Pavlikán
 | 
			
		||||
 | 
			
		||||
        This program is free software: you can redistribute it and/or modify
 | 
			
		||||
        it under the terms of the GNU Affero General Public License as
 | 
			
		||||
        published by the Free Software Foundation, either version 3 of the
 | 
			
		||||
        License, or (at your option) any later version.
 | 
			
		||||
 | 
			
		||||
        This program is distributed in the hope that it will be useful,
 | 
			
		||||
        but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
        MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
        GNU Affero General Public License for more details.
 | 
			
		||||
 | 
			
		||||
        You should have received a copy of the GNU Affero General Public License
 | 
			
		||||
        along with this program.  If not, see <https://www.gnu.org/licenses/>.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
class NastaveniOkno extends StatefulWidget {
 | 
			
		||||
  const NastaveniOkno({super.key});
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -39,6 +26,8 @@ class NastaveniOkno extends StatefulWidget {
 | 
			
		|||
class _NastaveniOknoState extends State<NastaveniOkno> {
 | 
			
		||||
  var _loading = true;
 | 
			
		||||
  var name = "error";
 | 
			
		||||
  bool isAdmin = false;
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  void initState() {
 | 
			
		||||
    super.initState();
 | 
			
		||||
| 
						 | 
				
			
			@ -49,7 +38,16 @@ class _NastaveniOknoState extends State<NastaveniOkno> {
 | 
			
		|||
          (route) => false);
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
    name = FirebaseAuth.instance.currentUser!.displayName!;
 | 
			
		||||
 | 
			
		||||
    ref.get().then((value) {
 | 
			
		||||
      setState(() {
 | 
			
		||||
        name = FirebaseAuth.instance.currentUser!.displayName ??
 | 
			
		||||
            value[
 | 
			
		||||
                "name"]; // fallback když uživatel je vytvořen skrz firebase admin
 | 
			
		||||
 | 
			
		||||
        isAdmin = value["isAdmin"];
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    setState(() {
 | 
			
		||||
      _loading = false;
 | 
			
		||||
| 
						 | 
				
			
			@ -60,247 +58,380 @@ class _NastaveniOknoState extends State<NastaveniOkno> {
 | 
			
		|||
  Widget build(BuildContext context) {
 | 
			
		||||
    return Scaffold(
 | 
			
		||||
      body: SingleChildScrollView(
 | 
			
		||||
          child: Center(
 | 
			
		||||
        child: SizedBox(
 | 
			
		||||
          width: 90.w,
 | 
			
		||||
          height: 100.h,
 | 
			
		||||
          child: (_loading)
 | 
			
		||||
              ? const LoadingWidget()
 | 
			
		||||
              : Column(children: [
 | 
			
		||||
                  DeviceContainer(
 | 
			
		||||
                    mainAxisAlignmentDesktop: MainAxisAlignment.spaceBetween,
 | 
			
		||||
        child: Center(
 | 
			
		||||
          child: SizedBox(
 | 
			
		||||
            width: 90.w,
 | 
			
		||||
            height: 100.h,
 | 
			
		||||
            child: (_loading)
 | 
			
		||||
                ? const LoadingWidget()
 | 
			
		||||
                : Column(
 | 
			
		||||
                    children: [
 | 
			
		||||
                      MyContainer(
 | 
			
		||||
                        width: (Device.screenType == ScreenType.mobile)
 | 
			
		||||
                            ? 90.w
 | 
			
		||||
                            : 35.w,
 | 
			
		||||
                        child: Row(
 | 
			
		||||
                          mainAxisAlignment: MainAxisAlignment.spaceBetween,
 | 
			
		||||
                          children: [
 | 
			
		||||
                            if (name != "error") Text("Ahoj $name"),
 | 
			
		||||
                            TextButton(
 | 
			
		||||
                              onPressed: () => showAboutDialog(
 | 
			
		||||
                                  context: context,
 | 
			
		||||
                                  applicationName: "Kodelog",
 | 
			
		||||
                                  applicationVersion: "1.1.0",
 | 
			
		||||
                                  applicationLegalese:
 | 
			
		||||
                                      "©️ 2023 Matyáš Caras a Richard Pavlikán,\n vydáno pod licencí AGPLv3",
 | 
			
		||||
                                  children: [
 | 
			
		||||
                                    TextButton(
 | 
			
		||||
                                      child: const Text("Zdrojový kód"),
 | 
			
		||||
                                      onPressed: () => launchUrlString(
 | 
			
		||||
                                          "https://github.com/Royal-Buccaneers/kodelog"),
 | 
			
		||||
                                    )
 | 
			
		||||
                                  ]),
 | 
			
		||||
                              child: const Text(
 | 
			
		||||
                                "Licence",
 | 
			
		||||
                                style: Vzhled.textBtn,
 | 
			
		||||
                              ),
 | 
			
		||||
                      DeviceContainer(
 | 
			
		||||
                        mainAxisAlignmentDesktop:
 | 
			
		||||
                            MainAxisAlignment.spaceBetween,
 | 
			
		||||
                        children: [
 | 
			
		||||
                          MyContainer(
 | 
			
		||||
                            width: (Device.screenType == ScreenType.mobile)
 | 
			
		||||
                                ? 90.w
 | 
			
		||||
                                : 35.w,
 | 
			
		||||
                            child: Row(
 | 
			
		||||
                              mainAxisAlignment: MainAxisAlignment.spaceBetween,
 | 
			
		||||
                              children: [
 | 
			
		||||
                                if (name != "error") Text("Ahoj $name"),
 | 
			
		||||
                                TextButton(
 | 
			
		||||
                                  onPressed: () => showAboutDialog(
 | 
			
		||||
                                      context: context,
 | 
			
		||||
                                      applicationName: "Kodelog",
 | 
			
		||||
                                      applicationVersion: "2.0.1",
 | 
			
		||||
                                      applicationLegalese:
 | 
			
		||||
                                          "©️ 2023 Matyáš Caras a Richard Pavlikán,\n vydáno pod licencí AGPLv3",
 | 
			
		||||
                                      children: [
 | 
			
		||||
                                        TextButton(
 | 
			
		||||
                                          child: const Text("Zdrojový kód"),
 | 
			
		||||
                                          onPressed: () => launchUrlString(
 | 
			
		||||
                                              "https://github.com/Royal-Buccaneers/kodelog"),
 | 
			
		||||
                                        )
 | 
			
		||||
                                      ]),
 | 
			
		||||
                                  child: const Text(
 | 
			
		||||
                                    "Licence",
 | 
			
		||||
                                    style: Vzhled.textBtn,
 | 
			
		||||
                                  ),
 | 
			
		||||
                                ),
 | 
			
		||||
                                TextButton(
 | 
			
		||||
                                  onPressed: () async {
 | 
			
		||||
                                    await FirebaseAuth.instance.signOut();
 | 
			
		||||
                                    if (!mounted) return;
 | 
			
		||||
                                    Navigator.pushAndRemoveUntil(
 | 
			
		||||
                                        context,
 | 
			
		||||
                                        MaterialPageRoute(
 | 
			
		||||
                                            builder: (c) => const SignInPage()),
 | 
			
		||||
                                        (route) => false);
 | 
			
		||||
                                  },
 | 
			
		||||
                                  child: const Text(
 | 
			
		||||
                                    "Odhlásit se",
 | 
			
		||||
                                    style: Vzhled.textBtn,
 | 
			
		||||
                                  ),
 | 
			
		||||
                                )
 | 
			
		||||
                              ],
 | 
			
		||||
                            ),
 | 
			
		||||
                            TextButton(
 | 
			
		||||
                              onPressed: () async {
 | 
			
		||||
                                await FirebaseAuth.instance.signOut();
 | 
			
		||||
                                if (!mounted) return;
 | 
			
		||||
                                Navigator.pushAndRemoveUntil(
 | 
			
		||||
                                    context,
 | 
			
		||||
                                    MaterialPageRoute(
 | 
			
		||||
                                        builder: (c) => const SignInPage()),
 | 
			
		||||
                                    (route) => false);
 | 
			
		||||
                              },
 | 
			
		||||
                              child: const Text(
 | 
			
		||||
                                "Odhlásit se",
 | 
			
		||||
                                style: Vzhled.textBtn,
 | 
			
		||||
                              ),
 | 
			
		||||
                            )
 | 
			
		||||
                          ],
 | 
			
		||||
                        ),
 | 
			
		||||
                          ),
 | 
			
		||||
                          MyContainer(
 | 
			
		||||
                            width: (Device.screenType == ScreenType.mobile)
 | 
			
		||||
                                ? 90.w
 | 
			
		||||
                                : 40.w,
 | 
			
		||||
                            child: DeviceContainer(
 | 
			
		||||
                              mainAxisAlignmentDesktop:
 | 
			
		||||
                                  MainAxisAlignment.spaceBetween,
 | 
			
		||||
                              children: [
 | 
			
		||||
                                TextButton(
 | 
			
		||||
                                  onPressed: () => Navigator.of(context)
 | 
			
		||||
                                      .pushReplacement(MaterialPageRoute(
 | 
			
		||||
                                          builder: (context) =>
 | 
			
		||||
                                              const HlavniOkno())),
 | 
			
		||||
                                  child: const Text(
 | 
			
		||||
                                    "Denní přehled",
 | 
			
		||||
                                    style: TextStyle(color: Vzhled.textColor),
 | 
			
		||||
                                  ),
 | 
			
		||||
                                ),
 | 
			
		||||
                                const SizedBox(height: 5),
 | 
			
		||||
                                TextButton(
 | 
			
		||||
                                  onPressed: () {
 | 
			
		||||
                                    Navigator.pushReplacement(
 | 
			
		||||
                                        context,
 | 
			
		||||
                                        MaterialPageRoute(
 | 
			
		||||
                                            builder: (context) =>
 | 
			
		||||
                                                const AllRecordsPage()));
 | 
			
		||||
                                  },
 | 
			
		||||
                                  child: const Text(
 | 
			
		||||
                                    "Všechny\nzáznamy",
 | 
			
		||||
                                    style: TextStyle(color: Vzhled.textColor),
 | 
			
		||||
                                  ),
 | 
			
		||||
                                ),
 | 
			
		||||
                                const SizedBox(height: 5),
 | 
			
		||||
                                TextButton(
 | 
			
		||||
                                  onPressed: () {},
 | 
			
		||||
                                  child: const Text(
 | 
			
		||||
                                    "Nastavení",
 | 
			
		||||
                                    style: TextStyle(
 | 
			
		||||
                                      color: Vzhled.textColor,
 | 
			
		||||
                                      fontWeight: FontWeight.bold,
 | 
			
		||||
                                    ),
 | 
			
		||||
                                  ),
 | 
			
		||||
                                ),
 | 
			
		||||
                                const SizedBox(height: 5),
 | 
			
		||||
                                OutlinedButton(
 | 
			
		||||
                                  onPressed: () =>
 | 
			
		||||
                                      showCreateItemDialog(context),
 | 
			
		||||
                                  style: Vzhled.orangeCudlik,
 | 
			
		||||
                                  child: const Text(
 | 
			
		||||
                                    "Přidat záznam",
 | 
			
		||||
                                  ),
 | 
			
		||||
                                )
 | 
			
		||||
                              ],
 | 
			
		||||
                            ),
 | 
			
		||||
                          ),
 | 
			
		||||
                        ],
 | 
			
		||||
                      ),
 | 
			
		||||
                      MyContainer(
 | 
			
		||||
                        width: (Device.screenType == ScreenType.mobile)
 | 
			
		||||
                            ? 90.w
 | 
			
		||||
                            : 40.w,
 | 
			
		||||
                        child: DeviceContainer(
 | 
			
		||||
                          mainAxisAlignmentDesktop:
 | 
			
		||||
                              MainAxisAlignment.spaceBetween,
 | 
			
		||||
                          children: [
 | 
			
		||||
                            TextButton(
 | 
			
		||||
                              onPressed: () => Navigator.of(context)
 | 
			
		||||
                                  .pushReplacement(MaterialPageRoute(
 | 
			
		||||
                                      builder: (context) =>
 | 
			
		||||
                                          const HlavniOkno())),
 | 
			
		||||
                              child: const Text(
 | 
			
		||||
                                "Denní přehled",
 | 
			
		||||
                                style: TextStyle(color: Vzhled.textColor),
 | 
			
		||||
                              ),
 | 
			
		||||
                            ),
 | 
			
		||||
                            const SizedBox(height: 5),
 | 
			
		||||
                            TextButton(
 | 
			
		||||
                              onPressed: () {
 | 
			
		||||
                                Navigator.pushReplacement(
 | 
			
		||||
                                    context,
 | 
			
		||||
                                    MaterialPageRoute(
 | 
			
		||||
                                        builder: (context) =>
 | 
			
		||||
                                            const AllRecordsPage()));
 | 
			
		||||
                              },
 | 
			
		||||
                              child: const Text(
 | 
			
		||||
                                "Všechny\nzáznamy",
 | 
			
		||||
                                style: TextStyle(color: Vzhled.textColor),
 | 
			
		||||
                              ),
 | 
			
		||||
                            ),
 | 
			
		||||
                            const SizedBox(height: 5),
 | 
			
		||||
                            TextButton(
 | 
			
		||||
                              onPressed: () {},
 | 
			
		||||
                              child: const Text(
 | 
			
		||||
                                "Nastavení",
 | 
			
		||||
                                style: TextStyle(
 | 
			
		||||
                                  color: Vzhled.textColor,
 | 
			
		||||
                                  fontWeight: FontWeight.bold,
 | 
			
		||||
                      const SizedBox(height: 5),
 | 
			
		||||
                      Expanded(
 | 
			
		||||
                        child: MyContainer(
 | 
			
		||||
                          width: 90.w,
 | 
			
		||||
                          child: Column(
 | 
			
		||||
                            mainAxisAlignment: MainAxisAlignment.center,
 | 
			
		||||
                            children: [
 | 
			
		||||
                              Container(
 | 
			
		||||
                                decoration: const BoxDecoration(
 | 
			
		||||
                                    borderRadius: BorderRadius.all(
 | 
			
		||||
                                      Radius.circular(
 | 
			
		||||
                                        10,
 | 
			
		||||
                                      ),
 | 
			
		||||
                                    ),
 | 
			
		||||
                                    color: Vzhled.purple),
 | 
			
		||||
                                width: 400,
 | 
			
		||||
                                child: InkWell(
 | 
			
		||||
                                  onTap: () => showEditJazyk(),
 | 
			
		||||
                                  child: Padding(
 | 
			
		||||
                                    padding: const EdgeInsets.all(8.0),
 | 
			
		||||
                                    child: Row(
 | 
			
		||||
                                      mainAxisAlignment:
 | 
			
		||||
                                          MainAxisAlignment.center,
 | 
			
		||||
                                      children: const [
 | 
			
		||||
                                        Text(
 | 
			
		||||
                                          "Oblíbený jazyk",
 | 
			
		||||
                                          style: Vzhled.nadpis,
 | 
			
		||||
                                        )
 | 
			
		||||
                                      ],
 | 
			
		||||
                                    ),
 | 
			
		||||
                                  ),
 | 
			
		||||
                                ),
 | 
			
		||||
                              ),
 | 
			
		||||
                            ),
 | 
			
		||||
                            const SizedBox(height: 5),
 | 
			
		||||
                            OutlinedButton(
 | 
			
		||||
                              onPressed: () => showCreateItemDialog(context),
 | 
			
		||||
                              style: Vzhled.orangeCudlik,
 | 
			
		||||
                              child: const Text(
 | 
			
		||||
                                "Přidat záznam",
 | 
			
		||||
                              const SizedBox(
 | 
			
		||||
                                height: 15,
 | 
			
		||||
                              ),
 | 
			
		||||
                            )
 | 
			
		||||
                          ],
 | 
			
		||||
                              Container(
 | 
			
		||||
                                decoration: const BoxDecoration(
 | 
			
		||||
                                    borderRadius: BorderRadius.all(
 | 
			
		||||
                                      Radius.circular(
 | 
			
		||||
                                        10,
 | 
			
		||||
                                      ),
 | 
			
		||||
                                    ),
 | 
			
		||||
                                    color: Vzhled.purple),
 | 
			
		||||
                                width: 400,
 | 
			
		||||
                                child: InkWell(
 | 
			
		||||
                                  onTap: () => showCategoriesDialog(context, [],
 | 
			
		||||
                                      jenMenit: true),
 | 
			
		||||
                                  child: Padding(
 | 
			
		||||
                                    padding: const EdgeInsets.all(8.0),
 | 
			
		||||
                                    child: Row(
 | 
			
		||||
                                      mainAxisAlignment:
 | 
			
		||||
                                          MainAxisAlignment.center,
 | 
			
		||||
                                      children: const [
 | 
			
		||||
                                        Text(
 | 
			
		||||
                                          "Upravit kategorie",
 | 
			
		||||
                                          style: Vzhled.nadpis,
 | 
			
		||||
                                        )
 | 
			
		||||
                                      ],
 | 
			
		||||
                                    ),
 | 
			
		||||
                                  ),
 | 
			
		||||
                                ),
 | 
			
		||||
                              ),
 | 
			
		||||
                              const SizedBox(
 | 
			
		||||
                                height: 15,
 | 
			
		||||
                              ),
 | 
			
		||||
                              DeviceContainer(
 | 
			
		||||
                                mainAxisAlignmentDesktop:
 | 
			
		||||
                                    MainAxisAlignment.center,
 | 
			
		||||
                                mainAxisAlignmentMobile:
 | 
			
		||||
                                    MainAxisAlignment.center,
 | 
			
		||||
                                children: [
 | 
			
		||||
                                  Container(
 | 
			
		||||
                                    decoration: const BoxDecoration(
 | 
			
		||||
                                        borderRadius: BorderRadius.all(
 | 
			
		||||
                                          Radius.circular(
 | 
			
		||||
                                            10,
 | 
			
		||||
                                          ),
 | 
			
		||||
                                        ),
 | 
			
		||||
                                        color: Vzhled.purple),
 | 
			
		||||
                                    width: 400,
 | 
			
		||||
                                    child: InkWell(
 | 
			
		||||
                                      onTap: () async {
 | 
			
		||||
                                        var csv = await exportCsv();
 | 
			
		||||
                                        var blob = html.Blob([csv]);
 | 
			
		||||
                                        var url =
 | 
			
		||||
                                            html.Url.createObjectUrlFromBlob(
 | 
			
		||||
                                                blob);
 | 
			
		||||
                                        var anchor = html.document
 | 
			
		||||
                                                .createElement('a')
 | 
			
		||||
                                            as html.AnchorElement
 | 
			
		||||
                                          ..href = url
 | 
			
		||||
                                          ..style.display = 'none'
 | 
			
		||||
                                          ..download =
 | 
			
		||||
                                              'db_${name.replaceAll(" ", "_")}.csv';
 | 
			
		||||
                                        html.document.body!.children
 | 
			
		||||
                                            .add(anchor);
 | 
			
		||||
 | 
			
		||||
                                        anchor.click();
 | 
			
		||||
 | 
			
		||||
                                        html.document.body!.children
 | 
			
		||||
                                            .remove(anchor);
 | 
			
		||||
                                        html.Url.revokeObjectUrl(url);
 | 
			
		||||
                                      },
 | 
			
		||||
                                      child: Padding(
 | 
			
		||||
                                        padding: const EdgeInsets.all(8.0),
 | 
			
		||||
                                        child: Row(
 | 
			
		||||
                                          mainAxisAlignment:
 | 
			
		||||
                                              MainAxisAlignment.center,
 | 
			
		||||
                                          children: const [
 | 
			
		||||
                                            Text(
 | 
			
		||||
                                              "Exportovat CSV",
 | 
			
		||||
                                              style: Vzhled.nadpis,
 | 
			
		||||
                                            )
 | 
			
		||||
                                          ],
 | 
			
		||||
                                        ),
 | 
			
		||||
                                      ),
 | 
			
		||||
                                    ),
 | 
			
		||||
                                  ),
 | 
			
		||||
                                  const SizedBox(
 | 
			
		||||
                                    width: 10,
 | 
			
		||||
                                    height: 10,
 | 
			
		||||
                                  ),
 | 
			
		||||
                                  Container(
 | 
			
		||||
                                    decoration: const BoxDecoration(
 | 
			
		||||
                                        borderRadius: BorderRadius.all(
 | 
			
		||||
                                          Radius.circular(
 | 
			
		||||
                                            10,
 | 
			
		||||
                                          ),
 | 
			
		||||
                                        ),
 | 
			
		||||
                                        color: Vzhled.purple),
 | 
			
		||||
                                    width: 400,
 | 
			
		||||
                                    child: InkWell(
 | 
			
		||||
                                      onTap: () async {
 | 
			
		||||
                                        try {
 | 
			
		||||
                                          var p = await importCsv(name);
 | 
			
		||||
                                          if (p != -1) {
 | 
			
		||||
                                            if (!mounted) return;
 | 
			
		||||
                                            showDialog(
 | 
			
		||||
                                              context: context,
 | 
			
		||||
                                              builder: (c) => AlertDialog(
 | 
			
		||||
                                                title: const Text("Úspěch!"),
 | 
			
		||||
                                                content: Text(
 | 
			
		||||
                                                    "Importováno $p záznamů"),
 | 
			
		||||
                                                actions: [
 | 
			
		||||
                                                  TextButton(
 | 
			
		||||
                                                      onPressed: () =>
 | 
			
		||||
                                                          Navigator.of(c).pop(),
 | 
			
		||||
                                                      child: const Text("Ok"))
 | 
			
		||||
                                                ],
 | 
			
		||||
                                              ),
 | 
			
		||||
                                            );
 | 
			
		||||
                                          }
 | 
			
		||||
                                        } catch (e) {
 | 
			
		||||
                                          showDialog(
 | 
			
		||||
                                            context: context,
 | 
			
		||||
                                            builder: (c) => AlertDialog(
 | 
			
		||||
                                              title: const Text(
 | 
			
		||||
                                                  "Při importování nastala chyba!"),
 | 
			
		||||
                                              content: Text(e.toString()),
 | 
			
		||||
                                            ),
 | 
			
		||||
                                          );
 | 
			
		||||
                                        }
 | 
			
		||||
                                      },
 | 
			
		||||
                                      child: Padding(
 | 
			
		||||
                                        padding: const EdgeInsets.all(8.0),
 | 
			
		||||
                                        child: Row(
 | 
			
		||||
                                          mainAxisAlignment:
 | 
			
		||||
                                              MainAxisAlignment.center,
 | 
			
		||||
                                          children: const [
 | 
			
		||||
                                            Text(
 | 
			
		||||
                                              "Importovat CSV",
 | 
			
		||||
                                              style: Vzhled.nadpis,
 | 
			
		||||
                                            )
 | 
			
		||||
                                          ],
 | 
			
		||||
                                        ),
 | 
			
		||||
                                      ),
 | 
			
		||||
                                    ),
 | 
			
		||||
                                  ),
 | 
			
		||||
                                ],
 | 
			
		||||
                              ),
 | 
			
		||||
                              const SizedBox(
 | 
			
		||||
                                height: 15,
 | 
			
		||||
                              ),
 | 
			
		||||
                              if (isAdmin)
 | 
			
		||||
                                Container(
 | 
			
		||||
                                  decoration: const BoxDecoration(
 | 
			
		||||
                                      borderRadius: BorderRadius.all(
 | 
			
		||||
                                        Radius.circular(
 | 
			
		||||
                                          10,
 | 
			
		||||
                                        ),
 | 
			
		||||
                                      ),
 | 
			
		||||
                                      color: Vzhled.purple),
 | 
			
		||||
                                  width: 400,
 | 
			
		||||
                                  child: InkWell(
 | 
			
		||||
                                    onTap: () => Navigator.pushReplacement(
 | 
			
		||||
                                      context,
 | 
			
		||||
                                      MaterialPageRoute(
 | 
			
		||||
                                        builder: (context) => const UsersPage(),
 | 
			
		||||
                                      ),
 | 
			
		||||
                                    ),
 | 
			
		||||
                                    child: Padding(
 | 
			
		||||
                                      padding: const EdgeInsets.all(8.0),
 | 
			
		||||
                                      child: Row(
 | 
			
		||||
                                        mainAxisAlignment:
 | 
			
		||||
                                            MainAxisAlignment.center,
 | 
			
		||||
                                        children: const [
 | 
			
		||||
                                          Text(
 | 
			
		||||
                                            "Správa uživatelů",
 | 
			
		||||
                                            style: Vzhled.nadpis,
 | 
			
		||||
                                          )
 | 
			
		||||
                                        ],
 | 
			
		||||
                                      ),
 | 
			
		||||
                                    ),
 | 
			
		||||
                                  ),
 | 
			
		||||
                                ),
 | 
			
		||||
                            ],
 | 
			
		||||
                          ),
 | 
			
		||||
                        ),
 | 
			
		||||
                      ),
 | 
			
		||||
                      )
 | 
			
		||||
                    ],
 | 
			
		||||
                  ),
 | 
			
		||||
                  const SizedBox(height: 5),
 | 
			
		||||
                  Expanded(
 | 
			
		||||
                      child: MyContainer(
 | 
			
		||||
                    width: 90.w,
 | 
			
		||||
                    child: Column(
 | 
			
		||||
                        mainAxisAlignment: MainAxisAlignment.center,
 | 
			
		||||
                        children: [
 | 
			
		||||
                          Container(
 | 
			
		||||
                            decoration: const BoxDecoration(
 | 
			
		||||
                              borderRadius: BorderRadius.all(
 | 
			
		||||
                                Radius.circular(
 | 
			
		||||
                                  10,
 | 
			
		||||
                                ),
 | 
			
		||||
                              ),
 | 
			
		||||
                              color: Vzhled.purple,
 | 
			
		||||
                            ),
 | 
			
		||||
                            width: 400,
 | 
			
		||||
                            child: InkWell(
 | 
			
		||||
                              onTap: () => showProgrammersDialog(context,
 | 
			
		||||
                                  jenMenit: true),
 | 
			
		||||
                              child: Padding(
 | 
			
		||||
                                padding: const EdgeInsets.all(8.0),
 | 
			
		||||
                                child: Row(
 | 
			
		||||
                                  mainAxisAlignment: MainAxisAlignment.center,
 | 
			
		||||
                                  children: const [
 | 
			
		||||
                                    Text(
 | 
			
		||||
                                      "Upravit programátory",
 | 
			
		||||
                                      style: Vzhled.nadpis,
 | 
			
		||||
                                    )
 | 
			
		||||
                                  ],
 | 
			
		||||
                                ),
 | 
			
		||||
                              ),
 | 
			
		||||
                            ),
 | 
			
		||||
                          ),
 | 
			
		||||
                          const SizedBox(
 | 
			
		||||
                            height: 15,
 | 
			
		||||
                          ),
 | 
			
		||||
                          Container(
 | 
			
		||||
                            decoration: const BoxDecoration(
 | 
			
		||||
                                borderRadius: BorderRadius.all(
 | 
			
		||||
                                  Radius.circular(
 | 
			
		||||
                                    10,
 | 
			
		||||
                                  ),
 | 
			
		||||
                                ),
 | 
			
		||||
                                color: Vzhled.purple),
 | 
			
		||||
                            width: 400,
 | 
			
		||||
                            child: InkWell(
 | 
			
		||||
                              onTap: () => showCategoriesDialog(context, [],
 | 
			
		||||
                                  jenMenit: true),
 | 
			
		||||
                              child: Padding(
 | 
			
		||||
                                padding: const EdgeInsets.all(8.0),
 | 
			
		||||
                                child: Row(
 | 
			
		||||
                                  mainAxisAlignment: MainAxisAlignment.center,
 | 
			
		||||
                                  children: const [
 | 
			
		||||
                                    Text(
 | 
			
		||||
                                      "Upravit kategorie",
 | 
			
		||||
                                      style: Vzhled.nadpis,
 | 
			
		||||
                                    )
 | 
			
		||||
                                  ],
 | 
			
		||||
                                ),
 | 
			
		||||
                              ),
 | 
			
		||||
                            ),
 | 
			
		||||
                          ),
 | 
			
		||||
                          const SizedBox(
 | 
			
		||||
                            height: 15,
 | 
			
		||||
                          ),
 | 
			
		||||
                          Container(
 | 
			
		||||
                            decoration: const BoxDecoration(
 | 
			
		||||
                                borderRadius: BorderRadius.all(
 | 
			
		||||
                                  Radius.circular(
 | 
			
		||||
                                    10,
 | 
			
		||||
                                  ),
 | 
			
		||||
                                ),
 | 
			
		||||
                                color: Vzhled.purple),
 | 
			
		||||
                            width: 400,
 | 
			
		||||
                            child: InkWell(
 | 
			
		||||
                              onTap: () => showEditJazyk(),
 | 
			
		||||
                              child: Padding(
 | 
			
		||||
                                padding: const EdgeInsets.all(8.0),
 | 
			
		||||
                                child: Row(
 | 
			
		||||
                                  mainAxisAlignment: MainAxisAlignment.center,
 | 
			
		||||
                                  children: const [
 | 
			
		||||
                                    Text(
 | 
			
		||||
                                      "Oblíbený jazyk",
 | 
			
		||||
                                      style: Vzhled.nadpis,
 | 
			
		||||
                                    )
 | 
			
		||||
                                  ],
 | 
			
		||||
                                ),
 | 
			
		||||
                              ),
 | 
			
		||||
                            ),
 | 
			
		||||
                          ),
 | 
			
		||||
                        ]),
 | 
			
		||||
                  ))
 | 
			
		||||
                ]),
 | 
			
		||||
          ),
 | 
			
		||||
        ),
 | 
			
		||||
      )),
 | 
			
		||||
      ),
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  showEditJazyk() {
 | 
			
		||||
    showDialog(
 | 
			
		||||
        context: context,
 | 
			
		||||
        builder: (_) => AlertDialog(
 | 
			
		||||
              title: const Text("Oblíbený jazyk", style: Vzhled.velkyText),
 | 
			
		||||
              scrollable: true,
 | 
			
		||||
              content: SizedBox(
 | 
			
		||||
                width: 20.w,
 | 
			
		||||
                child: StreamBuilder(
 | 
			
		||||
                    stream: ref.snapshots(),
 | 
			
		||||
                    builder: (context, snapshot) {
 | 
			
		||||
                      if (snapshot.hasData) {
 | 
			
		||||
                        return DropdownButton(
 | 
			
		||||
                            value: snapshot.data!.data()!["favourite"],
 | 
			
		||||
                            dropdownColor: Vzhled.backgroundColor,
 | 
			
		||||
                            items: jazyky
 | 
			
		||||
                                .map(
 | 
			
		||||
                                  (e) => DropdownMenuItem(
 | 
			
		||||
                                    value: e["jazyk"],
 | 
			
		||||
                                    child: SizedBox(
 | 
			
		||||
                                        width: 17.w, child: Text(e["jazyk"])),
 | 
			
		||||
                                  ),
 | 
			
		||||
                                )
 | 
			
		||||
                                .toList(),
 | 
			
		||||
                            onChanged: (value) {
 | 
			
		||||
                              ref.update({"favourite": value!});
 | 
			
		||||
                            });
 | 
			
		||||
                      }
 | 
			
		||||
                      return const LoadingWidget();
 | 
			
		||||
                    }),
 | 
			
		||||
              ),
 | 
			
		||||
            ));
 | 
			
		||||
      context: context,
 | 
			
		||||
      builder: (_) => AlertDialog(
 | 
			
		||||
        title: const Text("Oblíbený jazyk", style: Vzhled.velkyText),
 | 
			
		||||
        scrollable: true,
 | 
			
		||||
        content: SizedBox(
 | 
			
		||||
          width: 20.w,
 | 
			
		||||
          child: StreamBuilder(
 | 
			
		||||
              stream: ref.snapshots(),
 | 
			
		||||
              builder: (context, snapshot) {
 | 
			
		||||
                if (snapshot.hasData) {
 | 
			
		||||
                  return DropdownButton(
 | 
			
		||||
                      value: snapshot.data!.data()!["favourite"],
 | 
			
		||||
                      dropdownColor: Vzhled.backgroundColor,
 | 
			
		||||
                      items: jazyky
 | 
			
		||||
                          .map(
 | 
			
		||||
                            (e) => DropdownMenuItem(
 | 
			
		||||
                              value: e["jazyk"],
 | 
			
		||||
                              child: SizedBox(
 | 
			
		||||
                                  width: 17.w, child: Text(e["jazyk"])),
 | 
			
		||||
                            ),
 | 
			
		||||
                          )
 | 
			
		||||
                          .toList(),
 | 
			
		||||
                      onChanged: (value) {
 | 
			
		||||
                        ref.update({"favourite": value!});
 | 
			
		||||
                      });
 | 
			
		||||
                }
 | 
			
		||||
                return const LoadingWidget();
 | 
			
		||||
              }),
 | 
			
		||||
        ),
 | 
			
		||||
      ),
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -9,23 +9,6 @@ import 'package:flutter/scheduler.dart';
 | 
			
		|||
import 'package:responsive_sizer/responsive_sizer.dart';
 | 
			
		||||
import 'package:url_launcher/url_launcher_string.dart';
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
        Copyright (C) 2022 Matyáš Caras a Richard Pavlikán
 | 
			
		||||
 | 
			
		||||
        This program is free software: you can redistribute it and/or modify
 | 
			
		||||
        it under the terms of the GNU Affero General Public License as
 | 
			
		||||
        published by the Free Software Foundation, either version 3 of the
 | 
			
		||||
        License, or (at your option) any later version.
 | 
			
		||||
 | 
			
		||||
        This program is distributed in the hope that it will be useful,
 | 
			
		||||
        but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
        MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
        GNU Affero General Public License for more details.
 | 
			
		||||
 | 
			
		||||
        You should have received a copy of the GNU Affero General Public License
 | 
			
		||||
        along with this program.  If not, see <https://www.gnu.org/licenses/>.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
class SignInPage extends StatefulWidget {
 | 
			
		||||
  const SignInPage({super.key});
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -34,8 +17,10 @@ class SignInPage extends StatefulWidget {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
class _SignInPageState extends State<SignInPage> {
 | 
			
		||||
  bool showSignIn = true;
 | 
			
		||||
  bool isLoading = true;
 | 
			
		||||
  bool isSignInWidget = true;
 | 
			
		||||
  bool showEmailPage = true;
 | 
			
		||||
  String oldDocId = "";
 | 
			
		||||
 | 
			
		||||
  TextEditingController emailCon = TextEditingController();
 | 
			
		||||
  TextEditingController passwordCon = TextEditingController();
 | 
			
		||||
| 
						 | 
				
			
			@ -70,7 +55,7 @@ class _SignInPageState extends State<SignInPage> {
 | 
			
		|||
          : Stack(
 | 
			
		||||
              children: [
 | 
			
		||||
                Center(
 | 
			
		||||
                  child: showSignIn ? signInWidget() : registerWidget(),
 | 
			
		||||
                  child: isSignInWidget ? signInWidget() : registerWidget(),
 | 
			
		||||
                ),
 | 
			
		||||
                Positioned(
 | 
			
		||||
                  bottom: 10,
 | 
			
		||||
| 
						 | 
				
			
			@ -79,7 +64,7 @@ class _SignInPageState extends State<SignInPage> {
 | 
			
		|||
                    onPressed: () => showAboutDialog(
 | 
			
		||||
                        context: context,
 | 
			
		||||
                        applicationName: "Kodelog",
 | 
			
		||||
                        applicationVersion: "1.1.0",
 | 
			
		||||
                        applicationVersion: "2.0.1",
 | 
			
		||||
                        applicationLegalese:
 | 
			
		||||
                            "©️ 2023 Matyáš Caras a Richard Pavlikán,\n vydáno pod licencí AGPLv3",
 | 
			
		||||
                        children: [
 | 
			
		||||
| 
						 | 
				
			
			@ -121,7 +106,7 @@ class _SignInPageState extends State<SignInPage> {
 | 
			
		|||
            SizedBox(
 | 
			
		||||
              width: (Device.screenType == ScreenType.mobile) ? 60.w : 30.w,
 | 
			
		||||
              child: TextFormField(
 | 
			
		||||
                decoration: Vzhled.inputDecoration("E-mail"),
 | 
			
		||||
                decoration: Vzhled.inputDecoration("E-mail nebo Username"),
 | 
			
		||||
                cursorColor: Vzhled.textColor,
 | 
			
		||||
                keyboardType: TextInputType.emailAddress,
 | 
			
		||||
                autocorrect: false,
 | 
			
		||||
| 
						 | 
				
			
			@ -134,9 +119,6 @@ class _SignInPageState extends State<SignInPage> {
 | 
			
		|||
                validator: (value) {
 | 
			
		||||
                  if (value!.trim().isEmpty) {
 | 
			
		||||
                    return "Toto pole je povinné!";
 | 
			
		||||
                  } else if (!RegExp(r'[\w\.]+@[a-z0-9]+\.[a-z]{1,3}')
 | 
			
		||||
                      .hasMatch(value)) {
 | 
			
		||||
                    return "Neplatný e-mail!";
 | 
			
		||||
                  }
 | 
			
		||||
                  return null;
 | 
			
		||||
                },
 | 
			
		||||
| 
						 | 
				
			
			@ -188,11 +170,15 @@ class _SignInPageState extends State<SignInPage> {
 | 
			
		|||
            TextButton(
 | 
			
		||||
              onPressed: () {
 | 
			
		||||
                setState(() {
 | 
			
		||||
                  showSignIn = false;
 | 
			
		||||
                  isSignInWidget = false;
 | 
			
		||||
                  showEmailPage = true;
 | 
			
		||||
                });
 | 
			
		||||
              },
 | 
			
		||||
              child: const Text("Registrovat se", style: Vzhled.textBtn),
 | 
			
		||||
            )
 | 
			
		||||
              child: const Text(
 | 
			
		||||
                "Přihlašuji se poprvé",
 | 
			
		||||
                style: Vzhled.textBtn,
 | 
			
		||||
              ),
 | 
			
		||||
            ),
 | 
			
		||||
          ],
 | 
			
		||||
        ),
 | 
			
		||||
      ),
 | 
			
		||||
| 
						 | 
				
			
			@ -201,7 +187,9 @@ class _SignInPageState extends State<SignInPage> {
 | 
			
		|||
 | 
			
		||||
  Widget registerWidget() {
 | 
			
		||||
    GlobalKey<FormState> form = GlobalKey<FormState>();
 | 
			
		||||
 | 
			
		||||
    return MyContainer(
 | 
			
		||||
      height: 70.h,
 | 
			
		||||
      width: (Device.screenType == ScreenType.mobile) ? 80.w : 40.w,
 | 
			
		||||
      child: Form(
 | 
			
		||||
        key: form,
 | 
			
		||||
| 
						 | 
				
			
			@ -216,119 +204,142 @@ class _SignInPageState extends State<SignInPage> {
 | 
			
		|||
            const SizedBox(
 | 
			
		||||
              height: 30,
 | 
			
		||||
            ),
 | 
			
		||||
            SizedBox(
 | 
			
		||||
              width: (Device.screenType == ScreenType.mobile) ? 60.w : 30.w,
 | 
			
		||||
              child: TextFormField(
 | 
			
		||||
                decoration: Vzhled.inputDecoration("Jméno"),
 | 
			
		||||
                cursorColor: Vzhled.textColor,
 | 
			
		||||
                controller: nameCon,
 | 
			
		||||
                onFieldSubmitted: (_) {
 | 
			
		||||
                  if (form.currentState!.validate()) {
 | 
			
		||||
                    signUp();
 | 
			
		||||
                  }
 | 
			
		||||
                },
 | 
			
		||||
                validator: (value) {
 | 
			
		||||
                  if (value!.trim().isEmpty) {
 | 
			
		||||
                    return "Toto pole je povinné!";
 | 
			
		||||
                  }
 | 
			
		||||
                  return null;
 | 
			
		||||
                },
 | 
			
		||||
              ),
 | 
			
		||||
            ),
 | 
			
		||||
            const SizedBox(
 | 
			
		||||
              height: 20,
 | 
			
		||||
            ),
 | 
			
		||||
            SizedBox(
 | 
			
		||||
              width: (Device.screenType == ScreenType.mobile) ? 60.w : 30.w,
 | 
			
		||||
              child: TextFormField(
 | 
			
		||||
                decoration: Vzhled.inputDecoration("E-mail"),
 | 
			
		||||
                cursorColor: Vzhled.textColor,
 | 
			
		||||
                controller: emailCon,
 | 
			
		||||
                keyboardType: TextInputType.emailAddress,
 | 
			
		||||
                autocorrect: false,
 | 
			
		||||
                onFieldSubmitted: (_) {
 | 
			
		||||
                  if (form.currentState!.validate()) {
 | 
			
		||||
                    signUp();
 | 
			
		||||
                  }
 | 
			
		||||
                },
 | 
			
		||||
                validator: (value) {
 | 
			
		||||
                  if (value!.trim().isEmpty) {
 | 
			
		||||
                    return "Toto pole je povinné!";
 | 
			
		||||
                  } else if (!RegExp(r'[\w\.]+@[a-z0-9]+\.[a-z]{1,3}')
 | 
			
		||||
                      .hasMatch(value)) {
 | 
			
		||||
                    return "Neplatný e-mail!";
 | 
			
		||||
                  }
 | 
			
		||||
                  return null;
 | 
			
		||||
                },
 | 
			
		||||
              ),
 | 
			
		||||
            ),
 | 
			
		||||
            const SizedBox(
 | 
			
		||||
              height: 20,
 | 
			
		||||
            ),
 | 
			
		||||
            SizedBox(
 | 
			
		||||
              width: (Device.screenType == ScreenType.mobile) ? 60.w : 30.w,
 | 
			
		||||
              child: TextFormField(
 | 
			
		||||
                decoration: Vzhled.inputDecoration("Heslo"),
 | 
			
		||||
                cursorColor: Vzhled.textColor,
 | 
			
		||||
                obscureText: true,
 | 
			
		||||
                controller: passwordCon,
 | 
			
		||||
                onFieldSubmitted: (_) {
 | 
			
		||||
                  if (form.currentState!.validate()) {
 | 
			
		||||
                    signUp();
 | 
			
		||||
                  }
 | 
			
		||||
                },
 | 
			
		||||
                validator: (value) {
 | 
			
		||||
                  if (value!.trim().isEmpty) {
 | 
			
		||||
                    return "Toto pole je povinné!";
 | 
			
		||||
                  }
 | 
			
		||||
                  return null;
 | 
			
		||||
                },
 | 
			
		||||
              ),
 | 
			
		||||
            ),
 | 
			
		||||
            const SizedBox(
 | 
			
		||||
              height: 20,
 | 
			
		||||
            ),
 | 
			
		||||
            Row(
 | 
			
		||||
              mainAxisAlignment: MainAxisAlignment.center,
 | 
			
		||||
              children: [
 | 
			
		||||
                const Text(
 | 
			
		||||
                  "Oblíbený jazyk:",
 | 
			
		||||
                  style: TextStyle(
 | 
			
		||||
                    fontWeight: FontWeight.bold,
 | 
			
		||||
            showEmailPage
 | 
			
		||||
                ? SizedBox(
 | 
			
		||||
                    width:
 | 
			
		||||
                        (Device.screenType == ScreenType.mobile) ? 60.w : 30.w,
 | 
			
		||||
                    child: TextFormField(
 | 
			
		||||
                      decoration: Vzhled.inputDecoration("Váš e-mail"),
 | 
			
		||||
                      cursorColor: Vzhled.textColor,
 | 
			
		||||
                      keyboardType: TextInputType.emailAddress,
 | 
			
		||||
                      autocorrect: false,
 | 
			
		||||
                      controller: emailCon,
 | 
			
		||||
                      validator: (value) {
 | 
			
		||||
                        if (value!.trim().isEmpty) {
 | 
			
		||||
                          return "Toto pole je povinné!";
 | 
			
		||||
                        }
 | 
			
		||||
                        return null;
 | 
			
		||||
                      },
 | 
			
		||||
                    ),
 | 
			
		||||
                  )
 | 
			
		||||
                : SizedBox(
 | 
			
		||||
                    width:
 | 
			
		||||
                        (Device.screenType == ScreenType.mobile) ? 60.w : 30.w,
 | 
			
		||||
                    child: TextFormField(
 | 
			
		||||
                      decoration: Vzhled.inputDecoration("Váš nové heslo"),
 | 
			
		||||
                      cursorColor: Vzhled.textColor,
 | 
			
		||||
                      autocorrect: false,
 | 
			
		||||
                      obscureText: true,
 | 
			
		||||
                      controller: passwordCon,
 | 
			
		||||
                      validator: (value) {
 | 
			
		||||
                        if (value!.trim().isEmpty) {
 | 
			
		||||
                          return "Toto pole je povinné!";
 | 
			
		||||
                        }
 | 
			
		||||
                        return null;
 | 
			
		||||
                      },
 | 
			
		||||
                    ),
 | 
			
		||||
                  ),
 | 
			
		||||
                ),
 | 
			
		||||
                const SizedBox(width: 5),
 | 
			
		||||
                DropdownButton(
 | 
			
		||||
                  value: jazyk,
 | 
			
		||||
                  dropdownColor: Vzhled.backgroundColor,
 | 
			
		||||
                  items: jazyky
 | 
			
		||||
                      .map(
 | 
			
		||||
                        (e) => DropdownMenuItem(
 | 
			
		||||
                          value: e["jazyk"],
 | 
			
		||||
                          child: Text(e["jazyk"]),
 | 
			
		||||
                        ),
 | 
			
		||||
                      )
 | 
			
		||||
                      .toList(),
 | 
			
		||||
                  onChanged: (value) {
 | 
			
		||||
                    setState(() {
 | 
			
		||||
                      jazyk = (value as String?)!;
 | 
			
		||||
                    });
 | 
			
		||||
                  },
 | 
			
		||||
                ),
 | 
			
		||||
              ],
 | 
			
		||||
            ),
 | 
			
		||||
            const SizedBox(
 | 
			
		||||
              height: 20,
 | 
			
		||||
            ),
 | 
			
		||||
            OutlinedButton(
 | 
			
		||||
              style: Vzhled.orangeCudlik,
 | 
			
		||||
              onPressed: () async {
 | 
			
		||||
                if (form.currentState!.validate()) {
 | 
			
		||||
                  signUp();
 | 
			
		||||
                }
 | 
			
		||||
              },
 | 
			
		||||
              child: const Text("Registrovat se"),
 | 
			
		||||
            ),
 | 
			
		||||
            showEmailPage
 | 
			
		||||
                ? OutlinedButton(
 | 
			
		||||
                    style: Vzhled.orangeCudlik,
 | 
			
		||||
                    onPressed: () async {
 | 
			
		||||
                      if (form.currentState!.validate()) {
 | 
			
		||||
                        var emailRef = await FirebaseFirestore.instance
 | 
			
		||||
                            .collection("users")
 | 
			
		||||
                            .where("email", isEqualTo: emailCon.text)
 | 
			
		||||
                            .get();
 | 
			
		||||
 | 
			
		||||
                        if (emailRef.docs.isEmpty) {
 | 
			
		||||
                          // ignore: use_build_context_synchronously
 | 
			
		||||
                          showDialog(
 | 
			
		||||
                            context: context,
 | 
			
		||||
                            builder: (c) => const AlertDialog(
 | 
			
		||||
                              title: Text("Chyba"),
 | 
			
		||||
                              content: Text(
 | 
			
		||||
                                  "Účet s tímto emailem neexistuje. Pro přístup do aplikace musí váš email přidat admin aplikace."),
 | 
			
		||||
                            ),
 | 
			
		||||
                          );
 | 
			
		||||
                          return;
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                        setState(() {
 | 
			
		||||
                          oldDocId = emailRef.docs.first.id;
 | 
			
		||||
                          showEmailPage = false;
 | 
			
		||||
                        });
 | 
			
		||||
                      }
 | 
			
		||||
                    },
 | 
			
		||||
                    child: const Text("Pokračovat"),
 | 
			
		||||
                  )
 | 
			
		||||
                : OutlinedButton(
 | 
			
		||||
                    onPressed: () async {
 | 
			
		||||
                      if (form.currentState!.validate()) {
 | 
			
		||||
                        await FirebaseAuth.instance
 | 
			
		||||
                            .createUserWithEmailAndPassword(
 | 
			
		||||
                                email: emailCon.text,
 | 
			
		||||
                                password: passwordCon.text)
 | 
			
		||||
                            .then((value) async {
 | 
			
		||||
                          await FirebaseFirestore.instance
 | 
			
		||||
                              .collection("users")
 | 
			
		||||
                              .doc(oldDocId)
 | 
			
		||||
                              .get()
 | 
			
		||||
                              .then((value) {
 | 
			
		||||
                            FirebaseFirestore.instance
 | 
			
		||||
                                .collection("users")
 | 
			
		||||
                                .doc(FirebaseAuth.instance.currentUser!.uid)
 | 
			
		||||
                                .set({
 | 
			
		||||
                              "name": value["name"],
 | 
			
		||||
                              "favourite": value["favourite"],
 | 
			
		||||
                              "isAdmin": value["isAdmin"],
 | 
			
		||||
                              "username": value["username"],
 | 
			
		||||
                              "email": value["email"],
 | 
			
		||||
                            });
 | 
			
		||||
                          }).then((value) {
 | 
			
		||||
                            FirebaseFirestore.instance
 | 
			
		||||
                                .collection("users")
 | 
			
		||||
                                .doc(oldDocId)
 | 
			
		||||
                                .delete();
 | 
			
		||||
                          });
 | 
			
		||||
 | 
			
		||||
                          // ignore: use_build_context_synchronously
 | 
			
		||||
                          Navigator.pushReplacement(
 | 
			
		||||
                            context,
 | 
			
		||||
                            MaterialPageRoute(
 | 
			
		||||
                              builder: (context) => const HlavniOkno(),
 | 
			
		||||
                            ),
 | 
			
		||||
                          );
 | 
			
		||||
                        }).onError((e, st) {
 | 
			
		||||
                          if (e
 | 
			
		||||
                              .toString()
 | 
			
		||||
                              .contains("firebase_auth/email-already-in-use")) {
 | 
			
		||||
                            showDialog(
 | 
			
		||||
                              context: context,
 | 
			
		||||
                              builder: (c) => const AlertDialog(
 | 
			
		||||
                                title: Text("Chyba"),
 | 
			
		||||
                                content: Text(
 | 
			
		||||
                                    "Váš účet už existuje, prosím přihlaste se"),
 | 
			
		||||
                              ),
 | 
			
		||||
                            );
 | 
			
		||||
                          } else if (e
 | 
			
		||||
                              .toString()
 | 
			
		||||
                              .contains("firebase_auth/wrong-password")) {
 | 
			
		||||
                            showDialog(
 | 
			
		||||
                              context: context,
 | 
			
		||||
                              builder: (c) => const AlertDialog(
 | 
			
		||||
                                title: Text("Chyba"),
 | 
			
		||||
                                content: Text("Zadáváte špatné heslo!"),
 | 
			
		||||
                              ),
 | 
			
		||||
                            );
 | 
			
		||||
                          }
 | 
			
		||||
 | 
			
		||||
                          return;
 | 
			
		||||
                        });
 | 
			
		||||
                      }
 | 
			
		||||
                    },
 | 
			
		||||
                    style: Vzhled.orangeCudlik,
 | 
			
		||||
                    child: const Text("Pokračovat")),
 | 
			
		||||
            const SizedBox(
 | 
			
		||||
              height: 10,
 | 
			
		||||
            ),
 | 
			
		||||
| 
						 | 
				
			
			@ -339,21 +350,54 @@ class _SignInPageState extends State<SignInPage> {
 | 
			
		|||
            TextButton(
 | 
			
		||||
              onPressed: () {
 | 
			
		||||
                setState(() {
 | 
			
		||||
                  showSignIn = true;
 | 
			
		||||
                  isSignInWidget = true;
 | 
			
		||||
                });
 | 
			
		||||
              },
 | 
			
		||||
              child: const Text("Přihlásit se", style: Vzhled.textBtn),
 | 
			
		||||
            )
 | 
			
		||||
              child: const Text(
 | 
			
		||||
                "Účet mám vytvořen, chci se přihlásit",
 | 
			
		||||
                style: Vzhled.textBtn,
 | 
			
		||||
              ),
 | 
			
		||||
            ),
 | 
			
		||||
          ],
 | 
			
		||||
        ),
 | 
			
		||||
      ),
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  void signIn() {
 | 
			
		||||
  void signIn() async {
 | 
			
		||||
    setState(() {
 | 
			
		||||
      isLoading = true;
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    String email = emailCon.text;
 | 
			
		||||
 | 
			
		||||
    if (!emailCon.text.contains("@")) {
 | 
			
		||||
      var usernameRef = await FirebaseFirestore.instance
 | 
			
		||||
          .collection("users")
 | 
			
		||||
          .where("username", isEqualTo: emailCon.text)
 | 
			
		||||
          .get();
 | 
			
		||||
 | 
			
		||||
      if (usernameRef.docs.isEmpty) {
 | 
			
		||||
        // ignore: use_build_context_synchronously
 | 
			
		||||
        showDialog(
 | 
			
		||||
          context: context,
 | 
			
		||||
          builder: (c) => const AlertDialog(
 | 
			
		||||
            title: Text("Chyba"),
 | 
			
		||||
            content: Text("Účet s tímto jménem neexistuje"),
 | 
			
		||||
          ),
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        setState(() {
 | 
			
		||||
          isLoading = false;
 | 
			
		||||
        });
 | 
			
		||||
        return;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      email = usernameRef.docs.single.data()["email"];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    FirebaseAuth.instance
 | 
			
		||||
        .signInWithEmailAndPassword(
 | 
			
		||||
            email: emailCon.text, password: passwordCon.text)
 | 
			
		||||
        .signInWithEmailAndPassword(email: email, password: passwordCon.text)
 | 
			
		||||
        .then(
 | 
			
		||||
          (value) => Navigator.pushReplacement(
 | 
			
		||||
            context,
 | 
			
		||||
| 
						 | 
				
			
			@ -388,49 +432,11 @@ class _SignInPageState extends State<SignInPage> {
 | 
			
		|||
        debugPrint(e.toString());
 | 
			
		||||
      }
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  void signUp() {
 | 
			
		||||
    FirebaseAuth.instance
 | 
			
		||||
        .createUserWithEmailAndPassword(
 | 
			
		||||
            email: emailCon.text, password: passwordCon.text)
 | 
			
		||||
        .then(
 | 
			
		||||
      (value) async {
 | 
			
		||||
        await FirebaseFirestore.instance
 | 
			
		||||
            .collection("users")
 | 
			
		||||
            .doc(FirebaseAuth.instance.currentUser!.uid)
 | 
			
		||||
            .set({
 | 
			
		||||
          "name": nameCon.text,
 | 
			
		||||
          "email": emailCon.text,
 | 
			
		||||
          "favourite": jazyk,
 | 
			
		||||
        });
 | 
			
		||||
        value.user?.updateDisplayName(nameCon.text);
 | 
			
		||||
 | 
			
		||||
        if (!mounted) return;
 | 
			
		||||
        Navigator.pushReplacement(
 | 
			
		||||
          context,
 | 
			
		||||
          MaterialPageRoute(builder: (c) => const HlavniOkno()),
 | 
			
		||||
        );
 | 
			
		||||
      },
 | 
			
		||||
    ).onError((error, stackTrace) {
 | 
			
		||||
      if (error.toString().contains("firebase_auth/email-already-in-use")) {
 | 
			
		||||
        showDialog(
 | 
			
		||||
          context: context,
 | 
			
		||||
          builder: (c) => const AlertDialog(
 | 
			
		||||
            title: Text("Chyba"),
 | 
			
		||||
            content: Text("E-mail je již zaregistrovaný"),
 | 
			
		||||
          ),
 | 
			
		||||
        );
 | 
			
		||||
      } else {
 | 
			
		||||
        showDialog(
 | 
			
		||||
          context: context,
 | 
			
		||||
          builder: (c) => const AlertDialog(
 | 
			
		||||
            title: Text("Chyba"),
 | 
			
		||||
            content: Text("Nastala neznámá chyba."),
 | 
			
		||||
          ),
 | 
			
		||||
        );
 | 
			
		||||
        debugPrint(error.toString());
 | 
			
		||||
      }
 | 
			
		||||
    });
 | 
			
		||||
    if (mounted) {
 | 
			
		||||
      setState(() {
 | 
			
		||||
        isLoading = false;
 | 
			
		||||
      });
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										633
									
								
								lib/okna/users_page.dart
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										633
									
								
								lib/okna/users_page.dart
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,633 @@
 | 
			
		|||
import 'package:cloud_firestore/cloud_firestore.dart';
 | 
			
		||||
import 'package:denikprogramatora/okna/all_records.dart';
 | 
			
		||||
import 'package:denikprogramatora/okna/signin_page.dart';
 | 
			
		||||
import 'package:denikprogramatora/utils/devicecontainer.dart';
 | 
			
		||||
import 'package:denikprogramatora/utils/loading_widget.dart';
 | 
			
		||||
import 'package:denikprogramatora/utils/my_container.dart';
 | 
			
		||||
import 'package:denikprogramatora/utils/new_record_dialog.dart';
 | 
			
		||||
import 'package:denikprogramatora/utils/really_delete.dart';
 | 
			
		||||
import 'package:denikprogramatora/utils/vzhled.dart';
 | 
			
		||||
import 'package:firebase_auth/firebase_auth.dart';
 | 
			
		||||
import 'package:flutter/material.dart';
 | 
			
		||||
import 'package:responsive_sizer/responsive_sizer.dart';
 | 
			
		||||
import 'package:url_launcher/url_launcher_string.dart';
 | 
			
		||||
 | 
			
		||||
import 'app.dart';
 | 
			
		||||
 | 
			
		||||
class UsersPage extends StatefulWidget {
 | 
			
		||||
  const UsersPage({super.key});
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  State<UsersPage> createState() => _UsersPageState();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class _UsersPageState extends State<UsersPage> {
 | 
			
		||||
  var _loading = true;
 | 
			
		||||
  var name = "error";
 | 
			
		||||
  @override
 | 
			
		||||
  void initState() {
 | 
			
		||||
    super.initState();
 | 
			
		||||
    if (FirebaseAuth.instance.currentUser == null) {
 | 
			
		||||
      Navigator.pushAndRemoveUntil(
 | 
			
		||||
          context,
 | 
			
		||||
          MaterialPageRoute(builder: (c) => const SignInPage()),
 | 
			
		||||
          (route) => false);
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ref.get().then((value) {
 | 
			
		||||
      setState(() {
 | 
			
		||||
        name = FirebaseAuth.instance.currentUser!.displayName ??
 | 
			
		||||
            value[
 | 
			
		||||
                "name"]; // fallback když uživatel je vytvořen skrz firebase admin
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    setState(() {
 | 
			
		||||
      _loading = false;
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  Widget build(BuildContext context) {
 | 
			
		||||
    return Scaffold(
 | 
			
		||||
      body: SingleChildScrollView(
 | 
			
		||||
        child: Center(
 | 
			
		||||
          child: SizedBox(
 | 
			
		||||
            width: 90.w,
 | 
			
		||||
            height: 100.h,
 | 
			
		||||
            child: (_loading)
 | 
			
		||||
                ? const LoadingWidget()
 | 
			
		||||
                : Column(
 | 
			
		||||
                    children: [
 | 
			
		||||
                      DeviceContainer(
 | 
			
		||||
                        mainAxisAlignmentDesktop:
 | 
			
		||||
                            MainAxisAlignment.spaceBetween,
 | 
			
		||||
                        children: [
 | 
			
		||||
                          MyContainer(
 | 
			
		||||
                            width: (Device.screenType == ScreenType.mobile)
 | 
			
		||||
                                ? 90.w
 | 
			
		||||
                                : 35.w,
 | 
			
		||||
                            child: Row(
 | 
			
		||||
                              mainAxisAlignment: MainAxisAlignment.spaceBetween,
 | 
			
		||||
                              children: [
 | 
			
		||||
                                if (name != "error") Text("Ahoj $name"),
 | 
			
		||||
                                TextButton(
 | 
			
		||||
                                  onPressed: () => showAboutDialog(
 | 
			
		||||
                                      context: context,
 | 
			
		||||
                                      applicationName: "Kodelog",
 | 
			
		||||
                                      applicationVersion: "2.0.1",
 | 
			
		||||
                                      applicationLegalese:
 | 
			
		||||
                                          "©️ 2023 Matyáš Caras a Richard Pavlikán,\n vydáno pod licencí AGPLv3",
 | 
			
		||||
                                      children: [
 | 
			
		||||
                                        TextButton(
 | 
			
		||||
                                          child: const Text("Zdrojový kód"),
 | 
			
		||||
                                          onPressed: () => launchUrlString(
 | 
			
		||||
                                              "https://github.com/Royal-Buccaneers/kodelog"),
 | 
			
		||||
                                        )
 | 
			
		||||
                                      ]),
 | 
			
		||||
                                  child: const Text(
 | 
			
		||||
                                    "Licence",
 | 
			
		||||
                                    style: Vzhled.textBtn,
 | 
			
		||||
                                  ),
 | 
			
		||||
                                ),
 | 
			
		||||
                                TextButton(
 | 
			
		||||
                                  onPressed: () async {
 | 
			
		||||
                                    await FirebaseAuth.instance.signOut();
 | 
			
		||||
                                    if (!mounted) return;
 | 
			
		||||
                                    Navigator.pushAndRemoveUntil(
 | 
			
		||||
                                        context,
 | 
			
		||||
                                        MaterialPageRoute(
 | 
			
		||||
                                            builder: (c) => const SignInPage()),
 | 
			
		||||
                                        (route) => false);
 | 
			
		||||
                                  },
 | 
			
		||||
                                  child: const Text(
 | 
			
		||||
                                    "Odhlásit se",
 | 
			
		||||
                                    style: Vzhled.textBtn,
 | 
			
		||||
                                  ),
 | 
			
		||||
                                )
 | 
			
		||||
                              ],
 | 
			
		||||
                            ),
 | 
			
		||||
                          ),
 | 
			
		||||
                          MyContainer(
 | 
			
		||||
                            width: (Device.screenType == ScreenType.mobile)
 | 
			
		||||
                                ? 90.w
 | 
			
		||||
                                : 40.w,
 | 
			
		||||
                            child: DeviceContainer(
 | 
			
		||||
                              mainAxisAlignmentDesktop:
 | 
			
		||||
                                  MainAxisAlignment.spaceBetween,
 | 
			
		||||
                              children: [
 | 
			
		||||
                                TextButton(
 | 
			
		||||
                                  onPressed: () => Navigator.of(context)
 | 
			
		||||
                                      .pushReplacement(MaterialPageRoute(
 | 
			
		||||
                                          builder: (context) =>
 | 
			
		||||
                                              const HlavniOkno())),
 | 
			
		||||
                                  child: const Text(
 | 
			
		||||
                                    "Denní přehled",
 | 
			
		||||
                                    style: TextStyle(color: Vzhled.textColor),
 | 
			
		||||
                                  ),
 | 
			
		||||
                                ),
 | 
			
		||||
                                const SizedBox(height: 5),
 | 
			
		||||
                                TextButton(
 | 
			
		||||
                                  onPressed: () {
 | 
			
		||||
                                    Navigator.pushReplacement(
 | 
			
		||||
                                        context,
 | 
			
		||||
                                        MaterialPageRoute(
 | 
			
		||||
                                            builder: (context) =>
 | 
			
		||||
                                                const AllRecordsPage()));
 | 
			
		||||
                                  },
 | 
			
		||||
                                  child: const Text(
 | 
			
		||||
                                    "Všechny\nzáznamy",
 | 
			
		||||
                                    style: TextStyle(color: Vzhled.textColor),
 | 
			
		||||
                                  ),
 | 
			
		||||
                                ),
 | 
			
		||||
                                const SizedBox(height: 5),
 | 
			
		||||
                                TextButton(
 | 
			
		||||
                                  onPressed: () {},
 | 
			
		||||
                                  child: const Text(
 | 
			
		||||
                                    "Nastavení",
 | 
			
		||||
                                    style: TextStyle(
 | 
			
		||||
                                      color: Vzhled.textColor,
 | 
			
		||||
                                      fontWeight: FontWeight.bold,
 | 
			
		||||
                                    ),
 | 
			
		||||
                                  ),
 | 
			
		||||
                                ),
 | 
			
		||||
                                const SizedBox(height: 5),
 | 
			
		||||
                                OutlinedButton(
 | 
			
		||||
                                  onPressed: () =>
 | 
			
		||||
                                      showCreateItemDialog(context),
 | 
			
		||||
                                  style: Vzhled.orangeCudlik,
 | 
			
		||||
                                  child: const Text(
 | 
			
		||||
                                    "Přidat záznam",
 | 
			
		||||
                                  ),
 | 
			
		||||
                                )
 | 
			
		||||
                              ],
 | 
			
		||||
                            ),
 | 
			
		||||
                          ),
 | 
			
		||||
                        ],
 | 
			
		||||
                      ),
 | 
			
		||||
                      const SizedBox(height: 5),
 | 
			
		||||
                      Expanded(
 | 
			
		||||
                        child: MyContainer(
 | 
			
		||||
                          width: 90.w,
 | 
			
		||||
                          child: SingleChildScrollView(
 | 
			
		||||
                            child: Column(
 | 
			
		||||
                              children: [
 | 
			
		||||
                                Row(
 | 
			
		||||
                                  mainAxisAlignment:
 | 
			
		||||
                                      MainAxisAlignment.spaceEvenly,
 | 
			
		||||
                                  children: [
 | 
			
		||||
                                    const Text("Uživatelé",
 | 
			
		||||
                                        style: Vzhled.mensiAleVelkyText),
 | 
			
		||||
                                    OutlinedButton(
 | 
			
		||||
                                      onPressed: () => showNewUser(),
 | 
			
		||||
                                      style: Vzhled.orangeCudlik,
 | 
			
		||||
                                      child: const Text(
 | 
			
		||||
                                        "Přidat uživatele",
 | 
			
		||||
                                      ),
 | 
			
		||||
                                    ),
 | 
			
		||||
                                  ],
 | 
			
		||||
                                ),
 | 
			
		||||
                                const SizedBox(height: 40),
 | 
			
		||||
                                const Padding(
 | 
			
		||||
                                  padding: EdgeInsets.only(right: 8.0, left: 8),
 | 
			
		||||
                                  child: DeviceContainer(
 | 
			
		||||
                                    mainAxisAlignmentDesktop:
 | 
			
		||||
                                        MainAxisAlignment.spaceBetween,
 | 
			
		||||
                                    mainAxisAlignmentMobile:
 | 
			
		||||
                                        MainAxisAlignment.center,
 | 
			
		||||
                                    children: [
 | 
			
		||||
                                      SizedBox(
 | 
			
		||||
                                        width: 100,
 | 
			
		||||
                                        child: Text(
 | 
			
		||||
                                          "Jméno",
 | 
			
		||||
                                        ),
 | 
			
		||||
                                      ),
 | 
			
		||||
                                      SizedBox(
 | 
			
		||||
                                        width: 150,
 | 
			
		||||
                                        child: Text(
 | 
			
		||||
                                          "Email",
 | 
			
		||||
                                        ),
 | 
			
		||||
                                      ),
 | 
			
		||||
                                      SizedBox(
 | 
			
		||||
                                        width: 150,
 | 
			
		||||
                                        child: Text("Username"),
 | 
			
		||||
                                      ),
 | 
			
		||||
                                      SizedBox(
 | 
			
		||||
                                        width: 50,
 | 
			
		||||
                                        child: Text("Admin"),
 | 
			
		||||
                                      ),
 | 
			
		||||
                                      Text("Nastavení")
 | 
			
		||||
                                    ],
 | 
			
		||||
                                  ),
 | 
			
		||||
                                ),
 | 
			
		||||
                                const SizedBox(height: 10),
 | 
			
		||||
                                SizedBox(
 | 
			
		||||
                                  width: 80.w,
 | 
			
		||||
                                  child: const Divider(color: Vzhled.purple),
 | 
			
		||||
                                ),
 | 
			
		||||
                                const SizedBox(height: 20),
 | 
			
		||||
                                SingleChildScrollView(
 | 
			
		||||
                                  child: StreamBuilder(
 | 
			
		||||
                                      stream: FirebaseFirestore.instance
 | 
			
		||||
                                          .collection("users")
 | 
			
		||||
                                          .snapshots(),
 | 
			
		||||
                                      builder: (context, snapshot) {
 | 
			
		||||
                                        if (snapshot.hasError) {
 | 
			
		||||
                                          return const Text(
 | 
			
		||||
                                              "Nastal error :C...");
 | 
			
		||||
                                        } else if (snapshot.hasData) {
 | 
			
		||||
                                          var docs = snapshot.data!.docs;
 | 
			
		||||
                                          return Column(
 | 
			
		||||
                                            children: List.generate(
 | 
			
		||||
                                              docs.length,
 | 
			
		||||
                                              (index) {
 | 
			
		||||
                                                var data = docs[index].data();
 | 
			
		||||
 | 
			
		||||
                                                return Padding(
 | 
			
		||||
                                                  padding:
 | 
			
		||||
                                                      const EdgeInsets.all(8.0),
 | 
			
		||||
                                                  child: DeviceContainer(
 | 
			
		||||
                                                    mainAxisAlignmentDesktop:
 | 
			
		||||
                                                        MainAxisAlignment
 | 
			
		||||
                                                            .spaceBetween,
 | 
			
		||||
                                                    mainAxisAlignmentMobile:
 | 
			
		||||
                                                        MainAxisAlignment
 | 
			
		||||
                                                            .center,
 | 
			
		||||
                                                    children: [
 | 
			
		||||
                                                      SizedBox(
 | 
			
		||||
                                                        width: 100,
 | 
			
		||||
                                                        child: Text(
 | 
			
		||||
                                                          data["name"],
 | 
			
		||||
                                                          style: const TextStyle(
 | 
			
		||||
                                                              fontWeight:
 | 
			
		||||
                                                                  FontWeight
 | 
			
		||||
                                                                      .bold),
 | 
			
		||||
                                                        ),
 | 
			
		||||
                                                      ),
 | 
			
		||||
                                                      SizedBox(
 | 
			
		||||
                                                        width: 150,
 | 
			
		||||
                                                        child: Text(
 | 
			
		||||
                                                          data["email"],
 | 
			
		||||
                                                        ),
 | 
			
		||||
                                                      ),
 | 
			
		||||
                                                      SizedBox(
 | 
			
		||||
                                                        width: 150,
 | 
			
		||||
                                                        child: Text(
 | 
			
		||||
                                                            data["username"] ??
 | 
			
		||||
                                                                "Prozatím nic"),
 | 
			
		||||
                                                      ),
 | 
			
		||||
                                                      SizedBox(
 | 
			
		||||
                                                        width: 50,
 | 
			
		||||
                                                        child: Icon(
 | 
			
		||||
                                                            data["isAdmin"] ??
 | 
			
		||||
                                                                    false
 | 
			
		||||
                                                                ? Icons.done
 | 
			
		||||
                                                                : Icons
 | 
			
		||||
                                                                    .do_disturb),
 | 
			
		||||
                                                      ),
 | 
			
		||||
                                                      (data["username"] !=
 | 
			
		||||
                                                              "admin")
 | 
			
		||||
                                                          ? PopupMenuButton(
 | 
			
		||||
                                                              onSelected:
 | 
			
		||||
                                                                  (value) {
 | 
			
		||||
                                                                switch (value) {
 | 
			
		||||
                                                                  case 'Změnit práva':
 | 
			
		||||
                                                                    showPrava(
 | 
			
		||||
                                                                        docs[index]
 | 
			
		||||
                                                                            .id,
 | 
			
		||||
                                                                        data[
 | 
			
		||||
                                                                            "isAdmin"]);
 | 
			
		||||
                                                                    break;
 | 
			
		||||
                                                                  case "Upravit username":
 | 
			
		||||
                                                                    showUpravitUsername(
 | 
			
		||||
                                                                        docs[index]
 | 
			
		||||
                                                                            .id,
 | 
			
		||||
                                                                        data[
 | 
			
		||||
                                                                            "username"]);
 | 
			
		||||
                                                                    break;
 | 
			
		||||
                                                                  case 'Odstranit':
 | 
			
		||||
                                                                    showOdstranit(
 | 
			
		||||
                                                                        docs[index]
 | 
			
		||||
                                                                            .id);
 | 
			
		||||
                                                                    break;
 | 
			
		||||
                                                                }
 | 
			
		||||
                                                              },
 | 
			
		||||
                                                              itemBuilder:
 | 
			
		||||
                                                                  (BuildContext
 | 
			
		||||
                                                                      context) {
 | 
			
		||||
                                                                return {
 | 
			
		||||
                                                                  'Změnit práva',
 | 
			
		||||
                                                                  "Upravit username",
 | 
			
		||||
                                                                  'Odstranit'
 | 
			
		||||
                                                                }.map((String
 | 
			
		||||
                                                                    choice) {
 | 
			
		||||
                                                                  return PopupMenuItem<
 | 
			
		||||
                                                                      String>(
 | 
			
		||||
                                                                    value:
 | 
			
		||||
                                                                        choice,
 | 
			
		||||
                                                                    child: Text(
 | 
			
		||||
                                                                        choice),
 | 
			
		||||
                                                                  );
 | 
			
		||||
                                                                }).toList();
 | 
			
		||||
                                                              },
 | 
			
		||||
                                                            )
 | 
			
		||||
                                                          : const SizedBox(
 | 
			
		||||
                                                              width: 40)
 | 
			
		||||
                                                    ],
 | 
			
		||||
                                                  ),
 | 
			
		||||
                                                );
 | 
			
		||||
                                              },
 | 
			
		||||
                                            ),
 | 
			
		||||
                                          );
 | 
			
		||||
                                        }
 | 
			
		||||
                                        return const LoadingWidget();
 | 
			
		||||
                                      }),
 | 
			
		||||
                                ),
 | 
			
		||||
                              ],
 | 
			
		||||
                            ),
 | 
			
		||||
                          ),
 | 
			
		||||
                        ),
 | 
			
		||||
                      ),
 | 
			
		||||
                    ],
 | 
			
		||||
                  ),
 | 
			
		||||
          ),
 | 
			
		||||
        ),
 | 
			
		||||
      ),
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  showNewUser() async {
 | 
			
		||||
    GlobalKey<FormState> key = GlobalKey<FormState>();
 | 
			
		||||
    String jmeno = "";
 | 
			
		||||
    String email = "";
 | 
			
		||||
    String username = "";
 | 
			
		||||
    bool isAdmin = false;
 | 
			
		||||
 | 
			
		||||
    showDialog(
 | 
			
		||||
      context: context,
 | 
			
		||||
      builder: (_) => AlertDialog(
 | 
			
		||||
        title: const Text("Nový uživatel", style: Vzhled.velkyText),
 | 
			
		||||
        scrollable: true,
 | 
			
		||||
        content: StatefulBuilder(
 | 
			
		||||
          builder: (context, setState) {
 | 
			
		||||
            return SizedBox(
 | 
			
		||||
              width: 50.w,
 | 
			
		||||
              child: Form(
 | 
			
		||||
                key: key,
 | 
			
		||||
                child: Column(
 | 
			
		||||
                  children: [
 | 
			
		||||
                    TextFormField(
 | 
			
		||||
                      decoration: Vzhled.inputDecoration("Jméno"),
 | 
			
		||||
                      validator: (value) {
 | 
			
		||||
                        if (value!.trim().isEmpty) {
 | 
			
		||||
                          return "Toto pole je povinné!";
 | 
			
		||||
                        }
 | 
			
		||||
                        return null;
 | 
			
		||||
                      },
 | 
			
		||||
                      onChanged: (value) {
 | 
			
		||||
                        jmeno = value;
 | 
			
		||||
                      },
 | 
			
		||||
                    ),
 | 
			
		||||
                    const SizedBox(height: 10),
 | 
			
		||||
                    TextFormField(
 | 
			
		||||
                      decoration: Vzhled.inputDecoration("Username"),
 | 
			
		||||
                      validator: (value) {
 | 
			
		||||
                        if (value!.trim().isEmpty) {
 | 
			
		||||
                          return "Toto pole je povinné!";
 | 
			
		||||
                        }
 | 
			
		||||
                        return null;
 | 
			
		||||
                      },
 | 
			
		||||
                      onChanged: (value) {
 | 
			
		||||
                        username = value;
 | 
			
		||||
                      },
 | 
			
		||||
                    ),
 | 
			
		||||
                    const SizedBox(height: 10),
 | 
			
		||||
                    TextFormField(
 | 
			
		||||
                      decoration: Vzhled.inputDecoration("Email"),
 | 
			
		||||
                      validator: (value) {
 | 
			
		||||
                        if (value!.trim().isEmpty) {
 | 
			
		||||
                          return "Toto pole je povinné!";
 | 
			
		||||
                        } else if (!RegExp(r'[\w\.]+@[a-z0-9]+\.[a-z]{1,3}')
 | 
			
		||||
                            .hasMatch(value)) {
 | 
			
		||||
                          return "Neplatný e-mail!";
 | 
			
		||||
                        }
 | 
			
		||||
                        return null;
 | 
			
		||||
                      },
 | 
			
		||||
                      onChanged: (value) {
 | 
			
		||||
                        email = value;
 | 
			
		||||
                      },
 | 
			
		||||
                    ),
 | 
			
		||||
                    const SizedBox(height: 10),
 | 
			
		||||
                    DropdownButton(
 | 
			
		||||
                      value: isAdmin,
 | 
			
		||||
                      items: ["Admin", "Uživatel"]
 | 
			
		||||
                          .map((e) => DropdownMenuItem(
 | 
			
		||||
                              value: e == "Admin" ? true : false,
 | 
			
		||||
                              child: Text(e)))
 | 
			
		||||
                          .toList(),
 | 
			
		||||
                      onChanged: (value) {
 | 
			
		||||
                        setState(() {
 | 
			
		||||
                          isAdmin = value!;
 | 
			
		||||
                        });
 | 
			
		||||
                      },
 | 
			
		||||
                    ),
 | 
			
		||||
                    const SizedBox(height: 20),
 | 
			
		||||
                    OutlinedButton(
 | 
			
		||||
                      style: Vzhled.orangeCudlik,
 | 
			
		||||
                      onPressed: () async {
 | 
			
		||||
                        if (key.currentState!.validate()) {
 | 
			
		||||
                          // kontrola ci niekto nevyuziva username
 | 
			
		||||
                          var usernameRef = await FirebaseFirestore.instance
 | 
			
		||||
                              .collection("users")
 | 
			
		||||
                              .where("username", isEqualTo: username)
 | 
			
		||||
                              .get();
 | 
			
		||||
 | 
			
		||||
                          if (usernameRef.docs.isNotEmpty) {
 | 
			
		||||
                            // ignore: use_build_context_synchronously
 | 
			
		||||
                            showDialog(
 | 
			
		||||
                              context: context,
 | 
			
		||||
                              builder: (c) => const AlertDialog(
 | 
			
		||||
                                title: Text("Chyba"),
 | 
			
		||||
                                content: Text(
 | 
			
		||||
                                    "Toto username patří jinému uživateli, prosím napište nové username."),
 | 
			
		||||
                              ),
 | 
			
		||||
                            );
 | 
			
		||||
 | 
			
		||||
                            return;
 | 
			
		||||
                          }
 | 
			
		||||
 | 
			
		||||
                          // kontrola ci niekto nevyuziva email
 | 
			
		||||
                          var emailRef = await FirebaseFirestore.instance
 | 
			
		||||
                              .collection("users")
 | 
			
		||||
                              .where("email", isEqualTo: email)
 | 
			
		||||
                              .get();
 | 
			
		||||
 | 
			
		||||
                          if (emailRef.docs.isNotEmpty) {
 | 
			
		||||
                            // ignore: use_build_context_synchronously
 | 
			
		||||
                            showDialog(
 | 
			
		||||
                              context: context,
 | 
			
		||||
                              builder: (c) => const AlertDialog(
 | 
			
		||||
                                title: Text("Chyba"),
 | 
			
		||||
                                content: Text(
 | 
			
		||||
                                    "Tento email patří jinému uživateli, prosím jiný email."),
 | 
			
		||||
                              ),
 | 
			
		||||
                            );
 | 
			
		||||
 | 
			
		||||
                            return;
 | 
			
		||||
                          }
 | 
			
		||||
 | 
			
		||||
                          FirebaseFirestore.instance.collection("users").add({
 | 
			
		||||
                            "email": email,
 | 
			
		||||
                            "name": jmeno,
 | 
			
		||||
                            "isAdmin": isAdmin,
 | 
			
		||||
                            "favourite": "Dart",
 | 
			
		||||
                            "username": username
 | 
			
		||||
                          }).then((value) {
 | 
			
		||||
                            Navigator.of(context, rootNavigator: true)
 | 
			
		||||
                                .pop("dialog");
 | 
			
		||||
 | 
			
		||||
                            showDialog(
 | 
			
		||||
                              context: context,
 | 
			
		||||
                              builder: (_) => const AlertDialog(
 | 
			
		||||
                                  scrollable: true,
 | 
			
		||||
                                  content: Text("Uživatel vytvořen")),
 | 
			
		||||
                            );
 | 
			
		||||
                          });
 | 
			
		||||
                        }
 | 
			
		||||
                      },
 | 
			
		||||
                      child: const Text("Přidat"),
 | 
			
		||||
                    ),
 | 
			
		||||
                    const SizedBox(height: 20),
 | 
			
		||||
                    const Text(
 | 
			
		||||
                      "Uživatel si při prvním přihlášení vytvoří heslo sám",
 | 
			
		||||
                      textAlign: TextAlign.center,
 | 
			
		||||
                    ),
 | 
			
		||||
                  ],
 | 
			
		||||
                ),
 | 
			
		||||
              ),
 | 
			
		||||
            );
 | 
			
		||||
          },
 | 
			
		||||
        ),
 | 
			
		||||
      ),
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  showUpravitUsername(id, oldUsername) async {
 | 
			
		||||
    GlobalKey<FormState> key = GlobalKey<FormState>();
 | 
			
		||||
    String newUsername = oldUsername;
 | 
			
		||||
 | 
			
		||||
    showDialog(
 | 
			
		||||
      context: context,
 | 
			
		||||
      builder: (_) => AlertDialog(
 | 
			
		||||
        title: const Text("Username", style: Vzhled.velkyText),
 | 
			
		||||
        scrollable: true,
 | 
			
		||||
        content: SizedBox(
 | 
			
		||||
          width: 50.w,
 | 
			
		||||
          child: Form(
 | 
			
		||||
            key: key,
 | 
			
		||||
            child: Column(
 | 
			
		||||
              children: [
 | 
			
		||||
                TextFormField(
 | 
			
		||||
                  initialValue: oldUsername,
 | 
			
		||||
                  decoration: Vzhled.inputDecoration("Nové username"),
 | 
			
		||||
                  validator: (value) {
 | 
			
		||||
                    if (value!.trim().isEmpty) {
 | 
			
		||||
                      return "Toto pole je povinné!";
 | 
			
		||||
                    }
 | 
			
		||||
                    return null;
 | 
			
		||||
                  },
 | 
			
		||||
                  onChanged: (value) {
 | 
			
		||||
                    newUsername = value;
 | 
			
		||||
                  },
 | 
			
		||||
                ),
 | 
			
		||||
                const SizedBox(height: 15),
 | 
			
		||||
                OutlinedButton(
 | 
			
		||||
                    style: Vzhled.orangeCudlik,
 | 
			
		||||
                    onPressed: () async {
 | 
			
		||||
                      if (key.currentState!.validate()) {
 | 
			
		||||
                        // kontrola ci niekto nevyuziva username
 | 
			
		||||
                        var usernameRef = await FirebaseFirestore.instance
 | 
			
		||||
                            .collection("users")
 | 
			
		||||
                            .where("username", isEqualTo: newUsername)
 | 
			
		||||
                            .get();
 | 
			
		||||
 | 
			
		||||
                        if (newUsername.isEmpty) {
 | 
			
		||||
                          // ignore: use_build_context_synchronously
 | 
			
		||||
                          showDialog(
 | 
			
		||||
                            context: context,
 | 
			
		||||
                            builder: (c) => const AlertDialog(
 | 
			
		||||
                              title: Text("Chyba"),
 | 
			
		||||
                              content: Text("Toto pole je povinné!"),
 | 
			
		||||
                            ),
 | 
			
		||||
                          );
 | 
			
		||||
 | 
			
		||||
                          return;
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                        if (usernameRef.docs.isNotEmpty &&
 | 
			
		||||
                            oldUsername != newUsername) {
 | 
			
		||||
                          // ignore: use_build_context_synchronously
 | 
			
		||||
                          showDialog(
 | 
			
		||||
                            context: context,
 | 
			
		||||
                            builder: (c) => const AlertDialog(
 | 
			
		||||
                              title: Text("Chyba"),
 | 
			
		||||
                              content: Text(
 | 
			
		||||
                                  "Toto username patří jinému uživateli, prosím napište nové username."),
 | 
			
		||||
                            ),
 | 
			
		||||
                          );
 | 
			
		||||
 | 
			
		||||
                          return;
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                        FirebaseFirestore.instance
 | 
			
		||||
                            .collection("users")
 | 
			
		||||
                            .doc(id)
 | 
			
		||||
                            .update({"username": newUsername}).then((value) =>
 | 
			
		||||
                                Navigator.of(context, rootNavigator: true)
 | 
			
		||||
                                    .pop("dialog"));
 | 
			
		||||
                      }
 | 
			
		||||
                    },
 | 
			
		||||
                    child: const Text("Uložit"))
 | 
			
		||||
              ],
 | 
			
		||||
            ),
 | 
			
		||||
          ),
 | 
			
		||||
        ),
 | 
			
		||||
      ),
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  showPrava(id, isAdmin) async {
 | 
			
		||||
    showDialog(
 | 
			
		||||
      context: context,
 | 
			
		||||
      builder: (_) => AlertDialog(
 | 
			
		||||
        title: const Text("Práva uživatele", style: Vzhled.velkyText),
 | 
			
		||||
        scrollable: true,
 | 
			
		||||
        content: SizedBox(
 | 
			
		||||
            width: 20.w,
 | 
			
		||||
            child: DropdownButton(
 | 
			
		||||
              value: isAdmin,
 | 
			
		||||
              items: ["Admin", "Uživatel"]
 | 
			
		||||
                  .map((e) => DropdownMenuItem(
 | 
			
		||||
                      value: e == "Admin" ? true : false, child: Text(e)))
 | 
			
		||||
                  .toList(),
 | 
			
		||||
              onChanged: (value) {
 | 
			
		||||
                FirebaseFirestore.instance
 | 
			
		||||
                    .collection("users")
 | 
			
		||||
                    .doc(id)
 | 
			
		||||
                    .update({"isAdmin": value});
 | 
			
		||||
 | 
			
		||||
                Navigator.of(context, rootNavigator: true).pop("dialog");
 | 
			
		||||
              },
 | 
			
		||||
            )),
 | 
			
		||||
      ),
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  showOdstranit(id) async {
 | 
			
		||||
    showReallyDelete(context, () {
 | 
			
		||||
      FirebaseFirestore.instance.collection("users").doc(id).delete();
 | 
			
		||||
      Navigator.of(context, rootNavigator: true).pop("dialog");
 | 
			
		||||
    }, doNavigatorPop: false);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue