diff --git a/refilc/lib/app.dart b/refilc/lib/app.dart index abf6158..849c0b9 100644 --- a/refilc/lib/app.dart +++ b/refilc/lib/app.dart @@ -39,11 +39,11 @@ import 'package:refilc_mobile_ui/screens/settings/settings_route.dart' import 'package:refilc_mobile_ui/screens/settings/settings_screen.dart' as mobile; -// Desktop UI -import 'package:refilc_desktop_ui/screens/navigation/navigation_screen.dart' - as desktop; -import 'package:refilc_desktop_ui/screens/login/login_screen.dart' as desktop; -import 'package:refilc_desktop_ui/screens/login/login_route.dart' as desktop; +// Desktop UI (no more desktop ui) +// import 'package:refilc_desktop_ui/screens/navigation/navigation_screen.dart' +// as desktop; +// import 'package:refilc_desktop_ui/screens/login/login_screen.dart' as desktop; +// import 'package:refilc_desktop_ui/screens/login/login_route.dart' as desktop; // Providers import 'package:refilc/models/settings.dart'; @@ -248,17 +248,18 @@ class App extends StatelessWidget { Route? rootNavigator(RouteSettings route) { if (kIsWeb) { - switch (route.name) { - case "login_back": - return CupertinoPageRoute( - builder: (context) => const desktop.LoginScreen(back: true)); - case "login": - return _rootRoute(const desktop.LoginScreen()); - case "navigation": - return _rootRoute(const desktop.NavigationScreen()); - case "login_to_navigation": - return desktop.loginRoute(const desktop.NavigationScreen()); - } + return null; + // switch (route.name) { + // case "login_back": + // return CupertinoPageRoute( + // builder: (context) => const desktop.LoginScreen(back: true)); + // case "login": + // return _rootRoute(const desktop.LoginScreen()); + // case "navigation": + // return _rootRoute(const desktop.NavigationScreen()); + // case "login_to_navigation": + // return desktop.loginRoute(const desktop.NavigationScreen()); + // } } else if (Platform.isAndroid || Platform.isIOS) { switch (route.name) { case "login_back": @@ -274,17 +275,18 @@ class App extends StatelessWidget { return mobile.settingsRoute(const mobile.SettingsScreen()); } } else if (Platform.isWindows || Platform.isMacOS || Platform.isLinux) { - switch (route.name) { - case "login_back": - return CupertinoPageRoute( - builder: (context) => const desktop.LoginScreen(back: true)); - case "login": - return _rootRoute(const desktop.LoginScreen()); - case "navigation": - return _rootRoute(const desktop.NavigationScreen()); - case "login_to_navigation": - return desktop.loginRoute(const desktop.NavigationScreen()); - } + return null; + // switch (route.name) { + // case "login_back": + // return CupertinoPageRoute( + // builder: (context) => const desktop.LoginScreen(back: true)); + // case "login": + // return _rootRoute(const desktop.LoginScreen()); + // case "navigation": + // return _rootRoute(const desktop.NavigationScreen()); + // case "login_to_navigation": + // return desktop.loginRoute(const desktop.NavigationScreen()); + // } } return null; } diff --git a/refilc/lib/ui/filter/widgets/grades.dart b/refilc/lib/ui/filter/widgets/grades.dart index dbb54f7..447f14e 100644 --- a/refilc/lib/ui/filter/widgets/grades.dart +++ b/refilc/lib/ui/filter/widgets/grades.dart @@ -1,12 +1,9 @@ import 'package:refilc/ui/date_widget.dart'; -import 'package:refilc/utils/platform.dart'; import 'package:refilc_kreta_api/models/grade.dart'; import 'package:refilc_mobile_ui/common/widgets/grade/grade_viewable.dart' as mobile; import 'package:refilc_mobile_ui/common/widgets/grade/new_grades.dart' as mobile; -import 'package:refilc_desktop_ui/common/widgets/grade/grade_viewable.dart' - as desktop; List getWidgets( List providerGrades, DateTime? lastSeenDate) { @@ -19,9 +16,7 @@ List getWidgets( items.add(DateWidget( key: grade.id, date: grade.date, - widget: PlatformUtils.isMobile - ? mobile.GradeViewable(grade) - : desktop.GradeViewable(grade), + widget: mobile.GradeViewable(grade), )); } } diff --git a/refilc/pubspec.yaml b/refilc/pubspec.yaml index 0797927..092c29a 100644 --- a/refilc/pubspec.yaml +++ b/refilc/pubspec.yaml @@ -75,9 +75,7 @@ dependencies: screenshot: ^3.0.0 flutter_staggered_grid_view: ^0.7.0 sqflite_common_ffi_web: ^0.4.0 - image_crop: - git: - url: https://github.com/kimaah/image_crop.git + image_crop_plus: ^1.0.0 googleapis: ^13.2.0 google_sign_in: ^6.2.1 extension_google_sign_in_as_googleapis_auth: ^2.0.12 diff --git a/refilc_desktop_ui/LICENSE b/refilc_desktop_ui/LICENSE deleted file mode 100644 index f288702..0000000 --- a/refilc_desktop_ui/LICENSE +++ /dev/null @@ -1,674 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The GNU General Public License is a free, copyleft license for -software and other kinds of works. - - The licenses for most software and other practical works are designed -to take away your freedom to share and change the works. By contrast, -the GNU General Public License is intended to guarantee your freedom to -share and change all versions of a program--to make sure it remains free -software for all its users. We, the Free Software Foundation, use the -GNU General Public License for most of our software; it applies also to -any other work released this way by its authors. You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -them if you wish), that you receive source code or can get it if you -want it, that you can change the software or use pieces of it in new -free programs, and that you know you can do these things. - - To protect your rights, we need to prevent others from denying you -these rights or asking you to surrender the rights. Therefore, you have -certain responsibilities if you distribute copies of the software, or if -you modify it: responsibilities to respect the freedom of others. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must pass on to the recipients the same -freedoms that you received. You must make sure that they, too, receive -or can get the source code. And you must show them these terms so they -know their rights. - - Developers that use the GNU GPL protect your rights with two steps: -(1) assert copyright on the software, and (2) offer you this License -giving you legal permission to copy, distribute and/or modify it. - - For the developers' and authors' protection, the GPL clearly explains -that there is no warranty for this free software. For both users' and -authors' sake, the GPL requires that modified versions be marked as -changed, so that their problems will not be attributed erroneously to -authors of previous versions. - - Some devices are designed to deny users access to install or run -modified versions of the software inside them, although the manufacturer -can do so. This is fundamentally incompatible with the aim of -protecting users' freedom to change the software. The systematic -pattern of such abuse occurs in the area of products for individuals to -use, which is precisely where it is most unacceptable. Therefore, we -have designed this version of the GPL to prohibit the practice for those -products. If such problems arise substantially in other domains, we -stand ready to extend this provision to those domains in future versions -of the GPL, as needed to protect the freedom of users. - - Finally, every program is threatened constantly by software patents. -States should not allow patents to restrict development and use of -software on general-purpose computers, but in those that do, we wish to -avoid the special danger that patents applied to a free program could -make it effectively proprietary. To prevent this, the GPL assures that -patents cannot be used to render the program non-free. - - The precise terms and conditions for copying, distribution and -modification follow. - - TERMS AND CONDITIONS - - 0. Definitions. - - "This License" refers to version 3 of the GNU General Public License. - - "Copyright" also means copyright-like laws that apply to other kinds of -works, such as semiconductor masks. - - "The Program" refers to any copyrightable work licensed under this -License. Each licensee is addressed as "you". "Licensees" and -"recipients" may be individuals or organizations. - - To "modify" a work means to copy from or adapt all or part of the work -in a fashion requiring copyright permission, other than the making of an -exact copy. The resulting work is called a "modified version" of the -earlier work or a work "based on" the earlier work. - - A "covered work" means either the unmodified Program or a work based -on the Program. - - To "propagate" a work means to do anything with it that, without -permission, would make you directly or secondarily liable for -infringement under applicable copyright law, except executing it on a -computer or modifying a private copy. Propagation includes copying, -distribution (with or without modification), making available to the -public, and in some countries other activities as well. - - To "convey" a work means any kind of propagation that enables other -parties to make or receive copies. Mere interaction with a user through -a computer network, with no transfer of a copy, is not conveying. - - An interactive user interface displays "Appropriate Legal Notices" -to the extent that it includes a convenient and prominently visible -feature that (1) displays an appropriate copyright notice, and (2) -tells the user that there is no warranty for the work (except to the -extent that warranties are provided), that licensees may convey the -work under this License, and how to view a copy of this License. If -the interface presents a list of user commands or options, such as a -menu, a prominent item in the list meets this criterion. - - 1. Source Code. - - The "source code" for a work means the preferred form of the work -for making modifications to it. "Object code" means any non-source -form of a work. - - A "Standard Interface" means an interface that either is an official -standard defined by a recognized standards body, or, in the case of -interfaces specified for a particular programming language, one that -is widely used among developers working in that language. - - The "System Libraries" of an executable work include anything, other -than the work as a whole, that (a) is included in the normal form of -packaging a Major Component, but which is not part of that Major -Component, and (b) serves only to enable use of the work with that -Major Component, or to implement a Standard Interface for which an -implementation is available to the public in source code form. A -"Major Component", in this context, means a major essential component -(kernel, window system, and so on) of the specific operating system -(if any) on which the executable work runs, or a compiler used to -produce the work, or an object code interpreter used to run it. - - The "Corresponding Source" for a work in object code form means all -the source code needed to generate, install, and (for an executable -work) run the object code and to modify the work, including scripts to -control those activities. However, it does not include the work's -System Libraries, or general-purpose tools or generally available free -programs which are used unmodified in performing those activities but -which are not part of the work. For example, Corresponding Source -includes interface definition files associated with source files for -the work, and the source code for shared libraries and dynamically -linked subprograms that the work is specifically designed to require, -such as by intimate data communication or control flow between those -subprograms and other parts of the work. - - The Corresponding Source need not include anything that users -can regenerate automatically from other parts of the Corresponding -Source. - - The Corresponding Source for a work in source code form is that -same work. - - 2. Basic Permissions. - - All rights granted under this License are granted for the term of -copyright on the Program, and are irrevocable provided the stated -conditions are met. This License explicitly affirms your unlimited -permission to run the unmodified Program. The output from running a -covered work is covered by this License only if the output, given its -content, constitutes a covered work. This License acknowledges your -rights of fair use or other equivalent, as provided by copyright law. - - You may make, run and propagate covered works that you do not -convey, without conditions so long as your license otherwise remains -in force. You may convey covered works to others for the sole purpose -of having them make modifications exclusively for you, or provide you -with facilities for running those works, provided that you comply with -the terms of this License in conveying all material for which you do -not control copyright. Those thus making or running the covered works -for you must do so exclusively on your behalf, under your direction -and control, on terms that prohibit them from making any copies of -your copyrighted material outside their relationship with you. - - Conveying under any other circumstances is permitted solely under -the conditions stated below. Sublicensing is not allowed; section 10 -makes it unnecessary. - - 3. Protecting Users' Legal Rights From Anti-Circumvention Law. - - No covered work shall be deemed part of an effective technological -measure under any applicable law fulfilling obligations under article -11 of the WIPO copyright treaty adopted on 20 December 1996, or -similar laws prohibiting or restricting circumvention of such -measures. - - When you convey a covered work, you waive any legal power to forbid -circumvention of technological measures to the extent such circumvention -is effected by exercising rights under this License with respect to -the covered work, and you disclaim any intention to limit operation or -modification of the work as a means of enforcing, against the work's -users, your or third parties' legal rights to forbid circumvention of -technological measures. - - 4. Conveying Verbatim Copies. - - You may convey verbatim copies of the Program's source code as you -receive it, in any medium, provided that you conspicuously and -appropriately publish on each copy an appropriate copyright notice; -keep intact all notices stating that this License and any -non-permissive terms added in accord with section 7 apply to the code; -keep intact all notices of the absence of any warranty; and give all -recipients a copy of this License along with the Program. - - You may charge any price or no price for each copy that you convey, -and you may offer support or warranty protection for a fee. - - 5. Conveying Modified Source Versions. - - You may convey a work based on the Program, or the modifications to -produce it from the Program, in the form of source code under the -terms of section 4, provided that you also meet all of these conditions: - - a) The work must carry prominent notices stating that you modified - it, and giving a relevant date. - - b) The work must carry prominent notices stating that it is - released under this License and any conditions added under section - 7. This requirement modifies the requirement in section 4 to - "keep intact all notices". - - c) You must license the entire work, as a whole, under this - License to anyone who comes into possession of a copy. This - License will therefore apply, along with any applicable section 7 - additional terms, to the whole of the work, and all its parts, - regardless of how they are packaged. This License gives no - permission to license the work in any other way, but it does not - invalidate such permission if you have separately received it. - - d) If the work has interactive user interfaces, each must display - Appropriate Legal Notices; however, if the Program has interactive - interfaces that do not display Appropriate Legal Notices, your - work need not make them do so. - - A compilation of a covered work with other separate and independent -works, which are not by their nature extensions of the covered work, -and which are not combined with it such as to form a larger program, -in or on a volume of a storage or distribution medium, is called an -"aggregate" if the compilation and its resulting copyright are not -used to limit the access or legal rights of the compilation's users -beyond what the individual works permit. Inclusion of a covered work -in an aggregate does not cause this License to apply to the other -parts of the aggregate. - - 6. Conveying Non-Source Forms. - - You may convey a covered work in object code form under the terms -of sections 4 and 5, provided that you also convey the -machine-readable Corresponding Source under the terms of this License, -in one of these ways: - - a) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by the - Corresponding Source fixed on a durable physical medium - customarily used for software interchange. - - b) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by a - written offer, valid for at least three years and valid for as - long as you offer spare parts or customer support for that product - model, to give anyone who possesses the object code either (1) a - copy of the Corresponding Source for all the software in the - product that is covered by this License, on a durable physical - medium customarily used for software interchange, for a price no - more than your reasonable cost of physically performing this - conveying of source, or (2) access to copy the - Corresponding Source from a network server at no charge. - - c) Convey individual copies of the object code with a copy of the - written offer to provide the Corresponding Source. This - alternative is allowed only occasionally and noncommercially, and - only if you received the object code with such an offer, in accord - with subsection 6b. - - d) Convey the object code by offering access from a designated - place (gratis or for a charge), and offer equivalent access to the - Corresponding Source in the same way through the same place at no - further charge. You need not require recipients to copy the - Corresponding Source along with the object code. If the place to - copy the object code is a network server, the Corresponding Source - may be on a different server (operated by you or a third party) - that supports equivalent copying facilities, provided you maintain - clear directions next to the object code saying where to find the - Corresponding Source. Regardless of what server hosts the - Corresponding Source, you remain obligated to ensure that it is - available for as long as needed to satisfy these requirements. - - e) Convey the object code using peer-to-peer transmission, provided - you inform other peers where the object code and Corresponding - Source of the work are being offered to the general public at no - charge under subsection 6d. - - A separable portion of the object code, whose source code is excluded -from the Corresponding Source as a System Library, need not be -included in conveying the object code work. - - A "User Product" is either (1) a "consumer product", which means any -tangible personal property which is normally used for personal, family, -or household purposes, or (2) anything designed or sold for incorporation -into a dwelling. In determining whether a product is a consumer product, -doubtful cases shall be resolved in favor of coverage. For a particular -product received by a particular user, "normally used" refers to a -typical or common use of that class of product, regardless of the status -of the particular user or of the way in which the particular user -actually uses, or expects or is expected to use, the product. A product -is a consumer product regardless of whether the product has substantial -commercial, industrial or non-consumer uses, unless such uses represent -the only significant mode of use of the product. - - "Installation Information" for a User Product means any methods, -procedures, authorization keys, or other information required to install -and execute modified versions of a covered work in that User Product from -a modified version of its Corresponding Source. The information must -suffice to ensure that the continued functioning of the modified object -code is in no case prevented or interfered with solely because -modification has been made. - - If you convey an object code work under this section in, or with, or -specifically for use in, a User Product, and the conveying occurs as -part of a transaction in which the right of possession and use of the -User Product is transferred to the recipient in perpetuity or for a -fixed term (regardless of how the transaction is characterized), the -Corresponding Source conveyed under this section must be accompanied -by the Installation Information. But this requirement does not apply -if neither you nor any third party retains the ability to install -modified object code on the User Product (for example, the work has -been installed in ROM). - - The requirement to provide Installation Information does not include a -requirement to continue to provide support service, warranty, or updates -for a work that has been modified or installed by the recipient, or for -the User Product in which it has been modified or installed. Access to a -network may be denied when the modification itself materially and -adversely affects the operation of the network or violates the rules and -protocols for communication across the network. - - Corresponding Source conveyed, and Installation Information provided, -in accord with this section must be in a format that is publicly -documented (and with an implementation available to the public in -source code form), and must require no special password or key for -unpacking, reading or copying. - - 7. Additional Terms. - - "Additional permissions" are terms that supplement the terms of this -License by making exceptions from one or more of its conditions. -Additional permissions that are applicable to the entire Program shall -be treated as though they were included in this License, to the extent -that they are valid under applicable law. If additional permissions -apply only to part of the Program, that part may be used separately -under those permissions, but the entire Program remains governed by -this License without regard to the additional permissions. - - When you convey a copy of a covered work, you may at your option -remove any additional permissions from that copy, or from any part of -it. (Additional permissions may be written to require their own -removal in certain cases when you modify the work.) You may place -additional permissions on material, added by you to a covered work, -for which you have or can give appropriate copyright permission. - - Notwithstanding any other provision of this License, for material you -add to a covered work, you may (if authorized by the copyright holders of -that material) supplement the terms of this License with terms: - - a) Disclaiming warranty or limiting liability differently from the - terms of sections 15 and 16 of this License; or - - b) Requiring preservation of specified reasonable legal notices or - author attributions in that material or in the Appropriate Legal - Notices displayed by works containing it; or - - c) Prohibiting misrepresentation of the origin of that material, or - requiring that modified versions of such material be marked in - reasonable ways as different from the original version; or - - d) Limiting the use for publicity purposes of names of licensors or - authors of the material; or - - e) Declining to grant rights under trademark law for use of some - trade names, trademarks, or service marks; or - - f) Requiring indemnification of licensors and authors of that - material by anyone who conveys the material (or modified versions of - it) with contractual assumptions of liability to the recipient, for - any liability that these contractual assumptions directly impose on - those licensors and authors. - - All other non-permissive additional terms are considered "further -restrictions" within the meaning of section 10. If the Program as you -received it, or any part of it, contains a notice stating that it is -governed by this License along with a term that is a further -restriction, you may remove that term. If a license document contains -a further restriction but permits relicensing or conveying under this -License, you may add to a covered work material governed by the terms -of that license document, provided that the further restriction does -not survive such relicensing or conveying. - - If you add terms to a covered work in accord with this section, you -must place, in the relevant source files, a statement of the -additional terms that apply to those files, or a notice indicating -where to find the applicable terms. - - Additional terms, permissive or non-permissive, may be stated in the -form of a separately written license, or stated as exceptions; -the above requirements apply either way. - - 8. Termination. - - You may not propagate or modify a covered work except as expressly -provided under this License. Any attempt otherwise to propagate or -modify it is void, and will automatically terminate your rights under -this License (including any patent licenses granted under the third -paragraph of section 11). - - However, if you cease all violation of this License, then your -license from a particular copyright holder is reinstated (a) -provisionally, unless and until the copyright holder explicitly and -finally terminates your license, and (b) permanently, if the copyright -holder fails to notify you of the violation by some reasonable means -prior to 60 days after the cessation. - - Moreover, your license from a particular copyright holder is -reinstated permanently if the copyright holder notifies you of the -violation by some reasonable means, this is the first time you have -received notice of violation of this License (for any work) from that -copyright holder, and you cure the violation prior to 30 days after -your receipt of the notice. - - Termination of your rights under this section does not terminate the -licenses of parties who have received copies or rights from you under -this License. If your rights have been terminated and not permanently -reinstated, you do not qualify to receive new licenses for the same -material under section 10. - - 9. Acceptance Not Required for Having Copies. - - You are not required to accept this License in order to receive or -run a copy of the Program. Ancillary propagation of a covered work -occurring solely as a consequence of using peer-to-peer transmission -to receive a copy likewise does not require acceptance. However, -nothing other than this License grants you permission to propagate or -modify any covered work. These actions infringe copyright if you do -not accept this License. Therefore, by modifying or propagating a -covered work, you indicate your acceptance of this License to do so. - - 10. Automatic Licensing of Downstream Recipients. - - Each time you convey a covered work, the recipient automatically -receives a license from the original licensors, to run, modify and -propagate that work, subject to this License. You are not responsible -for enforcing compliance by third parties with this License. - - An "entity transaction" is a transaction transferring control of an -organization, or substantially all assets of one, or subdividing an -organization, or merging organizations. If propagation of a covered -work results from an entity transaction, each party to that -transaction who receives a copy of the work also receives whatever -licenses to the work the party's predecessor in interest had or could -give under the previous paragraph, plus a right to possession of the -Corresponding Source of the work from the predecessor in interest, if -the predecessor has it or can get it with reasonable efforts. - - You may not impose any further restrictions on the exercise of the -rights granted or affirmed under this License. For example, you may -not impose a license fee, royalty, or other charge for exercise of -rights granted under this License, and you may not initiate litigation -(including a cross-claim or counterclaim in a lawsuit) alleging that -any patent claim is infringed by making, using, selling, offering for -sale, or importing the Program or any portion of it. - - 11. Patents. - - A "contributor" is a copyright holder who authorizes use under this -License of the Program or a work on which the Program is based. The -work thus licensed is called the contributor's "contributor version". - - A contributor's "essential patent claims" are all patent claims -owned or controlled by the contributor, whether already acquired or -hereafter acquired, that would be infringed by some manner, permitted -by this License, of making, using, or selling its contributor version, -but do not include claims that would be infringed only as a -consequence of further modification of the contributor version. For -purposes of this definition, "control" includes the right to grant -patent sublicenses in a manner consistent with the requirements of -this License. - - Each contributor grants you a non-exclusive, worldwide, royalty-free -patent license under the contributor's essential patent claims, to -make, use, sell, offer for sale, import and otherwise run, modify and -propagate the contents of its contributor version. - - In the following three paragraphs, a "patent license" is any express -agreement or commitment, however denominated, not to enforce a patent -(such as an express permission to practice a patent or covenant not to -sue for patent infringement). To "grant" such a patent license to a -party means to make such an agreement or commitment not to enforce a -patent against the party. - - If you convey a covered work, knowingly relying on a patent license, -and the Corresponding Source of the work is not available for anyone -to copy, free of charge and under the terms of this License, through a -publicly available network server or other readily accessible means, -then you must either (1) cause the Corresponding Source to be so -available, or (2) arrange to deprive yourself of the benefit of the -patent license for this particular work, or (3) arrange, in a manner -consistent with the requirements of this License, to extend the patent -license to downstream recipients. "Knowingly relying" means you have -actual knowledge that, but for the patent license, your conveying the -covered work in a country, or your recipient's use of the covered work -in a country, would infringe one or more identifiable patents in that -country that you have reason to believe are valid. - - If, pursuant to or in connection with a single transaction or -arrangement, you convey, or propagate by procuring conveyance of, a -covered work, and grant a patent license to some of the parties -receiving the covered work authorizing them to use, propagate, modify -or convey a specific copy of the covered work, then the patent license -you grant is automatically extended to all recipients of the covered -work and works based on it. - - A patent license is "discriminatory" if it does not include within -the scope of its coverage, prohibits the exercise of, or is -conditioned on the non-exercise of one or more of the rights that are -specifically granted under this License. You may not convey a covered -work if you are a party to an arrangement with a third party that is -in the business of distributing software, under which you make payment -to the third party based on the extent of your activity of conveying -the work, and under which the third party grants, to any of the -parties who would receive the covered work from you, a discriminatory -patent license (a) in connection with copies of the covered work -conveyed by you (or copies made from those copies), or (b) primarily -for and in connection with specific products or compilations that -contain the covered work, unless you entered into that arrangement, -or that patent license was granted, prior to 28 March 2007. - - Nothing in this License shall be construed as excluding or limiting -any implied license or other defenses to infringement that may -otherwise be available to you under applicable patent law. - - 12. No Surrender of Others' Freedom. - - If conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot convey a -covered work so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you may -not convey it at all. For example, if you agree to terms that obligate you -to collect a royalty for further conveying from those to whom you convey -the Program, the only way you could satisfy both those terms and this -License would be to refrain entirely from conveying the Program. - - 13. Use with the GNU Affero General Public License. - - Notwithstanding any other provision of this License, you have -permission to link or combine any covered work with a work licensed -under version 3 of the GNU Affero General Public License into a single -combined work, and to convey the resulting work. The terms of this -License will continue to apply to the part which is the covered work, -but the special requirements of the GNU Affero General Public License, -section 13, concerning interaction through a network will apply to the -combination as such. - - 14. Revised Versions of this License. - - The Free Software Foundation may publish revised and/or new versions of -the GNU General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - - Each version is given a distinguishing version number. If the -Program specifies that a certain numbered version of the GNU General -Public License "or any later version" applies to it, you have the -option of following the terms and conditions either of that numbered -version or of any later version published by the Free Software -Foundation. If the Program does not specify a version number of the -GNU General Public License, you may choose any version ever published -by the Free Software Foundation. - - If the Program specifies that a proxy can decide which future -versions of the GNU General Public License can be used, that proxy's -public statement of acceptance of a version permanently authorizes you -to choose that version for the Program. - - Later license versions may give you additional or different -permissions. However, no additional obligations are imposed on any -author or copyright holder as a result of your choosing to follow a -later version. - - 15. Disclaimer of Warranty. - - THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY -APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT -HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY -OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, -THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM -IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF -ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. Limitation of Liability. - - IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS -THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY -GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE -USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF -DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD -PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), -EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF -SUCH DAMAGES. - - 17. Interpretation of Sections 15 and 16. - - If the disclaimer of warranty and limitation of liability provided -above cannot be given local legal effect according to their terms, -reviewing courts shall apply local law that most closely approximates -an absolute waiver of all civil liability in connection with the -Program, unless a warranty or assumption of liability accompanies a -copy of the Program in return for a fee. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -state the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - -Also add information on how to contact you by electronic and paper mail. - - If the program does terminal interaction, make it output a short -notice like this when it starts in an interactive mode: - - Copyright (C) - This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, your program's commands -might be different; for a GUI interface, you would use an "about box". - - You should also get your employer (if you work as a programmer) or school, -if any, to sign a "copyright disclaimer" for the program, if necessary. -For more information on this, and how to apply and follow the GNU GPL, see -. - - The GNU General Public License does not permit incorporating your program -into proprietary programs. If your program is a subroutine library, you -may consider it more useful to permit linking proprietary applications with -the library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. But first, please read -. diff --git a/refilc_desktop_ui/README.md b/refilc_desktop_ui/README.md deleted file mode 100644 index e69de29..0000000 diff --git a/refilc_desktop_ui/analysis_options.yaml b/refilc_desktop_ui/analysis_options.yaml deleted file mode 100644 index fd16f92..0000000 --- a/refilc_desktop_ui/analysis_options.yaml +++ /dev/null @@ -1,28 +0,0 @@ -# This file configures the analyzer, which statically analyzes Dart code to -# check for errors, warnings, and lints. -# -# The issues identified by the analyzer are surfaced in the UI of Dart-enabled -# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be -# invoked from the command line by running `flutter analyze`. - -# The following line activates a set of recommended lints for Flutter apps, -# packages, and plugins designed to encourage good coding practices. -include: package:flutter_lints/flutter.yaml - -linter: - # The lint rules applied to this project can be customized in the - # section below to disable rules from the `package:flutter_lints/flutter.yaml` - # included above or to enable additional rules. A list of all available lints - # and their documentation is published at - # https://dart-lang.github.io/linter/lints/index.html. - # - # Instead of disabling a lint rule for the entire project in the - # section below, it can also be suppressed for a single line of code - # or a specific dart file by using the `// ignore: name_of_lint` and - # `// ignore_for_file: name_of_lint` syntax on the line or in the file - # producing the lint. - rules: - # avoid_print: false # Uncomment to disable the `avoid_print` rule - # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule -# Additional information about this file can be found at -# https://dart.dev/guides/language/analysis-options diff --git a/refilc_desktop_ui/lib/common/filter_bar.dart b/refilc_desktop_ui/lib/common/filter_bar.dart deleted file mode 100644 index 790f9e9..0000000 --- a/refilc_desktop_ui/lib/common/filter_bar.dart +++ /dev/null @@ -1,91 +0,0 @@ -import 'package:refilc/theme/colors/colors.dart'; -import 'package:flutter/material.dart'; - -class FilterBar extends StatelessWidget implements PreferredSizeWidget { - const FilterBar({ - super.key, - required this.items, - required this.controller, - this.onTap, - this.padding = const EdgeInsets.symmetric(horizontal: 24.0), - this.disableFading = false, - this.scrollable = true, - }) : assert(items.length == controller.length); - - final List items; - final TabController controller; - final EdgeInsetsGeometry padding; - final Function(int)? onTap; - @override - final Size preferredSize = const Size.fromHeight(42.0); - final bool disableFading; - final bool scrollable; - - @override - Widget build(BuildContext context) { - final tabbar = TabBar( - controller: controller, - isScrollable: scrollable, - physics: const BouncingScrollPhysics(), - // Label - labelStyle: Theme.of(context).textTheme.titleMedium!.copyWith( - fontWeight: FontWeight.w600, - fontSize: 15.0, - ), - labelPadding: const EdgeInsets.symmetric(horizontal: 12, vertical: 3), - labelColor: Theme.of(context).colorScheme.secondary, - unselectedLabelColor: AppColors.of(context).text.withOpacity(0.65), - // Indicator - indicatorPadding: const EdgeInsets.symmetric(vertical: 8), - indicator: BoxDecoration( - color: Theme.of(context).colorScheme.secondary.withOpacity(0.25), - borderRadius: BorderRadius.circular(45.0), - ), - overlayColor: WidgetStateProperty.all(const Color(0x00000000)), - // Tabs - padding: EdgeInsets.zero, - tabs: items, - onTap: onTap, - ); - - return Container( - width: MediaQuery.of(context).size.width, - height: 48.0, - padding: padding, - child: disableFading - ? tabbar - : AnimatedBuilder( - animation: controller.animation!, - builder: (ctx, child) { - // avoid fading over selected tab - return ShaderMask( - shaderCallback: (Rect bounds) { - final Color bg = - Theme.of(context).scaffoldBackgroundColor; - final double index = controller.animation!.value; - return LinearGradient( - begin: Alignment.topLeft, - end: Alignment.bottomRight, - colors: [ - index < 0.2 ? Colors.transparent : bg, - Colors.transparent, - Colors.transparent, - index > controller.length - 1.2 - ? Colors.transparent - : bg - ], - stops: const [ - 0, - 0.1, - 0.9, - 1 - ]).createShader(bounds); - }, - blendMode: BlendMode.dstOut, - child: child); - }, - child: tabbar, - ), - ); - } -} diff --git a/refilc_desktop_ui/lib/common/panel_button.dart b/refilc_desktop_ui/lib/common/panel_button.dart deleted file mode 100644 index 4f68917..0000000 --- a/refilc_desktop_ui/lib/common/panel_button.dart +++ /dev/null @@ -1,72 +0,0 @@ -import 'package:refilc/theme/colors/colors.dart'; -import 'package:flutter/material.dart'; - -class PanelButton extends StatelessWidget { - const PanelButton({ - super.key, - this.onPressed, - this.padding = const EdgeInsets.symmetric(horizontal: 14.0), - this.leading, - this.title, - this.trailing, - this.trailingDivider = false, - }); - - final void Function()? onPressed; - final EdgeInsetsGeometry padding; - final Widget? leading; - final Widget? title; - final Widget? trailing; - final bool trailingDivider; - - @override - Widget build(BuildContext context) { - return Padding( - padding: const EdgeInsets.symmetric(horizontal: 12.0), - child: RawMaterialButton( - onPressed: onPressed, - padding: padding, - shape: - RoundedRectangleBorder(borderRadius: BorderRadius.circular(12.0)), - child: ListTile( - leading: leading != null - ? Theme( - data: Theme.of(context).copyWith( - iconTheme: IconThemeData( - color: Theme.of(context).colorScheme.secondary)), - child: leading!, - ) - : null, - trailing: trailingDivider - ? Row( - mainAxisSize: MainAxisSize.min, - children: [ - Container( - margin: const EdgeInsets.only(right: 6.0), - width: 2.0, - height: 32.0, - decoration: BoxDecoration( - color: AppColors.of(context).text.withOpacity(.15), - borderRadius: BorderRadius.circular(45.0), - ), - ), - if (trailing != null) trailing!, - ], - ) - : trailing, - title: title != null - ? DefaultTextStyle( - style: Theme.of(context) - .textTheme - .titleMedium! - .copyWith(fontWeight: FontWeight.w600, fontSize: 14.0), - child: title!, - ) - : null, - contentPadding: EdgeInsets.zero, - visualDensity: VisualDensity.compact, - ), - ), - ); - } -} diff --git a/refilc_desktop_ui/lib/common/profile_image.dart b/refilc_desktop_ui/lib/common/profile_image.dart deleted file mode 100644 index 15c3215..0000000 --- a/refilc_desktop_ui/lib/common/profile_image.dart +++ /dev/null @@ -1,78 +0,0 @@ -import 'package:refilc/models/user.dart'; -import 'package:refilc/utils/color.dart'; -import 'package:flutter/material.dart'; -import 'package:refilc/theme/colors/colors.dart'; - -class ProfileImage extends StatelessWidget { - const ProfileImage({ - super.key, - this.name, - this.radius = 20.0, - this.role = Role.student, - this.backgroundColor, - }); - - final String? name; - final double radius; - final Role? role; - final Color? backgroundColor; - - @override - Widget build(BuildContext context) { - Color color = ColorUtils.foregroundColor( - backgroundColor ?? Theme.of(context).scaffoldBackgroundColor); - Color roleColor; - - if (Theme.of(context).brightness == Brightness.light) { - roleColor = const Color(0xFF444444); - } else { - roleColor = const Color(0xFF555555); - } - - return Stack( - alignment: Alignment.center, - children: [ - Material( - clipBehavior: Clip.hardEdge, - shape: const CircleBorder(), - color: backgroundColor ?? AppColors.of(context).text.withOpacity(.15), - child: InkWell( - child: AnimatedContainer( - duration: const Duration(milliseconds: 200), - height: radius * 2, - width: radius * 2, - decoration: const BoxDecoration( - shape: BoxShape.circle, - ), - child: name != null && (name?.trim().length ?? 0) > 0 - ? Center( - child: Text( - (name?.trim().length ?? 0) > 0 - ? (name ?? "?").trim()[0] - : "?", - style: TextStyle( - color: color, - fontWeight: FontWeight.w600, - fontSize: 18.0 * (radius / 20.0), - ), - ), - ) - : Container(), - ), - ), - ), - - // Role indicator - if (role == Role.parent) - SizedBox( - height: radius * 2, - width: radius * 2, - child: Container( - alignment: Alignment.bottomRight, - child: Icon(Icons.shield, color: roleColor, size: radius / 1.3), - ), - ), - ], - ); - } -} diff --git a/refilc_desktop_ui/lib/common/widgets/grade/grade_viewable.dart b/refilc_desktop_ui/lib/common/widgets/grade/grade_viewable.dart deleted file mode 100644 index 3f9fdbd..0000000 --- a/refilc_desktop_ui/lib/common/widgets/grade/grade_viewable.dart +++ /dev/null @@ -1,14 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:refilc_kreta_api/models/grade.dart'; -import 'package:refilc/ui/widgets/grade/grade_tile.dart'; - -class GradeViewable extends StatelessWidget { - const GradeViewable(this.grade, {super.key}); - - final Grade grade; - - @override - Widget build(BuildContext context) { - return GradeTile(grade); - } -} diff --git a/refilc_desktop_ui/lib/common/widgets/lesson/lesson_viewable.dart b/refilc_desktop_ui/lib/common/widgets/lesson/lesson_viewable.dart deleted file mode 100644 index 2ce76cb..0000000 --- a/refilc_desktop_ui/lib/common/widgets/lesson/lesson_viewable.dart +++ /dev/null @@ -1,19 +0,0 @@ -import 'package:refilc_kreta_api/models/lesson.dart'; -import 'package:refilc/ui/widgets/lesson/lesson_tile.dart'; -import 'package:flutter/material.dart'; - -class LessonViewable extends StatelessWidget { - const LessonViewable(this.lesson, {super.key, this.swapDesc = false}); - - final Lesson lesson; - final bool swapDesc; - - @override - Widget build(BuildContext context) { - final tile = LessonTile(lesson, swapDesc: swapDesc); - - if (lesson.subject.id == '' || tile.lesson.isEmpty) return tile; - - return tile; - } -} diff --git a/refilc_desktop_ui/lib/pages/absences/absences_page.dart b/refilc_desktop_ui/lib/pages/absences/absences_page.dart deleted file mode 100644 index 33e0906..0000000 --- a/refilc_desktop_ui/lib/pages/absences/absences_page.dart +++ /dev/null @@ -1,408 +0,0 @@ -import 'dart:math'; - -import 'package:animations/animations.dart'; -import 'package:auto_size_text/auto_size_text.dart'; -import 'package:refilc/api/providers/update_provider.dart'; -import 'package:refilc/ui/date_widget.dart'; -import 'package:refilc_kreta_api/models/absence.dart'; -import 'package:refilc_kreta_api/models/lesson.dart'; -import 'package:refilc_kreta_api/models/subject.dart'; -import 'package:refilc_kreta_api/models/week.dart'; -import 'package:refilc_kreta_api/providers/absence_provider.dart'; -import 'package:refilc_kreta_api/providers/note_provider.dart'; -import 'package:refilc/api/providers/user_provider.dart'; -import 'package:refilc/theme/colors/colors.dart'; -import 'package:refilc_kreta_api/providers/timetable_provider.dart'; -import 'package:refilc_mobile_ui/common/action_button.dart'; -import 'package:refilc_mobile_ui/common/empty.dart'; -import 'package:refilc_mobile_ui/common/filter_bar.dart'; -import 'package:refilc_mobile_ui/common/panel/panel.dart'; -import 'package:refilc_mobile_ui/common/widgets/absence/absence_subject_tile.dart'; -import 'package:refilc_mobile_ui/common/widgets/absence/absence_viewable.dart'; -import 'package:refilc_mobile_ui/common/widgets/statistics_tile.dart'; -import 'package:refilc_mobile_ui/common/widgets/miss_tile.dart'; -import 'package:refilc_mobile_ui/pages/absences/absence_subject_view.dart'; -import 'package:refilc/ui/filter/sort.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_feather_icons/flutter_feather_icons.dart'; -import 'package:provider/provider.dart'; -import 'absences_page.i18n.dart'; - -enum AbsenceFilter { absences, delays, misses } - -class SubjectAbsence { - GradeSubject subject; - List absences; - double percentage; - - SubjectAbsence( - {required this.subject, this.absences = const [], this.percentage = 0.0}); -} - -class AbsencesPage extends StatefulWidget { - const AbsencesPage({super.key}); - - @override - AbsencesPageState createState() => AbsencesPageState(); -} - -class AbsencesPageState extends State - with TickerProviderStateMixin { - late UserProvider user; - late AbsenceProvider absenceProvider; - late TimetableProvider timetableProvider; - late NoteProvider noteProvider; - late UpdateProvider updateProvider; - late String firstName; - late TabController _tabController; - late List absences = []; - final Map _lessonCount = {}; - - @override - void initState() { - super.initState(); - - _tabController = TabController(length: 3, vsync: this); - timetableProvider = Provider.of(context, listen: false); - - WidgetsBinding.instance.addPostFrameCallback((timeStamp) async { - for (final lesson in timetableProvider.getWeek(Week.current()) ?? []) { - if (!lesson.isEmpty && - lesson.subject.id != '' && - lesson.lessonYearIndex != null) { - _lessonCount.update( - lesson.subject, - (value) { - if (lesson.lessonYearIndex! > value.lessonYearIndex!) { - return lesson; - } else { - return value; - } - }, - ifAbsent: () => lesson, - ); - } - } - }); - } - - void buildSubjectAbsences() { - // ignore: no_leading_underscores_for_local_identifiers - Map _absences = {}; - - for (final absence in absenceProvider.absences) { - if (absence.delay != 0) continue; - - if (!_absences.containsKey(absence.subject)) { - _absences[absence.subject] = - SubjectAbsence(subject: absence.subject, absences: [absence]); - } else { - _absences[absence.subject]?.absences.add(absence); - } - } - - _absences.forEach((subject, absence) { - final absentLessonsOfSubject = absenceProvider.absences - .where((e) => e.subject == subject && e.delay == 0) - .length; - final totalLessonsOfSubject = _lessonCount[subject]?.lessonYearIndex ?? 0; - - double absentLessonsOfSubjectPercentage; - - if (absentLessonsOfSubject <= totalLessonsOfSubject) { - absentLessonsOfSubjectPercentage = - absentLessonsOfSubject / totalLessonsOfSubject * 100; - } else { - absentLessonsOfSubjectPercentage = -1; - } - - _absences[subject]?.percentage = - absentLessonsOfSubjectPercentage.clamp(-1, 100.0); - }); - - absences = _absences.values.toList(); - absences.sort((a, b) => -a.percentage.compareTo(b.percentage)); - } - - @override - Widget build(BuildContext context) { - user = Provider.of(context); - absenceProvider = Provider.of(context); - noteProvider = Provider.of(context); - updateProvider = Provider.of(context); - timetableProvider = Provider.of(context); - - List nameParts = user.displayName?.split(" ") ?? ["?"]; - firstName = nameParts.length > 1 ? nameParts[1] : nameParts[0]; - - buildSubjectAbsences(); - - return Scaffold( - body: Padding( - padding: const EdgeInsets.only(top: 12.0), - child: NestedScrollView( - physics: const BouncingScrollPhysics( - parent: AlwaysScrollableScrollPhysics()), - headerSliverBuilder: (context, _) => [ - SliverAppBar( - pinned: true, - floating: false, - snap: false, - centerTitle: false, - automaticallyImplyLeading: false, - shadowColor: Theme.of(context).shadowColor, - surfaceTintColor: Theme.of(context).scaffoldBackgroundColor, - title: Padding( - padding: const EdgeInsets.only(left: 8.0), - child: Text( - "Absences".i18n, - style: TextStyle( - color: AppColors.of(context).text, - fontSize: 32.0, - fontWeight: FontWeight.bold), - ), - ), - bottom: FilterBar(items: [ - Tab(text: "Absences".i18n), - Tab(text: "Delays".i18n), - Tab(text: "Misses".i18n), - ], controller: _tabController, disableFading: true), - ), - ], - body: TabBarView( - physics: const BouncingScrollPhysics(), - controller: _tabController, - children: List.generate( - 3, (index) => filterViewBuilder(context, index))), - ), - ), - ); - } - - List getFilterWidgets(AbsenceFilter activeData) { - List items = []; - switch (activeData) { - case AbsenceFilter.absences: - for (var a in absences) { - items.add(DateWidget( - date: DateTime.fromMillisecondsSinceEpoch(0), - widget: AbsenceSubjectTile( - a.subject, - percentage: a.percentage, - excused: a.absences - .where((a) => a.state == Justification.excused) - .length, - unexcused: a.absences - .where((a) => a.state == Justification.unexcused) - .length, - pending: a.absences - .where((a) => a.state == Justification.pending) - .length, - onTap: () => AbsenceSubjectView.show(a.subject, a.absences, - context: context), - ), - )); - } - break; - case AbsenceFilter.delays: - for (var absence in absenceProvider.absences) { - if (absence.delay != 0) { - items.add(DateWidget( - date: absence.date, - widget: AbsenceViewable( - absence, - padding: EdgeInsets.zero, - ))); - } - } - break; - case AbsenceFilter.misses: - for (var note in noteProvider.notes) { - if (note.type?.name == "HaziFeladatHiany" || - note.type?.name == "Felszereleshiany") { - items.add(DateWidget( - date: note.date, - widget: MissTile(note), - )); - } - } - break; - } - return items; - } - - Widget filterViewBuilder(context, int activeData) { - List filterWidgets = []; - - if (activeData > 0) { - filterWidgets = sortDateWidgets( - context, - dateWidgets: getFilterWidgets(AbsenceFilter.values[activeData]), - padding: EdgeInsets.zero, - hasShadow: true, - ); - } else { - filterWidgets = [ - Padding( - padding: const EdgeInsets.only(bottom: 24.0), - child: Panel( - title: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text("Subjects".i18n), - Padding( - padding: const EdgeInsets.only(right: 4.0), - child: IconButton( - onPressed: () { - showDialog( - context: context, - builder: (context) => AlertDialog( - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(12.0)), - title: Text("attention".i18n), - content: Text("attention_body".i18n), - actions: [ - ActionButton( - label: "Ok", - onTap: () => Navigator.of(context).pop()) - ], - ), - ); - }, - padding: EdgeInsets.zero, - splashRadius: 24.0, - visualDensity: VisualDensity.compact, - constraints: BoxConstraints.tight(const Size(42.0, 42.0)), - icon: const Icon(FeatherIcons.info), - ), - ), - ], - ), - child: PageTransitionSwitcher( - transitionBuilder: ( - Widget child, - Animation primaryAnimation, - Animation secondaryAnimation, - ) { - return FadeThroughTransition( - animation: primaryAnimation, - secondaryAnimation: secondaryAnimation, - fillColor: Theme.of(context).colorScheme.surface, - child: child, - ); - }, - child: Column( - children: getFilterWidgets(AbsenceFilter.values[activeData]) - .map((e) => e.widget) - .cast() - .toList(), - ), - ), - ), - ) - ]; - } - - return Padding( - padding: const EdgeInsets.only(top: 12.0), - child: RefreshIndicator( - color: Theme.of(context).colorScheme.secondary, - onRefresh: () async { - await absenceProvider.fetch(); - await noteProvider.fetch(); - }, - child: ListView.builder( - padding: EdgeInsets.zero, - physics: const BouncingScrollPhysics(), - itemCount: max(filterWidgets.length + (activeData <= 1 ? 1 : 0), 1), - itemBuilder: (context, index) { - if (filterWidgets.isNotEmpty) { - if ((index == 0 && activeData == 1) || - (index == 0 && activeData == 0)) { - int value1 = 0; - int value2 = 0; - String title1 = ""; - String title2 = ""; - String suffix = ""; - - if (activeData == AbsenceFilter.absences.index) { - value1 = absenceProvider.absences - .where((e) => - e.delay == 0 && e.state == Justification.excused) - .length; - value2 = absenceProvider.absences - .where((e) => - e.delay == 0 && e.state == Justification.unexcused) - .length; - title1 = "stat_1".i18n; - title2 = "stat_2".i18n; - suffix = " ${"hr".i18n}"; - } else if (activeData == AbsenceFilter.delays.index) { - value1 = absenceProvider.absences - .where((e) => - e.delay != 0 && e.state == Justification.excused) - .map((e) => e.delay) - .fold(0, (a, b) => a + b); - value2 = absenceProvider.absences - .where((e) => - e.delay != 0 && e.state == Justification.unexcused) - .map((e) => e.delay) - .fold(0, (a, b) => a + b); - title1 = "stat_3".i18n; - title2 = "stat_4".i18n; - suffix = " ${"min".i18n}"; - } - - return Padding( - padding: const EdgeInsets.only( - bottom: 24.0, left: 24.0, right: 24.0), - child: Row(children: [ - Expanded( - child: StatisticsTile( - title: AutoSizeText( - title1, - textAlign: TextAlign.center, - maxLines: 2, - overflow: TextOverflow.ellipsis, - ), - valueSuffix: suffix, - value: value1.toDouble(), - decimal: false, - color: AppColors.of(context).green, - ), - ), - const SizedBox(width: 24.0), - Expanded( - child: StatisticsTile( - title: AutoSizeText( - title2, - textAlign: TextAlign.center, - maxLines: 2, - overflow: TextOverflow.ellipsis, - ), - valueSuffix: suffix, - value: value2.toDouble(), - decimal: false, - color: AppColors.of(context).red, - ), - ), - ]), - ); - } - - return Padding( - padding: - const EdgeInsets.symmetric(horizontal: 24.0, vertical: 6.0), - child: filterWidgets[index - (activeData <= 1 ? 1 : 0)], - ); - } else { - return activeData == 1 - ? Empty(subtitle: "emptyDelays".i18n) - : Empty(subtitle: "emptyMisses".i18n); - } - }, - ), - ), - ); - } -} diff --git a/refilc_desktop_ui/lib/pages/absences/absences_page.i18n.dart b/refilc_desktop_ui/lib/pages/absences/absences_page.i18n.dart deleted file mode 100644 index 9984034..0000000 --- a/refilc_desktop_ui/lib/pages/absences/absences_page.i18n.dart +++ /dev/null @@ -1,60 +0,0 @@ -import 'package:i18n_extension/i18n_extension.dart'; - -extension ScreensLocalization on String { - static final _t = Translations.byLocale("hu_hu") + - { - "en_en": { - "Absences": "Absences", - "Delays": "Delays", - "Misses": "Misses", - "emptyDelays": "You have no delays.", - "emptyMisses": "You have no missing homeworks or equipments.", - "stat_1": "Excused Absences", - "stat_2": "Unexcused Absences", - "stat_3": "Excused Delay", - "stat_4": "Unexcused Delay", - "min": "min", - "hr": "hrs", - "Subjects": "Subjects", - "attention": "Attention!", - "attention_body": "Percentage calculations are only an approximation so they may not be accurate.", - }, - "hu_hu": { - "Absences": "Hiányzások", - "Delays": "Késések", - "Misses": "Hiányok", - "emptyDelays": "Nincsenek késéseid.", - "emptyMisses": "Nincsenek hiányzó házi feladataid, felszereléseid.", - "stat_1": "Igazolt hiányzások", - "stat_2": "Igazolatlan hiányzások", - "stat_3": "Igazolt Késés", - "stat_4": "Igazolatlan Késés", - "min": "perc", - "hr": "óra", - "Subjects": "Tantárgyak", - "attention": "Figyelem!", - "attention_body": "A százalékos számítások csak közelítések, ezért előfordulhat, hogy nem pontosak.", - }, - "de_de": { - "Absences": "Fehlen", - "Delays": "Verspätung", - "Misses": "Fehlt", - "emptyDelays": "Sie haben keine Abwesenheiten.", - "emptyMisses": "Sie haben noch keine fehlende Hausaufgaben oder Austattung.", - "stat_1": "Entschuldigte Fehlen", - "stat_2": "Unentschuldigte Fehlen", - "stat_3": "Entschuldigte Verspätung", - "stat_4": "Unentschuldigte Verspätung", - "min": "min", - "hr": "hrs", - "Subjects": "Fächer", - "attention": "Achtung!", - "attention_body": "Prozentberechnungen sind nur eine Annäherung und können daher ungenau sein.", - }, - }; - - String get i18n => localize(this, _t); - String fill(List params) => localizeFill(this, params); - String plural(int value) => localizePlural(value, this, _t); - String version(Object modifier) => localizeVersion(modifier, this, _t); -} diff --git a/refilc_desktop_ui/lib/pages/grades/grade_subject_view.dart b/refilc_desktop_ui/lib/pages/grades/grade_subject_view.dart deleted file mode 100644 index 2b417c0..0000000 --- a/refilc_desktop_ui/lib/pages/grades/grade_subject_view.dart +++ /dev/null @@ -1,296 +0,0 @@ -import 'dart:math'; - -import 'package:animations/animations.dart'; -import 'package:refilc/models/settings.dart'; -import 'package:refilc/utils/format.dart'; -import 'package:refilc_kreta_api/providers/grade_provider.dart'; -import 'package:refilc/helpers/average_helper.dart'; -import 'package:refilc/helpers/subject.dart'; -import 'package:refilc_kreta_api/models/grade.dart'; -import 'package:refilc_kreta_api/models/subject.dart'; -import 'package:refilc_mobile_ui/common/average_display.dart'; -import 'package:refilc_mobile_ui/common/bottom_sheet_menu/rounded_bottom_sheet.dart'; -import 'package:refilc_mobile_ui/common/panel/panel.dart'; -import 'package:refilc_mobile_ui/common/trend_display.dart'; -import 'package:refilc_mobile_ui/common/widgets/cretification/certification_tile.dart'; -import 'package:refilc/ui/widgets/grade/grade_tile.dart'; -import 'package:refilc_mobile_ui/common/widgets/grade/grade_viewable.dart'; -import 'package:refilc_mobile_ui/common/hero_scrollview.dart'; -import 'package:refilc_mobile_ui/pages/grades/calculator/grade_calculator.dart'; -import 'package:refilc_mobile_ui/pages/grades/calculator/grade_calculator_provider.dart'; -import 'package:refilc_desktop_ui/pages/grades/grades_count.dart'; -import 'package:refilc_mobile_ui/pages/grades/graph.dart'; -import 'package:refilc_mobile_ui/pages/grades/subject_grades_container.dart'; -import 'package:flutter/cupertino.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_expandable_fab/flutter_expandable_fab.dart'; -import 'package:flutter_feather_icons/flutter_feather_icons.dart'; -import 'package:provider/provider.dart'; -import 'grades_page.i18n.dart'; -//import 'package:refilc_plus/ui/mobile/goal_planner/new_goal.dart'; - -class GradeSubjectView extends StatefulWidget { - const GradeSubjectView(this.subject, {super.key, this.groupAverage = 0.0}); - - final GradeSubject subject; - final double groupAverage; - - void push(BuildContext context, {bool root = false}) { - Navigator.of(context, rootNavigator: root) - .push(CupertinoPageRoute(builder: (context) => this)); - } - - @override - State createState() => _GradeSubjectViewState(); -} - -class _GradeSubjectViewState extends State { - final GlobalKey _scaffoldKey = GlobalKey(); - - // Controllers - PersistentBottomSheetController? _sheetController; - final ScrollController _scrollController = ScrollController(); - - List gradeTiles = []; - - // Providers - late GradeProvider gradeProvider; - late GradeCalculatorProvider calculatorProvider; - late SettingsProvider settingsProvider; - - late double average; - late Widget gradeGraph; - - bool gradeCalcMode = false; - - List getSubjectGrades(GradeSubject subject) => !gradeCalcMode - ? gradeProvider.grades.where((e) => e.subject == subject).toList() - : calculatorProvider.grades.where((e) => e.subject == subject).toList(); - - bool showGraph(List subjectGrades) { - if (gradeCalcMode) return true; - - final gradeDates = subjectGrades.map((e) => e.date.millisecondsSinceEpoch); - final maxGradeDate = gradeDates.fold(0, max); - final minGradeDate = gradeDates.fold(0, min); - if (maxGradeDate - minGradeDate < const Duration(days: 5).inMilliseconds) { - return false; // naplo/#78 - } - - return subjectGrades.where((e) => e.type == GradeType.midYear).length > 1; - } - - void buildTiles(List subjectGrades) { - List tiles = []; - - if (showGraph(subjectGrades)) { - tiles.add(gradeGraph); - } else { - tiles.add(Container(height: 24.0)); - } - - // ignore: no_leading_underscores_for_local_identifiers - List _gradeTiles = []; - - if (!gradeCalcMode) { - subjectGrades.sort((a, b) => -a.date.compareTo(b.date)); - for (var grade in subjectGrades) { - if (grade.type == GradeType.midYear) { - _gradeTiles.add(GradeViewable(grade)); - } else { - _gradeTiles.add(CertificationTile(grade, padding: EdgeInsets.zero)); - } - } - } else if (subjectGrades.isNotEmpty) { - subjectGrades.sort((a, b) => -a.date.compareTo(b.date)); - for (var grade in subjectGrades) { - _gradeTiles.add(GradeTile(grade)); - } - } - tiles.add( - PageTransitionSwitcher( - transitionBuilder: ( - Widget child, - Animation primaryAnimation, - Animation secondaryAnimation, - ) { - return SharedAxisTransition( - animation: primaryAnimation, - secondaryAnimation: secondaryAnimation, - transitionType: SharedAxisTransitionType.vertical, - fillColor: Colors.transparent, - child: child, - ); - }, - child: _gradeTiles.isNotEmpty - ? Panel( - key: ValueKey(gradeCalcMode), - title: Text( - gradeCalcMode ? "Ghost Grades".i18n : "Grades".i18n, - ), - child: Column( - children: _gradeTiles, - )) - : const SizedBox(), - ), - ); - - tiles.add(Padding( - padding: EdgeInsets.only(bottom: !gradeCalcMode ? 24.0 : 250.0))); - gradeTiles = List.castFrom(tiles); - } - - @override - Widget build(BuildContext context) { - gradeProvider = Provider.of(context); - calculatorProvider = Provider.of(context); - settingsProvider = Provider.of(context); - - List subjectGrades = getSubjectGrades(widget.subject).toList(); - average = AverageHelper.averageEvals(subjectGrades); - final prevAvg = subjectGrades.isNotEmpty - ? AverageHelper.averageEvals(subjectGrades - .where((e) => e.date.isBefore(subjectGrades - .reduce((v, e) => e.date.isAfter(v.date) ? e : v) - .date - .subtract(const Duration(days: 30)))) - .toList()) - : 0.0; - - gradeGraph = Padding( - padding: const EdgeInsets.only(top: 16.0, bottom: 8.0), - child: Panel( - title: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text("annual_average".i18n), - if (average != prevAvg) - TrendDisplay(current: average, previous: prevAvg), - ], - ), - child: Container( - padding: const EdgeInsets.only(top: 12.0, right: 12.0), - child: Row( - children: [ - Expanded( - child: GradeGraph(subjectGrades, - dayThreshold: 5, classAvg: widget.groupAverage)), - Padding( - padding: const EdgeInsets.only(bottom: 24.0), - child: GradesCount(grades: subjectGrades), - ), - ], - ), - ), - ), - ); - - if (!gradeCalcMode) { - buildTiles(subjectGrades); - } else { - List ghostGrades = calculatorProvider.ghosts - .where((e) => e.subject == widget.subject) - .toList(); - buildTiles(ghostGrades); - } - - return Scaffold( - key: _scaffoldKey, - floatingActionButtonLocation: ExpandableFab.location, - floatingActionButton: Visibility( - visible: !gradeCalcMode && - subjectGrades - .where((e) => e.type == GradeType.midYear) - .isNotEmpty, - child: ExpandableFab( - type: ExpandableFabType.up, - distance: 50, - children: [ - FloatingActionButton.small( - child: const Icon(FeatherIcons.plus), - onPressed: () { - gradeCalc(context); - }, - ), - // FloatingActionButton.small( - // child: const Icon(FeatherIcons.flag, size: 20.0), - // onPressed: () { - // Navigator.of(context).push(CupertinoPageRoute(builder: (context) => PremiumGoalplannerNewGoalScreen(subject: widget.subject))); - // }, - // ), - ], - ), - ), - body: RefreshIndicator( - onRefresh: () async {}, - color: Theme.of(context).colorScheme.secondary, - child: HeroScrollView( - onClose: () { - if (_sheetController != null && gradeCalcMode) { - _sheetController!.close(); - } else { - Navigator.of(context).pop(); - } - }, - navBarItems: [ - const SizedBox(width: 6.0), - if (widget.groupAverage != 0) - Center( - child: AverageDisplay( - average: widget.groupAverage, border: true)), - const SizedBox(width: 6.0), - if (average != 0) - Center(child: AverageDisplay(average: average)), - const SizedBox(width: 12.0), - ], - icon: SubjectIcon.resolveVariant( - subject: widget.subject, context: context), - scrollController: _scrollController, - title: widget.subject.renamedTo ?? widget.subject.name.capital(), - italic: widget.subject.isRenamed && - settingsProvider.renamedSubjectsItalics, - child: SubjectGradesContainer( - child: CupertinoScrollbar( - child: ListView.builder( - physics: const BouncingScrollPhysics(), - padding: const EdgeInsets.symmetric(horizontal: 24.0), - shrinkWrap: true, - itemBuilder: (context, index) => gradeTiles[index], - itemCount: gradeTiles.length, - ), - ), - )), - )); - } - - void gradeCalc(BuildContext context) { - // Scroll to the top of the page - _scrollController.animateTo(75, - duration: const Duration(milliseconds: 500), curve: Curves.ease); - - calculatorProvider.clear(); - calculatorProvider.addAllGrades(gradeProvider.grades); - - _sheetController = _scaffoldKey.currentState?.showBottomSheet( - (context) => RoundedBottomSheet( - borderRadius: 14.0, - child: GradeCalculator(widget.subject)), - backgroundColor: const Color(0x00000000), - elevation: 12.0, - ); - - // Hide the fab and grades - setState(() { - gradeCalcMode = true; - }); - - _sheetController!.closed.then((value) { - // Show fab and grades - if (mounted) { - setState(() { - gradeCalcMode = false; - }); - } - }); - } -} diff --git a/refilc_desktop_ui/lib/pages/grades/grades_count.dart b/refilc_desktop_ui/lib/pages/grades/grades_count.dart deleted file mode 100644 index 104f70d..0000000 --- a/refilc_desktop_ui/lib/pages/grades/grades_count.dart +++ /dev/null @@ -1,30 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:refilc_kreta_api/models/grade.dart'; -import 'package:refilc_desktop_ui/pages/grades/grades_count_item.dart'; -import 'package:collection/collection.dart'; - -class GradesCount extends StatelessWidget { - const GradesCount({super.key, required this.grades}); - - final List grades; - - @override - Widget build(BuildContext context) { - List gradesCount = List.generate(5, - (int index) => grades.where((e) => e.value.value == index + 1).length); - - return Container( - width: 75, - padding: - const EdgeInsets.only(bottom: 6.0, top: 6.0, left: 12.0, right: 0.0), - margin: const EdgeInsets.symmetric(horizontal: 12.0), - child: Column( - mainAxisAlignment: MainAxisAlignment.spaceAround, - children: gradesCount - .mapIndexed( - (index, e) => GradesCountItem(count: e, value: index + 1)) - .toList(), - ), - ); - } -} diff --git a/refilc_desktop_ui/lib/pages/grades/grades_count_item.dart b/refilc_desktop_ui/lib/pages/grades/grades_count_item.dart deleted file mode 100644 index 0bd99c2..0000000 --- a/refilc_desktop_ui/lib/pages/grades/grades_count_item.dart +++ /dev/null @@ -1,38 +0,0 @@ -import 'package:refilc/ui/widgets/grade/grade_tile.dart'; -import 'package:refilc_kreta_api/models/grade.dart'; -import 'package:flutter/material.dart'; - -class GradesCountItem extends StatelessWidget { - const GradesCountItem({super.key, required this.count, required this.value}); - - final int count; - final int value; - - @override - Widget build(BuildContext context) { - return Padding( - padding: const EdgeInsets.symmetric(vertical: 2.0), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text.rich( - TextSpan(children: [ - TextSpan( - text: count.toString(), - style: const TextStyle(fontWeight: FontWeight.w600), - ), - const TextSpan( - text: "x", - style: TextStyle(fontSize: 13.0), - ), - ]), - style: const TextStyle(fontSize: 15.0), - ), - const SizedBox(width: 5.0), - GradeValueWidget(GradeValue(value, "Value", "Value", 100), - size: 19.0, fill: true, shadow: false), - ], - ), - ); - } -} diff --git a/refilc_desktop_ui/lib/pages/grades/grades_page.dart b/refilc_desktop_ui/lib/pages/grades/grades_page.dart deleted file mode 100644 index 24c9ec2..0000000 --- a/refilc_desktop_ui/lib/pages/grades/grades_page.dart +++ /dev/null @@ -1,314 +0,0 @@ -import 'dart:math'; - -import 'package:auto_size_text/auto_size_text.dart'; -import 'package:refilc/api/providers/update_provider.dart'; -import 'package:refilc_kreta_api/providers/grade_provider.dart'; -import 'package:refilc/api/providers/user_provider.dart'; -import 'package:refilc/theme/colors/colors.dart'; -import 'package:refilc_kreta_api/models/grade.dart'; -import 'package:refilc_kreta_api/models/subject.dart'; -import 'package:refilc_kreta_api/models/group_average.dart'; -import 'package:refilc_mobile_ui/common/average_display.dart'; -import 'package:refilc_mobile_ui/common/empty.dart'; -import 'package:refilc_mobile_ui/common/panel/panel.dart'; -import 'package:refilc_mobile_ui/common/widgets/statistics_tile.dart'; -import 'package:refilc_mobile_ui/common/widgets/grade/grade_subject_tile.dart'; -import 'package:refilc_mobile_ui/common/trend_display.dart'; -import 'package:refilc_mobile_ui/pages/grades/fail_warning.dart'; -import 'package:refilc_desktop_ui/pages/grades/grades_count.dart'; -import 'package:refilc_mobile_ui/pages/grades/graph.dart'; -import 'package:refilc_desktop_ui/pages/grades/grade_subject_view.dart'; -import 'package:flutter/material.dart'; -import 'package:provider/provider.dart'; -import 'package:refilc/helpers/average_helper.dart'; -import 'package:refilc_mobile_ui/pages/grades/average_selector.dart'; -import 'grades_page.i18n.dart'; - -class GradesPage extends StatefulWidget { - const GradesPage({super.key}); - - @override - GradesPageState createState() => GradesPageState(); -} - -class GradesPageState extends State { - late UserProvider user; - late GradeProvider gradeProvider; - late UpdateProvider updateProvider; - late String firstName; - late Widget yearlyGraph; - List subjectTiles = []; - - int avgDropValue = 0; - - List getSubjectGrades(GradeSubject subject, {int days = 0}) => - gradeProvider.grades - .where((e) => - e.subject == subject && - e.type == GradeType.midYear && - (days == 0 || - e.date - .isBefore(DateTime.now().subtract(Duration(days: days))))) - .toList(); - - void generateTiles() { - List subjects = gradeProvider.grades - .map((e) => e.subject) - .toSet() - .toList() - ..sort((a, b) => a.name.compareTo(b.name)); - List tiles = []; - - Map subjectAvgs = {}; - - tiles.addAll(subjects.map((subject) { - List subjectGrades = getSubjectGrades(subject); - - double avg = AverageHelper.averageEvals(subjectGrades); - double averageBefore = 0.0; - - if (avgDropValue != 0) { - List gradesBefore = - getSubjectGrades(subject, days: avgDropValue); - averageBefore = - avgDropValue == 0 ? 0.0 : AverageHelper.averageEvals(gradesBefore); - } - var nullavg = GroupAverage(average: 0.0, subject: subject, uid: "0"); - double groupAverage = gradeProvider.groupAverages - .firstWhere((e) => e.subject == subject, orElse: () => nullavg) - .average; - - if (avg != 0) subjectAvgs[subject] = avg; - - return GradeSubjectTile( - subject, - averageBefore: averageBefore, - average: avg, - groupAverage: avgDropValue == 0 ? groupAverage : 0.0, - onTap: () { - GradeSubjectView(subject, groupAverage: groupAverage) - .push(context, root: true); - }, - ); - })); - - if (tiles.isNotEmpty) { - tiles.insert(0, yearlyGraph); - tiles.insert(1, FailWarning(subjectAvgs: subjectAvgs)); - tiles.insert( - 2, - PanelTitle( - title: Text(avgDropValue == 0 - ? "Subjects".i18n - : "Subjects_changes".i18n))); - tiles.insert(3, const PanelHeader(padding: EdgeInsets.only(top: 12.0))); - tiles.add(const PanelFooter(padding: EdgeInsets.only(bottom: 12.0))); - tiles.add(const Padding(padding: EdgeInsets.only(bottom: 24.0))); - } else { - tiles.insert( - 0, - Padding( - padding: const EdgeInsets.only(top: 24.0), - child: Empty(subtitle: "empty".i18n), - ), - ); - } - - double subjectAvg = subjectAvgs.isNotEmpty - ? subjectAvgs.values.fold(0.0, (double a, double b) => a + b) / - subjectAvgs.length - : 0.0; - final double classAvg = gradeProvider.groupAverages.isNotEmpty - ? gradeProvider.groupAverages - .map((e) => e.average) - .fold(0.0, (double a, double b) => a + b) / - gradeProvider.groupAverages.length - : 0.0; - - if (subjectAvg > 0) { - tiles.add(Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Expanded( - child: StatisticsTile( - fill: true, - title: AutoSizeText( - "subjectavg".i18n, - textAlign: TextAlign.center, - maxLines: 2, - overflow: TextOverflow.ellipsis, - ), - value: subjectAvg, - ), - ), - const SizedBox(width: 24.0), - Expanded( - child: StatisticsTile( - outline: true, - title: AutoSizeText( - // https://discord.com/channels/1111649116020285532/1153397476578050130 - "classavg".i18n, - textAlign: TextAlign.center, - maxLines: 2, - wrapWords: false, - overflow: TextOverflow.ellipsis, - ), - value: classAvg, - ), - ), - ], - )); - } - - // padding - tiles.add(const SizedBox(height: 32.0)); - - subjectTiles = List.castFrom(tiles); - } - - @override - Widget build(BuildContext context) { - user = Provider.of(context); - gradeProvider = Provider.of(context); - updateProvider = Provider.of(context); - - List nameParts = user.displayName?.split(" ") ?? ["?"]; - firstName = nameParts.length > 1 ? nameParts[1] : nameParts[0]; - - final double totalClassAvg = gradeProvider.groupAverages.isEmpty - ? 0.0 - : gradeProvider.groupAverages - .map((e) => e.average) - .fold(0.0, (double a, double b) => a + b) / - gradeProvider.groupAverages.length; - - final now = gradeProvider.grades.isNotEmpty - ? gradeProvider.grades - .reduce((v, e) => e.date.isAfter(v.date) ? e : v) - .date - : DateTime.now(); - - final currentStudentAvg = AverageHelper.averageEvals(gradeProvider.grades - .where((e) => e.type == GradeType.midYear) - .toList()); - final prevStudentAvg = AverageHelper.averageEvals(gradeProvider.grades - .where((e) => e.type == GradeType.midYear) - .where((e) => e.date.isBefore(now.subtract(const Duration(days: 30)))) - .toList()); - - List graphGrades = gradeProvider.grades - .where((e) => - e.type == GradeType.midYear && - (avgDropValue == 0 || - e.date.isAfter( - DateTime.now().subtract(Duration(days: avgDropValue))))) - .toList(); - - yearlyGraph = Padding( - padding: const EdgeInsets.only(top: 12.0, bottom: 8.0), - child: Panel( - title: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - AverageSelector( - value: avgDropValue, - onChanged: (value) { - setState(() { - avgDropValue = value!; - }); - }, - ), - Row( - children: [ - // if (totalClassAvg >= 1.0) AverageDisplay(average: totalClassAvg, border: true), - // const SizedBox(width: 4.0), - TrendDisplay( - previous: prevStudentAvg, current: currentStudentAvg), - if (gradeProvider.grades - .where((e) => e.type == GradeType.midYear) - .isNotEmpty) - AverageDisplay(average: currentStudentAvg), - ], - ) - ], - ), - child: Container( - padding: const EdgeInsets.only(top: 12.0, right: 12.0), - child: Row( - children: [ - Expanded( - child: GradeGraph(graphGrades, - dayThreshold: 2, classAvg: totalClassAvg)), - Padding( - padding: const EdgeInsets.only(bottom: 24.0), - child: GradesCount(grades: graphGrades), - ), - ], - ), - ), - ), - ); - - generateTiles(); - - return Scaffold( - body: Padding( - padding: const EdgeInsets.only(top: 9.0), - child: NestedScrollView( - physics: const BouncingScrollPhysics( - parent: AlwaysScrollableScrollPhysics()), - headerSliverBuilder: (context, _) => [ - SliverAppBar( - centerTitle: false, - pinned: true, - floating: false, - snap: false, - automaticallyImplyLeading: false, - surfaceTintColor: Theme.of(context).scaffoldBackgroundColor, - title: Padding( - padding: const EdgeInsets.only(left: 8.0), - child: Text( - "page_title_grades".i18n, - style: TextStyle( - color: AppColors.of(context).text, - fontSize: 32.0, - fontWeight: FontWeight.bold), - ), - ), - shadowColor: Theme.of(context).shadowColor, - ), - ], - body: RefreshIndicator( - onRefresh: () => gradeProvider.fetch(), - color: Theme.of(context).colorScheme.secondary, - child: ListView.builder( - padding: EdgeInsets.zero, - physics: const BouncingScrollPhysics(), - itemCount: max(subjectTiles.length, 1), - itemBuilder: (context, index) { - if (subjectTiles.isNotEmpty) { - EdgeInsetsGeometry panelPadding = - const EdgeInsets.symmetric(horizontal: 24.0); - - if (subjectTiles[index].runtimeType == GradeSubjectTile) { - return Padding( - padding: panelPadding, - child: PanelBody( - padding: const EdgeInsets.symmetric(horizontal: 8.0), - child: subjectTiles[index], - )); - } else { - return Padding( - padding: panelPadding, child: subjectTiles[index]); - } - } else { - return Container(); - } - }, - ), - ), - ), - ), - ); - } -} diff --git a/refilc_desktop_ui/lib/pages/grades/grades_page.i18n.dart b/refilc_desktop_ui/lib/pages/grades/grades_page.i18n.dart deleted file mode 100644 index 86b8414..0000000 --- a/refilc_desktop_ui/lib/pages/grades/grades_page.i18n.dart +++ /dev/null @@ -1,61 +0,0 @@ -import 'package:i18n_extension/i18n_extension.dart'; - -extension Localization on String { - static final _t = Translations.byLocale("hu_hu") + - { - "en_en": { - "Grades": "Grades", - "Ghost Grades": "Grades", - "Subjects": "Subjects", - "Subjects_changes": "Subject Differences", - "empty": "You don't have any subjects.", - "annual_average": "Annual average", - "3_months_average": "3 Monthly Average", - "30_days_average": "Monthly Average", - "14_days_average": "2 Weekly Average", - "7_days_average": "Weekly Average", - "subjectavg": "Subject Average", - "classavg": "Class Average", - "fail_warning": "Failure warning", - "fail_warning_description": "You are failing %d subjects!" - .one("You are failing a subject!"), - }, - "hu_hu": { - "Grades": "Jegyek", - "Ghost Grades": "Szellem jegyek", - "Subjects": "Tantárgyak", - "Subjects_changes": "Tantárgyi változások", - "empty": "Még nincs egy tárgyad sem.", - "annual_average": "Éves átlag", - "3_months_average": "Háromhavi átlag", - "30_days_average": "Havi átlag", - "14_days_average": "Kétheti átlag", - "7_days_average": "Heti átlag", - "subjectavg": "Tantárgyi átlag", - "classavg": "Osztályátlag", - "fail_warning": "Bukás figyelmeztető", - "fail_warning_description": "Bukásra állsz %d tantárgyból", - }, - "de_de": { - "Grades": "Noten", - "Ghost Grades": "Geist Noten", - "Subjects": "Fächer", - "Subjects_changes": "Betreff Änderungen", - "empty": "Sie haben keine Fächer.", - "annual_average": "Jahresdurchschnitt", - "3_months_average": "Drei-Monats-Durchschnitt", - "30_days_average": "Monatsdurchschnitt", - "14_days_average": "Vierzehntägiger Durchschnitt", - "7_days_average": "Wöchentlicher Durchschnitt", - "subjectavg": "Fächer Durchschnitt", - "classavg": "Klassendurchschnitt", - "fail_warning": "Ausfallwarnung", - "fail_warning_description": "Sie werden in %d des Fachs durchfallen", - }, - }; - - String get i18n => localize(this, _t); - String fill(List params) => localizeFill(this, params); - String plural(int value) => localizePlural(value, this, _t); - String version(Object modifier) => localizeVersion(modifier, this, _t); -} diff --git a/refilc_desktop_ui/lib/pages/home/home_page.dart b/refilc_desktop_ui/lib/pages/home/home_page.dart deleted file mode 100644 index bd9ee2c..0000000 --- a/refilc_desktop_ui/lib/pages/home/home_page.dart +++ /dev/null @@ -1,180 +0,0 @@ -import 'package:refilc/api/providers/user_provider.dart'; -import 'package:refilc/models/settings.dart'; -import 'package:refilc/ui/date_widget.dart'; -import 'package:refilc_mobile_ui/common/filter_bar.dart'; -import 'package:flutter/material.dart'; -import 'package:animated_list_plus/animated_list_plus.dart'; -import 'package:provider/provider.dart'; -import 'package:refilc/ui/filter/widgets.dart'; -import 'package:refilc/ui/filter/sort.dart'; -import 'home_page.i18n.dart'; - -class HomePage extends StatefulWidget { - const HomePage({super.key}); - - @override - State createState() => _HomePageState(); -} - -class _HomePageState extends State - with SingleTickerProviderStateMixin { - late UserProvider user; - late SettingsProvider settings; - - late TabController _tabController; - late PageController _pageController; - - late String greeting; - late String firstName; - - late List listOrder; - static const pageCount = 4; - - @override - void initState() { - super.initState(); - - _tabController = TabController(length: pageCount, vsync: this); - _pageController = PageController(); - - listOrder = List.generate(pageCount, (index) => "$index"); - - user = Provider.of(context, listen: false); - - DateTime now = DateTime.now(); - if (now.isBefore(DateTime(now.year, DateTime.august, 31)) && - now.isAfter(DateTime(now.year, DateTime.june, 14))) { - greeting = "goodrest"; - } else if (now.month == user.student?.birth.month && - now.day == user.student?.birth.day) { - greeting = "happybirthday"; - } else if (now.month == DateTime.december && - now.day >= 24 && - now.day <= 26) { - greeting = "merryxmas"; - } else if (now.month == DateTime.january && now.day == 1) { - greeting = "happynewyear"; - } else if (now.hour >= 18) { - greeting = "goodevening"; - } else if (now.hour >= 12) { - greeting = "goodafternoon"; - } else if (now.hour >= 4) { - greeting = "goodmorning"; - } else { - greeting = "goodevening"; - } - } - - @override - Widget build(BuildContext context) { - user = Provider.of(context); - settings = Provider.of(context); - - List nameParts = user.name?.split(" ") ?? ["?"]; - if (!settings.presentationMode) { - firstName = nameParts.length > 1 ? nameParts[1] : nameParts[0]; - } else { - firstName = "Béla"; - } - - return SafeArea( - child: Row( - children: [ - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - // Greeting - Padding( - padding: const EdgeInsets.only( - left: 32.0, top: 24.0, bottom: 12.0), - child: Text( - greeting.i18n.fill([firstName]), - overflow: TextOverflow.fade, - style: TextStyle( - fontWeight: FontWeight.bold, - fontSize: 24.0, - color: Theme.of(context).textTheme.bodyMedium?.color, - ), - ), - ), - - Padding( - padding: const EdgeInsets.only(bottom: 12.0), - child: FilterBar( - items: [ - Tab(text: "All".i18n), - Tab(text: "Grades".i18n), - Tab(text: "Messages".i18n), - Tab(text: "Absences".i18n), - ], - controller: _tabController, - onTap: (i) async { - int selectedPage = _pageController.page!.round(); - - if (i == selectedPage) return; - if (_pageController.page?.roundToDouble() != - _pageController.page) { - _pageController.animateToPage(i, - curve: Curves.easeIn, duration: kTabScrollDuration); - return; - } - - // swap current page with target page - setState(() { - _pageController.jumpToPage(i); - String currentList = listOrder[selectedPage]; - listOrder[selectedPage] = listOrder[i]; - listOrder[i] = currentList; - }); - }, - disableFading: true, - ), - ), - - // Data filters - Expanded( - child: PageView.custom( - controller: _pageController, - childrenDelegate: SliverChildBuilderDelegate( - (BuildContext context, int index) { - return FutureBuilder>( - key: ValueKey(listOrder[index]), - future: getFilterWidgets(homeFilters[index], - context: context), - builder: (context, dateWidgets) => dateWidgets.data != - null - ? ImplicitlyAnimatedList( - items: sortDateWidgets(context, - dateWidgets: dateWidgets.data!), - itemBuilder: filterItemBuilder, - spawnIsolate: false, - areItemsTheSame: (a, b) => a.key == b.key, - physics: const BouncingScrollPhysics( - parent: AlwaysScrollableScrollPhysics()), - padding: const EdgeInsets.symmetric( - horizontal: 24.0), - ) - : Container(), - ); - }, - childCount: 4, - findChildIndexCallback: (Key key) { - final ValueKey valueKey = - key as ValueKey; - final String data = valueKey.value; - return listOrder.indexOf(data); - }, - ), - physics: const PageScrollPhysics() - .applyTo(const BouncingScrollPhysics()), - ), - ), - ], - ), - ), - ], - ), - ); - } -} diff --git a/refilc_desktop_ui/lib/pages/home/home_page.i18n.dart b/refilc_desktop_ui/lib/pages/home/home_page.i18n.dart deleted file mode 100644 index 2362b96..0000000 --- a/refilc_desktop_ui/lib/pages/home/home_page.i18n.dart +++ /dev/null @@ -1,63 +0,0 @@ -import 'package:i18n_extension/i18n_extension.dart'; - -extension Localization on String { - static final _t = Translations.byLocale("hu_hu") + - { - "en_en": { - "goodmorning": "Good morning, %s!", - "goodafternoon": "Good afternoon, %s!", - "goodevening": "Good evening, %s!", - "goodrest": "⛱️ Have a nice holiday, %s!", - "happybirthday": "🎂 Happy birthday, %s!", - "merryxmas": "🎄 Merry Christmas, %s!", - "happynewyear": "🎉 Happy New Year, %s!", - "empty": "Nothing to see here.", - "All": "All", - "Grades": "Grades", - "Messages": "Messages", - "Absences": "Absences", - "update_available": "Update Available", - "missed_exams": "You missed %s exams this week.".one("You missed an exam this week."), - "missed_exam_contact": "Contact %s, to resolve it!", - }, - "hu_hu": { - "goodmorning": "Jó reggelt, %s!", - "goodafternoon": "Szép napot, %s!", - "goodevening": "Szép estét, %s!", - "goodrest": "⛱️ Jó szünetet, %s!", - "happybirthday": "🎂 Boldog születésnapot, %s!", - "merryxmas": "🎄 Boldog Karácsonyt, %s!", - "happynewyear": "🎉 Boldog új évet, %s!", - "empty": "Nincs itt semmi látnivaló.", - "All": "Összes", - "Grades": "Jegyek", - "Messages": "Üzenetek", - "Absences": "Hiányok", - "update_available": "Frissítés elérhető", - "missed_exams": "Ezen a héten hiányoztál %s dolgozatról.".one("Ezen a héten hiányoztál egy dolgozatról."), - "missed_exam_contact": "Keresd %s-t, ha pótolni szeretnéd!", - }, - "de_de": { - "goodmorning": "Guten morgen, %s!", - "goodafternoon": "Guten Tag, %s!", - "goodevening": "Guten Abend, %s!", - "goodrest": "⛱️ Schöne Ferien, %s!", - "happybirthday": "🎂 Alles Gute zum Geburtstag, %s!", - "merryxmas": "🎄 Frohe Weihnachten, %s!", - "happynewyear": "🎉 Frohes neues Jahr, %s!", - "empty": "Hier gibt es nichts zu sehen.", - "All": "Alles", - "Grades": "Noten", - "Messages": "Nachrichten", - "Absences": "Fehlen", - "update_available": "Update verfügbar", - "missed_exams": "Diese Woche haben Sie %s Prüfungen verpasst.".one("Diese Woche haben Sie eine Prüfung verpasst."), - "missed_exam_contact": "Wenden Sie sich an %s, um sie zu erneuern!", - }, - }; - - String get i18n => localize(this, _t); - String fill(List params) => localizeFill(this, params); - String plural(int value) => localizePlural(value, this, _t); - String version(Object modifier) => localizeVersion(modifier, this, _t); -} diff --git a/refilc_desktop_ui/lib/pages/messages/messages_page.dart b/refilc_desktop_ui/lib/pages/messages/messages_page.dart deleted file mode 100644 index 9d0d997..0000000 --- a/refilc_desktop_ui/lib/pages/messages/messages_page.dart +++ /dev/null @@ -1,173 +0,0 @@ -import 'dart:math'; - -import 'package:refilc/api/providers/update_provider.dart'; -import 'package:refilc/ui/date_widget.dart'; -import 'package:refilc_kreta_api/providers/message_provider.dart'; -import 'package:refilc/api/providers/user_provider.dart'; -import 'package:refilc/theme/colors/colors.dart'; -import 'package:refilc_kreta_api/models/message.dart'; -import 'package:refilc_mobile_ui/common/empty.dart'; -import 'package:refilc_mobile_ui/common/filter_bar.dart'; -import 'package:refilc/ui/filter/sort.dart'; -import 'package:refilc_mobile_ui/common/widgets/message/message_viewable.dart'; -import 'package:flutter/material.dart'; -import 'package:provider/provider.dart'; -import 'messages_page.i18n.dart'; - -class MessagesPage extends StatefulWidget { - const MessagesPage({super.key}); - - @override - MessagesPageState createState() => MessagesPageState(); -} - -class MessagesPageState extends State - with TickerProviderStateMixin { - late UserProvider user; - late MessageProvider messageProvider; - late UpdateProvider updateProvider; - late String firstName; - late TabController tabController; - - @override - void initState() { - super.initState(); - - tabController = TabController(length: 4, vsync: this); - } - - @override - Widget build(BuildContext context) { - user = Provider.of(context); - messageProvider = Provider.of(context); - updateProvider = Provider.of(context); - - List nameParts = user.displayName?.split(" ") ?? ["?"]; - firstName = nameParts.length > 1 ? nameParts[1] : nameParts[0]; - - return Scaffold( - body: Padding( - padding: const EdgeInsets.only(top: 12.0), - child: NestedScrollView( - physics: const BouncingScrollPhysics( - parent: AlwaysScrollableScrollPhysics()), - headerSliverBuilder: (context, _) => [ - SliverAppBar( - pinned: true, - floating: false, - snap: false, - centerTitle: false, - automaticallyImplyLeading: false, - shadowColor: Theme.of(context).shadowColor, - surfaceTintColor: Theme.of(context).scaffoldBackgroundColor, - title: Padding( - padding: const EdgeInsets.only(left: 8.0), - child: Text( - "Messages".i18n, - style: TextStyle( - color: AppColors.of(context).text, - fontSize: 32.0, - fontWeight: FontWeight.bold), - ), - ), - bottom: FilterBar( - items: [ - Tab(text: "Inbox".i18n), - Tab(text: "Sent".i18n), - Tab(text: "Trash".i18n), - Tab(text: "Draft".i18n), - ], - controller: tabController, - disableFading: true, - ), - ), - ], - body: TabBarView( - physics: const BouncingScrollPhysics(), - controller: tabController, - children: List.generate( - 4, (index) => filterViewBuilder(context, index))), - ), - ), - ); - } - - List getFilterWidgets(MessageType activeData) { - List items = []; - switch (activeData) { - case MessageType.inbox: - for (var message in messageProvider.messages) { - if (message.type == MessageType.inbox) { - items.add(DateWidget( - date: message.date, - widget: MessageViewable(message), - )); - } - } - break; - case MessageType.sent: - for (var message in messageProvider.messages) { - if (message.type == MessageType.sent) { - items.add(DateWidget( - date: message.date, - widget: MessageViewable(message), - )); - } - } - break; - case MessageType.trash: - for (var message in messageProvider.messages) { - if (message.type == MessageType.trash) { - items.add(DateWidget( - date: message.date, - widget: MessageViewable(message), - )); - } - } - break; - case MessageType.draft: - for (var message in messageProvider.messages) { - if (message.type == MessageType.draft) { - items.add(DateWidget( - date: message.date, - widget: MessageViewable(message), - )); - } - } - break; - } - return items; - } - - Widget filterViewBuilder(context, int activeData) { - List filterWidgets = sortDateWidgets(context, - dateWidgets: getFilterWidgets(MessageType.values[activeData]), - hasShadow: true); - - return Padding( - padding: const EdgeInsets.only(top: 12.0), - child: RefreshIndicator( - color: Theme.of(context).colorScheme.secondary, - onRefresh: () { - return Future.wait([ - messageProvider.fetch(type: MessageType.inbox), - messageProvider.fetch(type: MessageType.sent), - messageProvider.fetch(type: MessageType.trash), - ]); - }, - child: ListView.builder( - padding: EdgeInsets.zero, - physics: const BouncingScrollPhysics(), - itemBuilder: (context, index) => filterWidgets.isNotEmpty - ? Padding( - padding: const EdgeInsets.symmetric( - horizontal: 24.0, vertical: 6.0), - child: filterWidgets[index], - ) - : Empty(subtitle: "empty".i18n), - itemCount: max(filterWidgets.length, 1), - ), - ), - ); - } -} diff --git a/refilc_desktop_ui/lib/pages/messages/messages_page.i18n.dart b/refilc_desktop_ui/lib/pages/messages/messages_page.i18n.dart deleted file mode 100644 index b1665e1..0000000 --- a/refilc_desktop_ui/lib/pages/messages/messages_page.i18n.dart +++ /dev/null @@ -1,36 +0,0 @@ -import 'package:i18n_extension/i18n_extension.dart'; - -extension Localization on String { - static final _t = Translations.byLocale("hu_hu") + - { - "en_en": { - "Messages": "Messages", - "Inbox": "Inbox", - "Sent": "Sent", - "Trash": "Trash", - "Draft": "Draft", - "empty": "You have no messages.", - }, - "hu_hu": { - "Messages": "Üzenetek", - "Inbox": "Beérkezett", - "Sent": "Elküldött", - "Trash": "Kuka", - "Draft": "Piszkozat", - "empty": "Nincsenek üzeneteid.", - }, - "de_de": { - "Messages": "Nachrichten", - "Inbox": "Posteingang", - "Sent": "Gesendet", - "Trash": "Müll", - "Draft": "Entwurf", - "empty": "Sie haben keine Nachrichten.", - }, - }; - - String get i18n => localize(this, _t); - String fill(List params) => localizeFill(this, params); - String plural(int value) => localizePlural(value, this, _t); - String version(Object modifier) => localizeVersion(modifier, this, _t); -} diff --git a/refilc_desktop_ui/lib/pages/timetable/timetable_page.dart b/refilc_desktop_ui/lib/pages/timetable/timetable_page.dart deleted file mode 100644 index 0729a70..0000000 --- a/refilc_desktop_ui/lib/pages/timetable/timetable_page.dart +++ /dev/null @@ -1,378 +0,0 @@ -import 'dart:math'; -import 'package:animations/animations.dart'; -import 'package:refilc/api/providers/update_provider.dart'; -import 'package:refilc/theme/colors/colors.dart'; -import 'package:refilc_kreta_api/client/client.dart'; -import 'package:refilc_kreta_api/models/week.dart'; -import 'package:refilc_kreta_api/providers/timetable_provider.dart'; -import 'package:refilc/api/providers/user_provider.dart'; -import 'package:refilc_kreta_api/models/lesson.dart'; -import 'package:refilc_mobile_ui/common/empty.dart'; -import 'package:refilc_mobile_ui/common/panel/panel.dart'; -import 'package:refilc_kreta_api/controllers/timetable_controller.dart'; -import 'package:refilc_desktop_ui/common/widgets/lesson/lesson_viewable.dart'; -import 'package:flutter/cupertino.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_feather_icons/flutter_feather_icons.dart'; -import 'package:provider/provider.dart'; -import 'package:refilc/utils/format.dart'; -import 'package:intl/intl.dart'; -import 'package:i18n_extension/i18n_extension.dart'; -import 'timetable_page.i18n.dart'; - -// todo: "fix" overflow (priority: -1) - -class TimetablePage extends StatefulWidget { - const TimetablePage({super.key, this.initialDay, this.initialWeek}); - - final DateTime? initialDay; - final Week? initialWeek; - - static void jump(BuildContext context, - {Week? week, DateTime? day, Lesson? lesson}) { - // Go to timetable page with arguments - // NavigationScreen.of(context)?.customRoute(navigationPageRoute((context) => TimetablePage( - // initialDay: lesson?.date ?? day, - // initialWeek: lesson?.date != null - // ? Week.fromDate(lesson!.date) - // : day != null - // ? Week.fromDate(day) - // : week, - // ))); - - // NavigationScreen.of(context)?.setPage("timetable"); - - // Show initial Lesson - // if (lesson != null) LessonView.show(lesson, context: context); - } - - @override - TimetablePageState createState() => TimetablePageState(); -} - -class TimetablePageState extends State - with TickerProviderStateMixin { - late UserProvider user; - late TimetableProvider timetableProvider; - late UpdateProvider updateProvider; - late String firstName; - late TimetableController _controller; - late TabController _tabController; - late Widget empty; - - int _getDayIndex(DateTime date) { - int index = 0; - if (_controller.days == null || (_controller.days?.isEmpty ?? true)) { - return index; - } - - // find the first day with upcoming lessons - index = _controller.days!.indexWhere((day) => day.last.end.isAfter(date)); - if (index == -1) index = 0; // fallback - - return index; - } - - // Update timetable on user change - Future _userListener() async { - await Provider.of(context, listen: false).refreshLogin(); - if (mounted) _controller.jump(_controller.currentWeek, context: context); - } - - @override - void initState() { - super.initState(); - - // Initalize controllers - _controller = TimetableController(); - _tabController = TabController(length: 0, vsync: this, initialIndex: 0); - - empty = Empty(subtitle: "empty".i18n); - - bool initial = true; - - // Only update the TabController on week changes - _controller.addListener(() { - if (_controller.days == null) return; - setState(() { - _tabController = TabController( - length: _controller.days!.length, - vsync: this, - initialIndex: - min(_tabController.index, max(_controller.days!.length - 1, 0)), - ); - - if (initial || - _controller.previousWeekId != _controller.currentWeekId) { - _tabController - .animateTo(_getDayIndex(widget.initialDay ?? DateTime.now())); - } - initial = false; - - // Empty is updated once every week change - empty = Empty(subtitle: "empty".i18n); - }); - }); - - if (mounted) { - if (widget.initialWeek != null) { - _controller.jump(widget.initialWeek!, context: context, initial: true); - } else { - _controller.jump(_controller.currentWeek, - context: context, initial: true, skip: true); - } - } - // Listen for user changes - user = Provider.of(context, listen: false); - user.addListener(_userListener); - } - - @override - void dispose() { - _tabController.dispose(); - _controller.dispose(); - user.removeListener(_userListener); - super.dispose(); - } - - String dayTitle(int index) { - // Sometimes when changing weeks really fast, - // controller.days might be null or won't include index - try { - return DateFormat("EEEE", I18n.of(context).locale.languageCode) - .format(_controller.days![index].first.date); - } catch (e) { - return "timetable".i18n; - } - } - - @override - Widget build(BuildContext context) { - user = Provider.of(context); - timetableProvider = Provider.of(context); - updateProvider = Provider.of(context); - - // First name - List nameParts = user.name?.split(" ") ?? ["?"]; - firstName = nameParts.length > 1 ? nameParts[1] : nameParts[0]; - - return Scaffold( - body: Padding( - padding: const EdgeInsets.only(top: 18.0), - child: Column( - children: [ - Expanded( - child: PageTransitionSwitcher( - transitionBuilder: ( - Widget child, - Animation primaryAnimation, - Animation secondaryAnimation, - ) { - return FadeThroughTransition( - animation: primaryAnimation, - secondaryAnimation: secondaryAnimation, - fillColor: Theme.of(context).scaffoldBackgroundColor, - child: child, - ); - }, - child: _controller.days != null - ? - // Week view - _tabController.length > 0 - ? CupertinoScrollbar( - child: ListView.builder( - scrollDirection: Axis.horizontal, - itemCount: _controller.days!.length, - itemBuilder: (context, tab) => SizedBox( - width: 400, - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - // Day Title - Padding( - padding: const EdgeInsets.only( - left: 24.0, - right: 28.0, - top: 18.0, - bottom: 8.0), - child: Row( - mainAxisAlignment: - MainAxisAlignment.spaceBetween, - children: [ - Text( - dayTitle(tab).capital(), - style: const TextStyle( - fontSize: 32.0, - fontWeight: FontWeight.w600, - ), - ), - Text( - "${"${_controller.days![tab].first.date.day}" - .padLeft(2, '0')}.", - style: TextStyle( - color: AppColors.of(context) - .text - .withOpacity(.5), - fontWeight: FontWeight.w500, - ), - ), - ], - ), - ), - - // Lessons - Expanded( - child: ListView.builder( - padding: EdgeInsets.zero, - physics: const BouncingScrollPhysics(), - itemCount: - _controller.days![tab].length + 2, - itemBuilder: (context, index) { - if (_controller.days == null) { - return Container(); - } - - // Header - if (index == 0) { - return const Padding( - padding: EdgeInsets.only( - top: 8.0, - left: 24.0, - right: 24.0), - child: PanelHeader( - padding: EdgeInsets.only( - top: 12.0)), - ); - } - - // Footer - if (index == - _controller.days![tab].length + - 1) { - return const Padding( - padding: EdgeInsets.only( - bottom: 8.0, - left: 24.0, - right: 24.0), - child: PanelFooter( - padding: EdgeInsets.only( - top: 12.0)), - ); - } - - // Body - final Lesson lesson = - _controller.days![tab][index - 1]; - final bool swapDescDay = _controller - .days![tab] - .map( - (l) => l.swapDesc ? 1 : 0) - .reduce((a, b) => a + b) >= - _controller.days![tab].length * - .5; - - return Padding( - padding: const EdgeInsets.symmetric( - horizontal: 24.0), - child: PanelBody( - padding: - const EdgeInsets.symmetric( - horizontal: 10.0), - child: LessonViewable( - lesson, - swapDesc: swapDescDay, - ), - ), - ); - }, - ), - ), - ], - ), - ), - ), - ) - - // Empty week - : Expanded( - child: Center(child: empty), - ) - : Center( - child: CircularProgressIndicator( - color: Theme.of(context).colorScheme.secondary, - ), - ), - ), - ), - Padding( - padding: - const EdgeInsets.symmetric(horizontal: 12.0, vertical: 8.0), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - // Previous week - IconButton( - onPressed: _controller.currentWeekId == 0 - ? null - : () => setState(() { - _controller.previous(context); - }), - splashRadius: 24.0, - icon: const Icon(FeatherIcons.chevronLeft), - color: Theme.of(context).colorScheme.secondary), - - // Week selector - InkWell( - borderRadius: BorderRadius.circular(6.0), - onTap: () => setState(() { - _controller.current(); - if (mounted) { - _controller.jump(_controller.currentWeek, - context: context, - loader: _controller.currentWeekId != - _controller.previousWeekId); - } - }), - child: Padding( - padding: const EdgeInsets.all(8.0), - child: Text( - "${_controller.currentWeekId + 1}. ${"week".i18n} (${DateFormat( - "${_controller.currentWeek.start.year != - DateTime.now().year - ? "yy. " - : ""}MMM d.", - I18n.of(context).locale.languageCode) - .format(_controller.currentWeek.start)} - ${DateFormat( - "${_controller.currentWeek.start.year != - DateTime.now().year - ? "yy. " - : ""}MMM d.", - I18n.of(context).locale.languageCode) - .format(_controller.currentWeek.end)})", - style: const TextStyle( - fontWeight: FontWeight.w500, - fontSize: 14.0, - ), - ), - ), - ), - - // Next week - IconButton( - onPressed: _controller.currentWeekId == 51 - ? null - : () => setState(() { - _controller.next(context); - }), - splashRadius: 24.0, - icon: const Icon(FeatherIcons.chevronRight), - color: Theme.of(context).colorScheme.secondary), - ], - ), - ), - ], - ), - ), - ); - } -} diff --git a/refilc_desktop_ui/lib/pages/timetable/timetable_page.i18n.dart b/refilc_desktop_ui/lib/pages/timetable/timetable_page.i18n.dart deleted file mode 100644 index 75d3bd0..0000000 --- a/refilc_desktop_ui/lib/pages/timetable/timetable_page.i18n.dart +++ /dev/null @@ -1,30 +0,0 @@ -import 'package:i18n_extension/i18n_extension.dart'; - -extension Localization on String { - static final _t = Translations.byLocale("hu_hu") + - { - "en_en": { - "timetable": "Timetable", - "empty": "No school this week!", - "week": "Week", - "error": "Failed to fetch timetable!", - }, - "hu_hu": { - "timetable": "Órarend", - "empty": "Ezen a héten nincs iskola.", - "week": "Hét", - "error": "Nem sikerült lekérni az órarendet!", - }, - "de_de": { - "timetable": "Zeitplan", - "empty": "Keine Schule diese Woche.", - "week": "Woche", - "error": "Der Fahrplan konnte nicht abgerufen werden!", - }, - }; - - String get i18n => localize(this, _t); - String fill(List params) => localizeFill(this, params); - String plural(int value) => localizePlural(value, this, _t); - String version(Object modifier) => localizeVersion(modifier, this, _t); -} diff --git a/refilc_desktop_ui/lib/screens/login/login_route.dart b/refilc_desktop_ui/lib/screens/login/login_route.dart deleted file mode 100644 index f6f5452..0000000 --- a/refilc_desktop_ui/lib/screens/login/login_route.dart +++ /dev/null @@ -1,17 +0,0 @@ -import 'package:animations/animations.dart'; -import 'package:flutter/material.dart'; - -Route loginRoute(Widget widget) { - return PageRouteBuilder( - pageBuilder: (context, animation, secondaryAnimation) => widget, - transitionDuration: const Duration(milliseconds: 650), - transitionsBuilder: (context, animation, secondaryAnimation, child) { - return FadeThroughTransition( - fillColor: Colors.transparent, - animation: animation, - secondaryAnimation: secondaryAnimation, - child: child, - ); - }, - ); -} diff --git a/refilc_desktop_ui/lib/screens/login/login_screen.dart b/refilc_desktop_ui/lib/screens/login/login_screen.dart deleted file mode 100644 index 892db46..0000000 --- a/refilc_desktop_ui/lib/screens/login/login_screen.dart +++ /dev/null @@ -1,358 +0,0 @@ -import 'dart:io'; -import 'dart:ui'; - -import 'package:elegant_notification/elegant_notification.dart'; -import 'package:elegant_notification/resources/arrays.dart'; -import 'package:refilc/api/client.dart'; -import 'package:refilc/api/login.dart'; -import 'package:refilc_mobile_ui/screens/login/login_button.dart'; -import 'package:refilc_mobile_ui/screens/login/login_input.dart'; -import 'package:refilc_desktop_ui/screens/login/school_input/school_input.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; -import 'package:flutter_acrylic/flutter_acrylic.dart'; -import 'login_screen.i18n.dart'; - -const LinearGradient _backgroundGradient = LinearGradient( - colors: [ - Color.fromARGB(255, 61, 122, 244), - Color.fromARGB(255, 23, 77, 185), - Color.fromARGB(255, 7, 42, 112), - ], - begin: Alignment(-0.8, -2.0), - end: Alignment(0.8, 1.0), - stops: [-1.0, 0.0, 1.0], -); - -class LoginScreen extends StatefulWidget { - const LoginScreen({super.key, this.back = false}); - - final bool back; - - @override - LoginScreenState createState() => LoginScreenState(); -} - -class LoginScreenState extends State { - final usernameController = TextEditingController(); - final passwordController = TextEditingController(); - final schoolController = SchoolInputController(); - final _scrollController = ScrollController(); - - LoginState _loginState = LoginState.normal; - bool showBack = false; - double topInset = 12.0; - - @override - void initState() { - super.initState(); - showBack = widget.back; - - SystemChrome.setSystemUIOverlayStyle(const SystemUiOverlayStyle( - statusBarColor: Colors.transparent, - statusBarIconBrightness: Brightness.light, - systemNavigationBarColor: Colors.white, - systemNavigationBarIconBrightness: Brightness.dark, - )); - - FilcAPI.getSchools().then((schools) { - if (schools != null) { - schoolController.update(() { - schoolController.schools = schools; - }); - } else { - ElegantNotification.error( - background: Colors.white, - description: Text( - "schools_error".i18n, - overflow: TextOverflow.ellipsis, - style: const TextStyle(color: Colors.red), - ), - // onActionPressed: () {}, - onCloseButtonPressed: () {}, - onDismiss: () {}, - onProgressFinished: () {}, - displayCloseButton: false, - showProgressIndicator: false, - autoDismiss: true, - animation: AnimationType.fromTop, - ).show(context); - } - }); - - if (Platform.isMacOS) { - Window.getTitlebarHeight() - .then((value) => setState(() => topInset = value)); - } - } - - @override - Widget build(BuildContext context) { - return Scaffold( - body: Container( - decoration: const BoxDecoration( - gradient: _backgroundGradient, - ), - child: SafeArea( - child: Stack( - children: [ - Row( - children: [ - Expanded( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - // App logo - Padding( - padding: const EdgeInsets.only(bottom: 24.0), - child: ClipRect( - child: Padding( - padding: const EdgeInsets.only( - left: 12.0, right: 12.0, bottom: 32.0), - child: SizedBox( - width: 100.0, - height: 100.0, - // Png shadow *hack* - child: Stack( - children: [ - Padding( - padding: const EdgeInsets.only(top: 8.0), - child: Opacity( - opacity: 0.3, - child: Image.asset( - "assets/icons/ic_splash.png", - color: Colors.black)), - ), - BackdropFilter( - filter: ImageFilter.blur( - sigmaX: 6.0, sigmaY: 6.0), - child: Image.asset( - "assets/icons/ic_splash.png"), - ) - ], - ), - ), - ), - ), - ), - - // Inputs - SizedBox( - width: 400.0, - child: AutofillGroup( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - // Username - Padding( - padding: const EdgeInsets.only(bottom: 6.0), - child: Row( - mainAxisAlignment: - MainAxisAlignment.spaceBetween, - children: [ - Expanded( - child: Text( - "username".i18n, - maxLines: 1, - style: const TextStyle( - color: Colors.white, - fontWeight: FontWeight.w600, - fontSize: 14.0, - ), - ), - ), - Expanded( - child: Text( - "usernameHint".i18n, - maxLines: 1, - textAlign: TextAlign.right, - style: const TextStyle( - color: Colors.white54, - fontWeight: FontWeight.w500, - fontSize: 12.0, - ), - ), - ), - ], - ), - ), - Padding( - padding: const EdgeInsets.only(bottom: 12.0), - child: LoginInput( - style: LoginInputStyle.username, - controller: usernameController, - ), - ), - - // Password - Padding( - padding: const EdgeInsets.only(bottom: 6.0), - child: Row( - mainAxisAlignment: - MainAxisAlignment.spaceBetween, - children: [ - Expanded( - child: Text( - "password".i18n, - maxLines: 1, - style: const TextStyle( - color: Colors.white, - fontWeight: FontWeight.w600, - fontSize: 14.0, - ), - ), - ), - Expanded( - child: Text( - "passwordHint".i18n, - maxLines: 1, - textAlign: TextAlign.right, - style: const TextStyle( - color: Colors.white54, - fontWeight: FontWeight.w500, - fontSize: 12.0, - ), - ), - ), - ], - ), - ), - Padding( - padding: const EdgeInsets.only(bottom: 12.0), - child: LoginInput( - style: LoginInputStyle.password, - controller: passwordController, - ), - ), - - // School - Padding( - padding: const EdgeInsets.only(bottom: 6.0), - child: Text( - "school".i18n, - maxLines: 1, - style: const TextStyle( - color: Colors.white, - fontWeight: FontWeight.w600, - fontSize: 14.0, - ), - ), - ), - SchoolInput( - scroll: _scrollController, - controller: schoolController, - ), - ], - ), - ), - ), - - // Log in button - SizedBox( - width: 400.0, - child: Padding( - padding: const EdgeInsets.only(top: 42.0), - child: Visibility( - visible: _loginState != LoginState.inProgress, - replacement: const Padding( - padding: EdgeInsets.symmetric(vertical: 6.0), - child: Center( - child: CircularProgressIndicator( - valueColor: AlwaysStoppedAnimation( - Colors.white), - ), - ), - ), - child: LoginButton( - child: Text("login".i18n, - maxLines: 1, - style: const TextStyle( - fontWeight: FontWeight.w600, - fontSize: 15.0, - )), - onPressed: () => _loginAPI(context: context), - ), - ), - ), - ), - if (_loginState == LoginState.missingFields || - _loginState == LoginState.invalidGrant || - _loginState == LoginState.failed) - Padding( - padding: const EdgeInsets.only(top: 8.0), - child: Text( - [ - "missing_fields", - "invalid_grant", - "error" - ][_loginState.index] - .i18n, - style: const TextStyle( - color: Colors.red, - fontWeight: FontWeight.w500), - ), - ), - ], - ), - ), - ], - ), - if (showBack) - Container( - alignment: Alignment.topLeft, - padding: EdgeInsets.only(left: 16.0, top: topInset), - child: const ClipOval( - child: Material( - type: MaterialType.transparency, - child: BackButton(color: Colors.white), - ), - ), - ), - ], - ), - ), - ), - ); - } - - void _loginAPI({required BuildContext context}) { - String username = usernameController.text; - String password = passwordController.text; - - if (username == "" || - password == "" || - schoolController.selectedSchool == null) { - return setState(() => _loginState = LoginState.missingFields); - } - - setState(() => _loginState = LoginState.inProgress); - - loginAPI( - username: username, - password: password, - instituteCode: schoolController.selectedSchool!.instituteCode, - context: context, - onLogin: (user) { - ElegantNotification.success( - background: Colors.white, - description: Text( - "welcome".i18n.fill([user.name]), - overflow: TextOverflow.ellipsis, - style: const TextStyle(color: Colors.black), - ), - // onActionPressed: () {}, - onCloseButtonPressed: () {}, - onDismiss: () {}, - onProgressFinished: () {}, - displayCloseButton: false, - showProgressIndicator: false, - autoDismiss: true, - animation: AnimationType.fromTop, - ).show(context); - }, - onSuccess: () { - Navigator.of(context) - .pushNamedAndRemoveUntil("login_to_navigation", (_) => false); - }).then((res) => setState(() => _loginState = res)); - } -} diff --git a/refilc_desktop_ui/lib/screens/login/login_screen.i18n.dart b/refilc_desktop_ui/lib/screens/login/login_screen.i18n.dart deleted file mode 100644 index f463081..0000000 --- a/refilc_desktop_ui/lib/screens/login/login_screen.i18n.dart +++ /dev/null @@ -1,51 +0,0 @@ -import 'package:i18n_extension/i18n_extension.dart'; - -extension Localization on String { - static final _t = Translations.byLocale("hu_hu") + - { - "en_en": { - "username": "Username", - "usernameHint": "Student ID number", - "password": "Password", - "passwordHint": "Date of birth", - "school": "School", - "login": "Log in", - "welcome": "Welcome, %s!", - "missing_fields": "Missing Fields!", - "invalid_grant": "Invalid Username/Password!", - "error": "Failed to log in.", - "schools_error": "Failed to get schools." - }, - "hu_hu": { - "username": "Felhasználónév", - "usernameHint": "Oktatási azonosító", - "password": "Jelszó", - "passwordHint": "Születési dátum", - "school": "Iskola", - "login": "Belépés", - "welcome": "Üdv, %s!", - "missing_fields": "Hiányzó adatok!", - "invalid_grant": "Helytelen Felhasználónév/Jelszó!", - "error": "Sikertelen bejelentkezés.", - "schools_error": "Nem sikerült lekérni az iskolákat." - }, - "de_de": { - "username": "Benutzername", - "usernameHint": "Ausbildung ID", - "password": "Passwort", - "passwordHint": "Geburtsdatum", - "school": "Schule", - "login": "Einloggen", - "welcome": "Wilkommen, %s!", - "missing_fields": "Fehlende Felder!", - "invalid_grant": "Ungültiger Benutzername/Passwort!", - "error": "Anmeldung fehlgeschlagen.", - "schools_error": "Keine Schulen gefunden." - }, - }; - - String get i18n => localize(this, _t); - String fill(List params) => localizeFill(this, params); - String plural(int value) => localizePlural(value, this, _t); - String version(Object modifier) => localizeVersion(modifier, this, _t); -} diff --git a/refilc_desktop_ui/lib/screens/login/school_input/school_input.dart b/refilc_desktop_ui/lib/screens/login/school_input/school_input.dart deleted file mode 100644 index 7422b0a..0000000 --- a/refilc_desktop_ui/lib/screens/login/school_input/school_input.dart +++ /dev/null @@ -1,121 +0,0 @@ -import 'package:refilc_mobile_ui/screens/login/login_input.dart'; -import 'package:refilc_mobile_ui/screens/login/school_input/school_input_overlay.dart'; -import 'package:refilc_desktop_ui/screens/login/school_input/school_input_tile.dart'; -import 'package:refilc_mobile_ui/screens/login/school_input/school_search.dart'; -import 'package:flutter/material.dart'; -import 'package:refilc_kreta_api/models/school.dart'; - -class SchoolInput extends StatefulWidget { - const SchoolInput({super.key, required this.controller, required this.scroll}); - - final SchoolInputController controller; - final ScrollController scroll; - - @override - SchoolInputState createState() => SchoolInputState(); -} - -class SchoolInputState extends State { - final _focusNode = FocusNode(); - final _layerLink = LayerLink(); - late SchoolInputOverlay overlay; - - @override - void initState() { - super.initState(); - - widget.controller.update = (fn) { - if (mounted) setState(fn); - }; - - overlay = SchoolInputOverlay(layerLink: _layerLink); - - // Show school list when focused - _focusNode.addListener(() { - if (_focusNode.hasFocus) { - WidgetsBinding.instance - .addPostFrameCallback((_) => overlay.createOverlayEntry(context)); - Future.delayed(const Duration(milliseconds: 100)).then((value) { - if (mounted && widget.scroll.hasClients) { - widget.scroll.animateTo(widget.scroll.offset + 500, - duration: const Duration(milliseconds: 500), - curve: Curves.ease); - } - }); - } else { - overlay.entry?.remove(); - } - }); - - // LoginInput TextField listener - widget.controller.textController.addListener(() { - String text = widget.controller.textController.text; - if (text.isEmpty) { - overlay.children = null; - return; - } - - List results = - searchSchools(widget.controller.schools ?? [], text); - setState(() { - overlay.children = results - .map((School e) => SchoolInputTile( - school: e, - onTap: () => _selectSchool(e), - )) - .toList(); - }); - Overlay.of(context).setState(() {}); - }); - } - - void _selectSchool(School school) { - FocusScope.of(context).requestFocus(FocusNode()); - - setState(() { - widget.controller.selectedSchool = school; - widget.controller.textController.text = school.name; - }); - } - - @override - Widget build(BuildContext context) { - return CompositedTransformTarget( - link: _layerLink, - child: widget.controller.schools == null - ? Container( - width: double.infinity, - padding: const EdgeInsets.symmetric(vertical: 10.0), - decoration: BoxDecoration( - color: Colors.black.withOpacity(0.15), - borderRadius: BorderRadius.circular(12.0), - ), - child: const Center( - child: SizedBox( - height: 28.0, - width: 28.0, - child: CircularProgressIndicator( - color: Colors.white, - ), - ), - ), - ) - : LoginInput( - style: LoginInputStyle.school, - focusNode: _focusNode, - onClear: () { - widget.controller.selectedSchool = null; - FocusScope.of(context).requestFocus(_focusNode); - }, - controller: widget.controller.textController, - ), - ); - } -} - -class SchoolInputController { - final textController = TextEditingController(); - School? selectedSchool; - List? schools; - late void Function(void Function()) update; -} diff --git a/refilc_desktop_ui/lib/screens/login/school_input/school_input_tile.dart b/refilc_desktop_ui/lib/screens/login/school_input/school_input_tile.dart deleted file mode 100644 index 6b0c05c..0000000 --- a/refilc_desktop_ui/lib/screens/login/school_input/school_input_tile.dart +++ /dev/null @@ -1,64 +0,0 @@ -import 'package:refilc_kreta_api/models/school.dart'; -import 'package:flutter/material.dart'; - -class SchoolInputTile extends StatelessWidget { - const SchoolInputTile({super.key, required this.school, this.onTap}); - - final School school; - final Function()? onTap; - - @override - Widget build(BuildContext context) { - return Padding( - padding: const EdgeInsets.all(4.0), - child: GestureDetector( - onPanDown: (e) { - onTap!(); - }, - child: InkWell( - onTapDown: (e) {}, - borderRadius: BorderRadius.circular(6.0), - child: Padding( - padding: const EdgeInsets.all(6.0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - // School name - Padding( - padding: const EdgeInsets.only(bottom: 4.0), - child: Text( - school.name, - maxLines: 2, - overflow: TextOverflow.ellipsis, - style: const TextStyle(fontWeight: FontWeight.w600), - ), - ), - Row( - children: [ - // School id - Expanded( - child: Text( - school.instituteCode, - maxLines: 1, - overflow: TextOverflow.ellipsis, - ), - ), - // School city - Expanded( - child: Text( - school.city, - textAlign: TextAlign.right, - maxLines: 1, - overflow: TextOverflow.ellipsis, - ), - ), - ], - ), - ], - ), - ), - ), - ), - ); - } -} diff --git a/refilc_desktop_ui/lib/screens/navigation/navigation_route.dart b/refilc_desktop_ui/lib/screens/navigation/navigation_route.dart deleted file mode 100644 index 79778aa..0000000 --- a/refilc_desktop_ui/lib/screens/navigation/navigation_route.dart +++ /dev/null @@ -1,25 +0,0 @@ -class NavigationRoute { - late String _name; - late int _index; - - final List _internalPageMap = [ - "home", - "grades", - "timetable", - "messages", - "absences", - ]; - - String get name => _name; - int get index => _index; - - set name(String n) { - _name = n; - _index = _internalPageMap.indexOf(n); - } - - set index(int i) { - _index = i; - _name = _internalPageMap.elementAt(i); - } -} diff --git a/refilc_desktop_ui/lib/screens/navigation/navigation_route_handler.dart b/refilc_desktop_ui/lib/screens/navigation/navigation_route_handler.dart deleted file mode 100644 index f7766d7..0000000 --- a/refilc_desktop_ui/lib/screens/navigation/navigation_route_handler.dart +++ /dev/null @@ -1,37 +0,0 @@ -import 'package:animations/animations.dart'; -import 'package:refilc_desktop_ui/pages/absences/absences_page.dart'; -import 'package:refilc_desktop_ui/pages/grades/grades_page.dart'; -import 'package:refilc_desktop_ui/pages/home/home_page.dart'; -import 'package:refilc_desktop_ui/pages/messages/messages_page.dart'; -import 'package:refilc_desktop_ui/pages/timetable/timetable_page.dart'; -import 'package:flutter/material.dart'; - -Route navigationRouteHandler(RouteSettings settings) { - switch (settings.name) { - case "grades": - return navigationPageRoute((context) => const GradesPage()); - case "timetable": - return navigationPageRoute((context) => const TimetablePage()); - case "messages": - return navigationPageRoute((context) => const MessagesPage()); - case "absences": - return navigationPageRoute((context) => const AbsencesPage()); - case "home": - default: - return navigationPageRoute((context) => const HomePage()); - } -} - -Route navigationPageRoute(Widget Function(BuildContext) builder) { - return PageRouteBuilder( - pageBuilder: (context, _, __) => builder(context), - transitionsBuilder: (context, animation, secondaryAnimation, child) { - return FadeThroughTransition( - fillColor: Theme.of(context).scaffoldBackgroundColor, - animation: animation, - secondaryAnimation: secondaryAnimation, - child: child, - ); - }, - ); -} diff --git a/refilc_desktop_ui/lib/screens/navigation/navigation_screen.dart b/refilc_desktop_ui/lib/screens/navigation/navigation_screen.dart deleted file mode 100644 index 2ce4eca..0000000 --- a/refilc_desktop_ui/lib/screens/navigation/navigation_screen.dart +++ /dev/null @@ -1,168 +0,0 @@ -import 'dart:io'; - -import 'package:refilc/api/providers/news_provider.dart'; -import 'package:refilc/api/providers/sync.dart'; -import 'package:refilc/theme/colors/colors.dart'; -import 'package:refilc/theme/observer.dart'; -import 'package:refilc_desktop_ui/screens/navigation/navigation_route.dart'; -import 'package:refilc_desktop_ui/screens/navigation/navigation_route_handler.dart'; -import 'package:refilc_desktop_ui/screens/navigation/sidebar.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_acrylic/flutter_acrylic.dart'; -import 'package:provider/provider.dart'; -import 'package:refilc/models/settings.dart'; -import 'package:refilc_kreta_api/client/client.dart'; -import 'package:refilc_plus/providers/goal_provider.dart'; - -class NavigationScreen extends StatefulWidget { - const NavigationScreen({super.key}); - - static NavigationScreenState? of(BuildContext context) => - context.findAncestorStateOfType(); - - @override - State createState() => NavigationScreenState(); -} - -class NavigationScreenState extends State - with WidgetsBindingObserver { - final _navigatorState = GlobalKey(); - late NavigationRoute selected; - late SettingsProvider settings; - late NewsProvider newsProvider; - late GoalProvider goalProvider; - double topInset = 0.0; - - @override - void initState() { - super.initState(); - settings = Provider.of(context, listen: false); - selected = NavigationRoute(); - selected.index = 0; - - // add brightness observer - WidgetsBinding.instance.addObserver(this); - - // set client User-Agent - Provider.of(context, listen: false).userAgent = - settings.config.userAgent; - - // get news - newsProvider = Provider.of(context, listen: false); - newsProvider.restore().then((value) => newsProvider.fetch()); - - // get goals - // goalProvider = Provider.of(context, listen: false); - // goalProvider.fetchDone(); - - // Initial sync - syncAll(context); - - // platform specific shit - () async { - try { - await Window.initialize(); - } catch (_) {} - // Transparent sidebar - if (Platform.isLinux) return; - - await Window.setEffect( - effect: Platform.isLinux - ? WindowEffect.transparent - : WindowEffect.acrylic, - color: Platform.isMacOS - ? Colors.transparent - : const Color.fromARGB(27, 27, 27, 27)); - - // todo: do for windows - if (Platform.isMacOS) { - topInset = await Window.getTitlebarHeight(); - await Window.enableFullSizeContentView(); - await Window.hideTitle(); - await Window.makeTitlebarTransparent(); - } - }(); - } - - @override - void dispose() { - WidgetsBinding.instance.removeObserver(this); - super.dispose(); - } - - @override - void didChangePlatformBrightness() { - if (settings.theme == ThemeMode.system) { - // ignore: deprecated_member_use - Brightness? brightness = - // ignore: deprecated_member_use - WidgetsBinding.instance.window.platformBrightness; - Provider.of(context, listen: false).changeTheme( - brightness == Brightness.light ? ThemeMode.light : ThemeMode.dark); - } - super.didChangePlatformBrightness(); - } - - void setPage(String page) => setState(() => selected.name = page); - - @override - Widget build(BuildContext context) { - settings = Provider.of(context); - newsProvider = Provider.of(context); - goalProvider = Provider.of(context); - - // show news / complete goals - WidgetsBinding.instance.addPostFrameCallback((_) { - if (newsProvider.show) { - newsProvider.lock(); - // NewsView.show(newsProvider.news[newsProvider.state], context: context).then((value) => newsProvider.release()); - } - if (goalProvider.hasDoneGoals) { - // to-do - } - }); - - return Scaffold( - backgroundColor: Colors.transparent, - body: Row( - children: [ - if (_navigatorState.currentState != null) - Container( - decoration: BoxDecoration( - color: - Theme.of(context).scaffoldBackgroundColor.withOpacity(.5), - border: Border( - right: BorderSide( - color: AppColors.of(context).shadow.withOpacity(.7), - width: 1.0)), - ), - child: Padding( - padding: EdgeInsets.only(top: topInset), - child: Sidebar( - navigator: _navigatorState.currentState!, - selected: selected.name, - onRouteChange: (name) => setPage(name), - ), - ), - ), - Expanded( - child: Container( - color: Theme.of(context).scaffoldBackgroundColor, - child: MediaQuery( - data: MediaQuery.of(context).copyWith( - padding: EdgeInsets.only(top: topInset), - ), - child: Navigator( - key: _navigatorState, - initialRoute: selected.name, - onGenerateRoute: (settings) => - navigationRouteHandler(settings), - ), - ), - ), - ), - ], - ), - ); - } -} diff --git a/refilc_desktop_ui/lib/screens/navigation/sidebar.dart b/refilc_desktop_ui/lib/screens/navigation/sidebar.dart deleted file mode 100644 index 7aebab2..0000000 --- a/refilc_desktop_ui/lib/screens/navigation/sidebar.dart +++ /dev/null @@ -1,356 +0,0 @@ -// ignore_for_file: no_leading_underscores_for_local_identifiers - -import 'package:animations/animations.dart'; -import 'package:refilc/api/providers/database_provider.dart'; -import 'package:refilc/api/providers/user_provider.dart'; -import 'package:refilc/icons/filc_icons.dart'; -import 'package:refilc/models/settings.dart'; -import 'package:refilc/utils/color.dart'; -import 'package:refilc_desktop_ui/common/panel_button.dart'; -import 'package:refilc_desktop_ui/common/profile_image.dart'; -import 'package:refilc_desktop_ui/screens/navigation/sidebar.i18n.dart'; -import 'package:refilc_desktop_ui/screens/navigation/sidebar_action.dart'; -import 'package:refilc_desktop_ui/screens/settings/settings_screen.dart'; -import 'package:refilc_mobile_ui/screens/settings/accounts/account_tile.dart'; -import 'package:refilc_kreta_api/client/client.dart'; -import 'package:refilc_kreta_api/providers/absence_provider.dart'; -import 'package:refilc_kreta_api/providers/event_provider.dart'; -import 'package:refilc_kreta_api/providers/exam_provider.dart'; -import 'package:refilc_kreta_api/providers/grade_provider.dart'; -import 'package:refilc_kreta_api/providers/homework_provider.dart'; -import 'package:refilc_kreta_api/providers/message_provider.dart'; -import 'package:refilc_kreta_api/providers/note_provider.dart'; -import 'package:refilc_kreta_api/providers/timetable_provider.dart'; -import 'package:flutter/cupertino.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_feather_icons/flutter_feather_icons.dart'; -import 'package:provider/provider.dart'; -import 'package:refilc/theme/colors/colors.dart'; - -class Sidebar extends StatefulWidget { - const Sidebar( - {super.key, - required this.navigator, - required this.onRouteChange, - this.selected = "home"}); - - final NavigatorState navigator; - final String selected; - final Function(String) onRouteChange; - - @override - State createState() => _SidebarState(); -} - -class _SidebarState extends State { - late UserProvider user; - late SettingsProvider settings; - late String firstName; - - String topNav = ""; - bool expandAccount = false; - List accountTiles = []; - - @override - void initState() { - super.initState(); - user = Provider.of(context, listen: false); - } - - Future restore() => Future.wait([ - Provider.of(context, listen: false).restore(), - Provider.of(context, listen: false).restoreUser(), - Provider.of(context, listen: false).restore(), - Provider.of(context, listen: false).restore(), - Provider.of(context, listen: false).restore(), - Provider.of(context, listen: false) - .restoreRecipients(), - Provider.of(context, listen: false).restore(), - Provider.of(context, listen: false).restore(), - Provider.of(context, listen: false).restore(), - Provider.of(context, listen: false).refreshLogin(), - ]); - - @override - Widget build(BuildContext context) { - user = Provider.of(context); - settings = Provider.of(context); - - List nameParts = user.name?.split(" ") ?? ["?"]; - if (!settings.presentationMode) { - firstName = nameParts.length > 1 ? nameParts[1] : nameParts[0]; - } else { - firstName = "János"; - } - - List pageWidgets = [ - SidebarAction( - title: Text("Home".i18n), - icon: const Icon(FilcIcons.home), - selected: widget.selected == "home", - onTap: () { - if (widget.selected != "home") { - widget.navigator.pushReplacementNamed("home"); - widget.onRouteChange("home"); - } - }, - ), - SidebarAction( - title: Text("Grades".i18n), - icon: const Icon(FeatherIcons.bookmark), - selected: widget.selected == "grades", - onTap: () { - if (widget.selected != "grades") { - widget.navigator.pushReplacementNamed("grades"); - widget.onRouteChange("grades"); - } - }, - ), - SidebarAction( - title: Text("Timetable".i18n), - icon: const Icon(FeatherIcons.calendar), - selected: widget.selected == "timetable", - onTap: () { - if (widget.selected != "timetable") { - widget.navigator.pushReplacementNamed("timetable"); - widget.onRouteChange("timetable"); - } - }, - ), - SidebarAction( - title: Text("Messages".i18n), - icon: const Icon(FeatherIcons.messageSquare), - selected: widget.selected == "messages", - onTap: () { - if (widget.selected != "messages") { - widget.navigator.pushReplacementNamed("messages"); - widget.onRouteChange("messages"); - } - }, - ), - SidebarAction( - title: Text("Absences".i18n), - icon: const Icon(FeatherIcons.clock), - selected: widget.selected == "absences", - onTap: () { - if (widget.selected != "absences") { - widget.navigator.pushReplacementNamed("absences"); - widget.onRouteChange("absences"); - } - }, - ), - ]; - - List bottomActions = [ - SidebarAction( - title: Text("Settings".i18n), - selected: true, - icon: const Icon(FeatherIcons.settings), - onTap: () { - if (topNav != "settings") { - widget.navigator - .push(CupertinoPageRoute( - builder: (context) => const SettingsScreen())) - .then((value) => topNav = ""); - topNav = "settings"; - } - }, - ), - ]; - - buildAccountTiles(); - - List accountWidgets = [ - Padding( - padding: const EdgeInsets.symmetric(horizontal: 12.0), - child: Column(children: accountTiles), - ), - - // Account settings - PanelButton( - onPressed: () { - Navigator.of(context).pushNamed("login_back"); - }, - title: Text("adduser".i18n), - leading: const Icon(FeatherIcons.userPlus), - ), - PanelButton( - onPressed: () async { - String? userId = user.id; - if (userId == null) return; - - // revoke refresh token - await Provider.of(context, listen: false).logout(); - - // delete user from app - user.removeUser(userId); - // ignore: use_build_context_synchronously - await Provider.of(context, listen: false) - .store - .removeUser(userId); - - // if no other users left, go back to login screen - if (user.getUsers().isNotEmpty) { - user.setUser(user.getUsers().first.id); - restore().then((_) => user.setUser(user.getUsers().first.id)); - } else { - // ignore: use_build_context_synchronously - Navigator.of(context) - .pushNamedAndRemoveUntil("login", (_) => false); - } - }, - title: Text("logout".i18n), - leading: Icon(FeatherIcons.logOut, color: AppColors.of(context).red), - ), - ]; - - return SizedBox( - height: double.infinity, - width: 250.0, - child: Column( - children: [ - Padding( - padding: const EdgeInsets.only( - left: 12.0, - top: 18.0, - bottom: 24.0, - right: 12.0, - ), - child: InkWell( - customBorder: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(10)), - onTap: () { - setState(() { - expandAccount = !expandAccount; - }); - }, - child: Row( - children: [ - Padding( - padding: const EdgeInsets.only( - right: 12.0, - left: 5.0, - top: 5.0, - bottom: 5.0, - ), - child: ProfileImage( - name: firstName, - radius: 18.0, - backgroundColor: Theme.of(context) - .colorScheme - .primary, //!settings.presentationMode - // ? ColorUtils.stringToColor(user.name ?? "?") - // : Theme.of(context).colorScheme.secondary, - ), - ), - Expanded( - child: Text( - firstName, - style: const TextStyle( - fontSize: 16.0, - fontWeight: FontWeight.w600, - ), - ), - ), - PageTransitionSwitcher( - transitionBuilder: - (child, primaryAnimation, secondaryAnimation) { - return FadeThroughTransition( - fillColor: Colors.transparent, - animation: primaryAnimation, - secondaryAnimation: secondaryAnimation, - child: child, - ); - }, - child: IconButton( - key: Key(expandAccount ? "accounts" : "pages"), - icon: Icon(expandAccount - ? FeatherIcons.chevronDown - : FeatherIcons.chevronRight), - padding: EdgeInsets.zero, - onPressed: () { - setState(() { - expandAccount = !expandAccount; - }); - }, - splashColor: const Color(0x00000000), - focusColor: const Color(0x00000000), - hoverColor: const Color(0x00000000), - highlightColor: const Color(0x00000000), - ), - ), - ], - ), - ), - ), - - // Pages - Expanded( - child: PageTransitionSwitcher( - duration: const Duration(milliseconds: 500), - transitionBuilder: (child, primaryAnimation, secondaryAnimation) { - return SharedAxisTransition( - fillColor: Colors.transparent, - animation: primaryAnimation, - secondaryAnimation: secondaryAnimation, - transitionType: SharedAxisTransitionType.scaled, - child: child, - ); - }, - child: !expandAccount - ? Column( - key: const Key("pages"), - children: pageWidgets, - ) - : Column( - key: const Key("accounts"), - children: accountWidgets, - ), - ), - ), - - // Settings - ...bottomActions, - - // Bottom padding - const SizedBox(height: 12.0), - ], - ), - ); - } - - void buildAccountTiles() { - accountTiles = []; - user.getUsers().forEach((account) { - if (account.id == user.id) return; - - String _firstName; - - List _nameParts = user.name?.split(" ") ?? ["?"]; - if (!settings.presentationMode) { - _firstName = _nameParts.length > 1 ? _nameParts[1] : _nameParts[0]; - } else { - _firstName = "János"; - } - - accountTiles.add(AccountTile( - name: Text(!settings.presentationMode ? account.name : "János", - style: const TextStyle(fontWeight: FontWeight.w500)), - username: - Text(!settings.presentationMode ? account.username : "72469696969"), - profileImage: ProfileImage( - name: _firstName, - backgroundColor: !settings.presentationMode - ? ColorUtils.stringToColor(account.name) - : Theme.of(context).colorScheme.secondary, - role: account.role, - ), - onTap: () { - user.setUser(account.id); - restore().then((_) => user.setUser(account.id)); - }, - // onTapMenu: () => _showBottomSheet(account), - )); - }); - } -} diff --git a/refilc_desktop_ui/lib/screens/navigation/sidebar.i18n.dart b/refilc_desktop_ui/lib/screens/navigation/sidebar.i18n.dart deleted file mode 100644 index 43cfb8a..0000000 --- a/refilc_desktop_ui/lib/screens/navigation/sidebar.i18n.dart +++ /dev/null @@ -1,42 +0,0 @@ -import 'package:i18n_extension/i18n_extension.dart'; - -extension SettingsLocalization on String { - static final _t = Translations.byLocale("hu_hu") + - { - "en_en": { - "Home": "Home", - "Grades": "Grades", - "Timetable": "Timetable", - "Messages": "Messages", - "Absences": "Absences", - "Settings": "Settings", - "adduser": "Add User", - "logout": "Log Out", - }, - "hu_hu": { - "Home": "Kezdőlap", - "Grades": "Jegyek", - "Timetable": "Órarend", - "Messages": "Üzenetek", - "Absences": "Hiányzások", - "Settings": "Beállítások", - "adduser": "Fiók hozzáadása", - "logout": "Kilépés", - }, - "de_de": { - "Home": "Zuhause", - "Grades": "Noten", - "Timetable": "Zeitplan", - "Messages": "Mitteilungen", - "Absences": "Fehlen", - "Settings": "Einstellungen", - "adduser": "Benutzer hinzufügen", - "logout": "Abmelden", - }, - }; - - String get i18n => localize(this, _t); - String fill(List params) => localizeFill(this, params); - String plural(int value) => localizePlural(value, this, _t); - String version(Object modifier) => localizeVersion(modifier, this, _t); -} diff --git a/refilc_desktop_ui/lib/screens/navigation/sidebar_action.dart b/refilc_desktop_ui/lib/screens/navigation/sidebar_action.dart deleted file mode 100644 index c718607..0000000 --- a/refilc_desktop_ui/lib/screens/navigation/sidebar_action.dart +++ /dev/null @@ -1,54 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:refilc/theme/colors/colors.dart'; - -class SidebarAction extends StatelessWidget { - const SidebarAction( - {super.key, this.title, this.icon, this.onTap, this.selected = false}); - - final bool selected; - final Widget? icon; - final Widget? title; - final Function()? onTap; - - @override - Widget build(BuildContext context) { - return Padding( - padding: const EdgeInsets.symmetric(vertical: 2.0, horizontal: 12.0), - child: InkWell( - onTap: onTap, - borderRadius: BorderRadius.circular(12.0), - child: Padding( - padding: const EdgeInsets.all(8.0), - child: Row( - children: [ - if (icon != null) - IconTheme( - data: IconThemeData( - color: AppColors.of(context) - .text - .withOpacity(selected ? 1.0 : .3), - ), - child: icon!, - ), - if (title != null) - Padding( - padding: const EdgeInsets.only(left: 24.0), - child: AnimatedDefaultTextStyle( - duration: const Duration(milliseconds: 500), - style: TextStyle( - color: AppColors.of(context) - .text - .withOpacity(selected ? 1.0 : .8), - fontWeight: FontWeight.w500, - fontFamily: "Montserrat", - ), - child: title!, - ), - ), - ], - ), - ), - ), - ); - } -} diff --git a/refilc_desktop_ui/lib/screens/news/news_view.dart b/refilc_desktop_ui/lib/screens/news/news_view.dart deleted file mode 100644 index e276692..0000000 --- a/refilc_desktop_ui/lib/screens/news/news_view.dart +++ /dev/null @@ -1,10 +0,0 @@ -import 'package:flutter/material.dart'; - -class NewsView extends StatelessWidget { - const NewsView({super.key}); - - @override - Widget build(BuildContext context) { - return Container(); - } -} diff --git a/refilc_desktop_ui/lib/screens/settings/settings_screen.dart b/refilc_desktop_ui/lib/screens/settings/settings_screen.dart deleted file mode 100644 index e8ca7a8..0000000 --- a/refilc_desktop_ui/lib/screens/settings/settings_screen.dart +++ /dev/null @@ -1,965 +0,0 @@ -// ignore_for_file: no_leading_underscores_for_local_identifiers - -import 'package:refilc/api/providers/update_provider.dart'; -import 'package:refilc_kreta_api/providers/absence_provider.dart'; -import 'package:refilc_kreta_api/providers/event_provider.dart'; -import 'package:refilc_kreta_api/providers/exam_provider.dart'; -import 'package:refilc_kreta_api/providers/grade_provider.dart'; -import 'package:refilc_kreta_api/providers/homework_provider.dart'; -import 'package:refilc_kreta_api/providers/message_provider.dart'; -import 'package:refilc_kreta_api/providers/note_provider.dart'; -import 'package:refilc_kreta_api/providers/timetable_provider.dart'; -import 'package:refilc/api/providers/user_provider.dart'; -import 'package:refilc/utils/format.dart'; -import 'package:refilc/models/settings.dart'; -import 'package:refilc/models/user.dart'; -import 'package:refilc/theme/colors/colors.dart'; -import 'package:refilc_kreta_api/client/client.dart'; -import 'package:refilc_mobile_ui/common/action_button.dart'; -import 'package:refilc_mobile_ui/common/bottom_sheet_menu/bottom_sheet_menu.dart'; -import 'package:refilc_mobile_ui/common/bottom_sheet_menu/bottom_sheet_menu_item.dart'; -import 'package:refilc_mobile_ui/common/panel/panel.dart'; -import 'package:refilc_mobile_ui/common/panel/panel_button.dart'; -import 'package:refilc_mobile_ui/common/profile_image/profile_image.dart'; -import 'package:refilc_mobile_ui/common/widgets/update/updates_view.dart'; -import 'package:refilc_mobile_ui/plus/premium_button.dart'; -import 'package:refilc_mobile_ui/screens/news/news_screen.dart'; -import 'package:refilc_mobile_ui/screens/settings/accounts/account_tile.dart'; -import 'package:refilc_mobile_ui/screens/settings/accounts/account_view.dart'; -import 'package:refilc_mobile_ui/screens/settings/debug/subject_icon_gallery.dart'; -import 'package:refilc_mobile_ui/screens/settings/privacy_view.dart'; -import 'package:refilc_mobile_ui/screens/settings/settings_helper.dart'; -import 'package:refilc_plus/providers/plus_provider.dart'; -import 'package:flutter/cupertino.dart'; -import 'package:flutter/foundation.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_custom_tabs/flutter_custom_tabs.dart' as tabs; -import 'package:flutter_feather_icons/flutter_feather_icons.dart'; -import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart'; -import 'package:provider/provider.dart'; -import 'package:url_launcher/url_launcher.dart'; -import 'settings_screen.i18n.dart'; -import 'package:flutter/services.dart'; -import 'package:refilc_mobile_ui/screens/settings/user/nickname.dart'; - -class SettingsScreen extends StatefulWidget { - const SettingsScreen({super.key}); - - @override - SettingsScreenState createState() => SettingsScreenState(); -} - -class SettingsScreenState extends State - with SingleTickerProviderStateMixin { - int devmodeCountdown = 3; - final bool __ss = false; // secret settings - - late UserProvider user; - late UpdateProvider updateProvider; - late SettingsProvider settings; - late KretaClient kretaClient; - late String firstName; - List accountTiles = []; - - late AnimationController _hideContainersController; - - Future restore() => Future.wait([ - Provider.of(context, listen: false).restore(), - Provider.of(context, listen: false).restoreUser(), - Provider.of(context, listen: false).restore(), - Provider.of(context, listen: false).restore(), - Provider.of(context, listen: false).restore(), - Provider.of(context, listen: false) - .restoreRecipients(), - Provider.of(context, listen: false).restore(), - Provider.of(context, listen: false).restore(), - Provider.of(context, listen: false).restore(), - Provider.of(context, listen: false).refreshLogin(), - ]); - - void buildAccountTiles() { - accountTiles = []; - user.getUsers().forEach((account) { - if (account.id == user.id) return; - - String _firstName; - - List _nameParts = user.displayName?.split(" ") ?? ["?"]; - if (!settings.presentationMode) { - _firstName = _nameParts.length > 1 ? _nameParts[1] : _nameParts[0]; - } else { - _firstName = "János"; - } - - accountTiles.add(AccountTile( - name: Text(!settings.presentationMode ? account.name : "János", - style: const TextStyle(fontWeight: FontWeight.w500)), - username: - Text(!settings.presentationMode ? account.username : "72469696969"), - profileImage: ProfileImage( - name: _firstName, - backgroundColor: Theme.of(context) - .colorScheme - .secondary, //!settings.presentationMode - //? ColorUtils.stringToColor(account.name) - //: Theme.of(context).colorScheme.secondary, - role: account.role, - ), - onTap: () { - user.setUser(account.id); - restore().then((_) => user.setUser(account.id)); - Navigator.of(context).pop(); - }, - onTapMenu: () => _showBottomSheet(account), - )); - }); - } - - void _showBottomSheet(User u) { - showBottomSheetMenu(context, items: [ - BottomSheetMenuItem( - onPressed: () => AccountView.show(u, context: context), - icon: const Icon(FeatherIcons.user), - title: Text("personal_details".i18n), - ), - BottomSheetMenuItem( - onPressed: () => _openDKT(u), - icon: Icon(FeatherIcons.grid, color: AppColors.of(context).teal), - title: Text("open_dkt".i18n), - ), - UserMenuNickname(u), - // BottomSheetMenuItem( - // onPressed: () {}, - // icon: Icon(FeatherIcons.camera), - // title: Text("edit_profile_picture".i18n), - // ), - // BottomSheetMenuItem( - // onPressed: () {}, - // icon: Icon(FeatherIcons.trash2, color: AppColors.of(context).red), - // title: Text("remove_profile_picture".i18n), - // ), - ]); - } - - void _openDKT(User u) => tabs.launchUrl( - Uri.parse( - "https://dkttanulo.e-kreta.hu/sso?id_token=${kretaClient.idToken}"), - customTabsOptions: tabs.CustomTabsOptions( - showTitle: true, - colorSchemes: tabs.CustomTabsColorSchemes( - defaultPrams: tabs.CustomTabsColorSchemeParams( - toolbarColor: Theme.of(context).scaffoldBackgroundColor, - ), - ), - ), - ); - - @override - void initState() { - super.initState(); - _hideContainersController = AnimationController( - vsync: this, duration: const Duration(milliseconds: 200)); - } - - @override - Widget build(BuildContext context) { - user = Provider.of(context); - settings = Provider.of(context); - updateProvider = Provider.of(context); - kretaClient = Provider.of(context); - - List nameParts = user.displayName?.split(" ") ?? ["?"]; - if (!settings.presentationMode) { - firstName = nameParts.length > 1 ? nameParts[1] : nameParts[0]; - } else { - firstName = "János"; - } - - String startPageTitle = - SettingsHelper.localizedPageTitles()[settings.startPage] ?? "?"; - String themeModeText = { - ThemeMode.light: "light".i18n, - ThemeMode.dark: "dark".i18n, - ThemeMode.system: "system".i18n - }[settings.theme] ?? - "?"; - String languageText = SettingsHelper.langMap[settings.language] ?? "?"; - String vibrateTitle = { - VibrationStrength.off: "voff".i18n, - VibrationStrength.light: "vlight".i18n, - VibrationStrength.medium: "vmedium".i18n, - VibrationStrength.strong: "vstrong".i18n, - }[settings.vibrate] ?? - "?"; - - buildAccountTiles(); - - if (settings.developerMode) devmodeCountdown = -1; - - return Scaffold( - body: Padding( - padding: const EdgeInsets.only(top: 11.5), - child: CustomScrollView( - slivers: [ - SliverAppBar( - pinned: true, - floating: true, - snap: false, - centerTitle: false, - title: const Text("Settings"), - surfaceTintColor: Theme.of(context).scaffoldBackgroundColor, - ), - SliverToBoxAdapter( - child: AnimatedBuilder( - animation: _hideContainersController, - builder: (context, child) => Opacity( - opacity: 1 - _hideContainersController.value, - child: Column( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - StaggeredGrid.extent( - // direction: Axis.horizontal, - // crossAxisCount: 3, - maxCrossAxisExtent: 600, - children: [ - const SizedBox(height: 32.0), - - // Updates - if (updateProvider.available) - Container( - constraints: const BoxConstraints(maxWidth: 500), - child: Padding( - padding: const EdgeInsets.symmetric( - vertical: 12.0, horizontal: 24.0), - child: Panel( - child: PanelButton( - onPressed: () => _openUpdates(context), - title: Text("update_available".i18n), - leading: const Icon(FeatherIcons.download), - trailing: Text( - updateProvider.releases.first.tag, - style: TextStyle( - fontWeight: FontWeight.w500, - color: Theme.of(context) - .colorScheme - .secondary, - ), - ), - ), - ), - ), - ), - - // const Padding( - // padding: EdgeInsets.symmetric(vertical: 12.0, horizontal: 24.0), - // child: PremiumBannerButton(), - // ), - if (!Provider.of(context).hasPremium) - const ClipRect( - child: Padding( - padding: EdgeInsets.symmetric(vertical: 12.0), - child: PremiumButton(), - ), - ), - - // General Settings - Container( - constraints: const BoxConstraints(maxWidth: 500), - child: Padding( - padding: const EdgeInsets.symmetric( - vertical: 12.0, horizontal: 24.0), - child: Panel( - title: Text("general".i18n), - child: Column( - children: [ - PanelButton( - onPressed: () { - SettingsHelper.language(context); - setState(() {}); - }, - title: Text("language".i18n), - leading: const Icon(FeatherIcons.globe), - trailing: Text(languageText), - ), - PanelButton( - onPressed: () { - SettingsHelper.startPage(context); - setState(() {}); - }, - title: Text("startpage".i18n), - leading: const Icon(FeatherIcons.play), - trailing: Text(startPageTitle.capital()), - ), - PanelButton( - onPressed: () { - SettingsHelper.rounding(context); - setState(() {}); - }, - title: Text("rounding".i18n), - leading: - const Icon(FeatherIcons.gitCommit), - trailing: Text((settings.rounding / 10) - .toStringAsFixed(1)), - ), - PanelButton( - onPressed: () { - SettingsHelper.vibrate(context); - setState(() {}); - }, - title: Text("vibrate".i18n), - leading: const Icon(FeatherIcons.radio), - trailing: Text(vibrateTitle), - ), - PanelButton( - padding: - const EdgeInsets.only(left: 14.0), - onPressed: () { - SettingsHelper.bellDelay(context); - setState(() {}); - }, - title: Text( - "bell_delay".i18n, - style: TextStyle( - color: AppColors.of(context) - .text - .withOpacity( - settings.bellDelayEnabled - ? 1.0 - : .5)), - ), - leading: settings.bellDelayEnabled - ? const Icon(FeatherIcons.bell) - : Icon(FeatherIcons.bellOff, - color: AppColors.of(context) - .text - .withOpacity(.25)), - trailingDivider: true, - trailing: Switch( - onChanged: (v) => settings.update( - bellDelayEnabled: v), - value: settings.bellDelayEnabled, - activeColor: Theme.of(context) - .colorScheme - .secondary, - ), - ), - ], - ), - ), - ), - ), - - if (kDebugMode) - Container( - constraints: const BoxConstraints(maxWidth: 500), - child: Padding( - padding: const EdgeInsets.symmetric( - vertical: 12.0, horizontal: 24.0), - child: Panel( - title: const Text("Debug"), - child: Column( - children: [ - PanelButton( - title: - const Text("Subject Icon Gallery"), - leading: const Icon(CupertinoIcons - .rectangle_3_offgrid_fill), - trailing: - const Icon(Icons.arrow_forward), - onPressed: () { - Navigator.of(context, - rootNavigator: true) - .push( - CupertinoPageRoute( - builder: (context) => - const SubjectIconGallery()), - ); - }, - ) - ], - ), - ), - ), - ), - - // Secret Settings - if (__ss) - Container( - constraints: const BoxConstraints(maxWidth: 500), - child: Padding( - padding: const EdgeInsets.symmetric( - vertical: 12.0, horizontal: 24.0), - child: Panel( - title: Text("secret".i18n), - child: Column( - children: [ - // Good student mode - Material( - type: MaterialType.transparency, - child: SwitchListTile( - contentPadding: - const EdgeInsets.only(left: 12.0), - shape: RoundedRectangleBorder( - borderRadius: - BorderRadius.circular(12.0)), - title: Text("goodstudent".i18n, - style: const TextStyle( - fontWeight: FontWeight.w500)), - onChanged: (v) { - if (v) { - showDialog( - context: context, - builder: (context) => PopScope( - onPopInvoked: (didPop) => - false, - child: AlertDialog( - shape: - RoundedRectangleBorder( - borderRadius: - BorderRadius - .circular( - 12.0)), - title: - Text("attention".i18n), - content: Text( - "goodstudent_disclaimer" - .i18n), - actions: [ - ActionButton( - label: - "understand".i18n, - onTap: () { - Navigator.of( - context) - .pop(); - settings.update( - goodStudent: v); - Provider.of( - context, - listen: - false) - .fetch(); - }) - ], - ), - ), - ); - } else { - settings.update(goodStudent: v); - Provider.of( - context, - listen: false) - .fetch(); - } - }, - value: settings.goodStudent, - activeColor: Theme.of(context) - .colorScheme - .secondary, - ), - ), - - // Presentation mode - Material( - type: MaterialType.transparency, - child: SwitchListTile( - contentPadding: - const EdgeInsets.only(left: 12.0), - shape: RoundedRectangleBorder( - borderRadius: - BorderRadius.circular(12.0)), - title: const Text("Presentation Mode", - style: TextStyle( - fontWeight: FontWeight.w500)), - onChanged: (v) => settings.update( - presentationMode: v), - value: settings.presentationMode, - activeColor: Theme.of(context) - .colorScheme - .secondary, - ), - ), - ], - ), - ), - ), - ), - - // Theme Settings - Container( - constraints: const BoxConstraints(maxWidth: 500), - child: Padding( - padding: const EdgeInsets.symmetric( - vertical: 12.0, horizontal: 24.0), - child: Panel( - title: Text("appearance".i18n), - child: Column( - children: [ - PanelButton( - onPressed: () { - SettingsHelper.theme(context); - setState(() {}); - }, - title: Text("theme".i18n), - leading: const Icon(FeatherIcons.sun), - trailing: Text(themeModeText), - ), - PanelButton( - onPressed: () async { - await _hideContainersController - .forward(); - // ignore: use_build_context_synchronously - SettingsHelper.accentColor(context); - setState(() {}); - _hideContainersController.reset(); - }, - title: Text("color".i18n), - leading: const Icon(FeatherIcons.droplet), - trailing: Container( - width: 12.0, - height: 12.0, - decoration: BoxDecoration( - color: Theme.of(context) - .colorScheme - .secondary, - shape: BoxShape.circle, - ), - ), - ), - PanelButton( - onPressed: () { - SettingsHelper.gradeColors(context); - setState(() {}); - }, - title: Text("grade_colors".i18n), - leading: const Icon(FeatherIcons.star), - trailing: Row( - mainAxisSize: MainAxisSize.min, - children: List.generate( - 5, - (i) => Container( - margin: const EdgeInsets.only( - left: 2.0), - width: 12.0, - height: 12.0, - decoration: BoxDecoration( - shape: BoxShape.circle, - color: settings.gradeColors[i], - ), - ), - ), - ), - ), - Material( - type: MaterialType.transparency, - child: SwitchListTile( - contentPadding: - const EdgeInsets.only(left: 12.0), - shape: RoundedRectangleBorder( - borderRadius: - BorderRadius.circular(12.0)), - title: Row( - children: [ - Icon( - FeatherIcons.barChart, - color: settings.graphClassAvg - ? Theme.of(context) - .colorScheme - .secondary - : AppColors.of(context) - .text - .withOpacity(.25), - ), - const SizedBox(width: 24.0), - Expanded( - child: Text( - "graph_class_avg".i18n, - style: TextStyle( - fontWeight: FontWeight.w600, - fontSize: 16.0, - color: AppColors.of(context) - .text - .withOpacity( - settings.graphClassAvg - ? 1.0 - : .5), - ), - ), - ), - ], - ), - onChanged: (v) => - settings.update(graphClassAvg: v), - value: settings.graphClassAvg, - activeColor: Theme.of(context) - .colorScheme - .secondary, - ), - ), - // we need icon pack selector here - // const PremiumIconPackSelector(), - ], - ), - ), - ), - ), - - // Notifications - Container( - constraints: const BoxConstraints(maxWidth: 500), - child: Padding( - padding: const EdgeInsets.symmetric( - vertical: 12.0, horizontal: 24.0), - child: Panel( - title: Text("notifications".i18n), - child: Material( - type: MaterialType.transparency, - child: SwitchListTile( - contentPadding: - const EdgeInsets.only(left: 12.0), - shape: RoundedRectangleBorder( - borderRadius: - BorderRadius.circular(12.0)), - title: Row( - children: [ - Icon( - Icons.newspaper_outlined, - color: settings.newsEnabled - ? Theme.of(context) - .colorScheme - .secondary - : AppColors.of(context) - .text - .withOpacity(.25), - ), - const SizedBox(width: 24.0), - Expanded( - child: Text( - "news".i18n, - style: TextStyle( - fontWeight: FontWeight.w600, - fontSize: 16.0, - color: AppColors.of(context) - .text - .withOpacity( - settings.newsEnabled - ? 1.0 - : .5), - ), - ), - ), - ], - ), - onChanged: (v) => - settings.update(newsEnabled: v), - value: settings.newsEnabled, - activeColor: - Theme.of(context).colorScheme.secondary, - ), - ), - ), - ), - ), - - // Extras - Container( - constraints: const BoxConstraints(maxWidth: 500), - child: Padding( - padding: const EdgeInsets.symmetric( - vertical: 12.0, horizontal: 24.0), - child: Panel( - title: Text("extras".i18n), - child: Column(children: [ - Material( - type: MaterialType.transparency, - child: SwitchListTile( - contentPadding: - const EdgeInsets.only(left: 12.0), - shape: RoundedRectangleBorder( - borderRadius: - BorderRadius.circular(12.0)), - title: Row( - children: [ - Icon( - FeatherIcons.gift, - color: settings.gradeOpeningFun - ? Theme.of(context) - .colorScheme - .secondary - : AppColors.of(context) - .text - .withOpacity(.25), - ), - const SizedBox(width: 24.0), - Expanded( - child: Text( - "surprise_grades".i18n, - style: TextStyle( - fontWeight: FontWeight.w600, - fontSize: 16.0, - color: AppColors.of(context) - .text - .withOpacity( - settings.gradeOpeningFun - ? 1.0 - : .5), - ), - ), - ), - ], - ), - onChanged: (v) => - settings.update(gradeOpeningFun: v), - value: settings.gradeOpeningFun, - activeColor: Theme.of(context) - .colorScheme - .secondary, - ), - ), - ]), - ), - ), - ), - - // About - Container( - constraints: const BoxConstraints(maxWidth: 500), - child: Padding( - padding: const EdgeInsets.symmetric( - vertical: 12.0, horizontal: 24.0), - child: Panel( - title: Text("about".i18n), - child: Column(children: [ - PanelButton( - leading: const Icon(FeatherIcons.atSign), - title: const Text("Discord"), - onPressed: () => launchUrl( - Uri.parse("https://refilc.hu/discord"), - mode: LaunchMode.externalApplication), - ), - PanelButton( - leading: const Icon(FeatherIcons.globe), - title: const Text("www.refilc.hu"), - onPressed: () => launchUrl( - Uri.parse("https://refilc.hu"), - mode: LaunchMode.externalApplication), - ), - PanelButton( - leading: const Icon(FeatherIcons.github), - title: const Text("Github"), - onPressed: () => launchUrl( - Uri.parse("https://github.com/filc"), - mode: LaunchMode.externalApplication), - ), - PanelButton( - leading: const Icon(FeatherIcons.mail), - title: Text("news".i18n), - onPressed: () => _openNews(context), - ), - PanelButton( - leading: const Icon(FeatherIcons.lock), - title: Text("privacy".i18n), - onPressed: () => _openPrivacy(context), - ), - PanelButton( - leading: const Icon(FeatherIcons.award), - title: Text("licenses".i18n), - onPressed: () => - showLicensePage(context: context), - ), - Tooltip( - message: "data_collected".i18n, - padding: const EdgeInsets.all(4.0), - textStyle: TextStyle( - fontWeight: FontWeight.w500, - color: AppColors.of(context).text), - decoration: BoxDecoration( - color: Theme.of(context) - .colorScheme - .surface), - child: Material( - type: MaterialType.transparency, - child: SwitchListTile( - contentPadding: - const EdgeInsets.only(left: 12.0), - shape: RoundedRectangleBorder( - borderRadius: - BorderRadius.circular(12.0)), - secondary: Icon( - FeatherIcons.barChart2, - color: settings.xFilcId != "none" - ? Theme.of(context) - .colorScheme - .secondary - : AppColors.of(context) - .text - .withOpacity(.25), - ), - title: Text( - "Analytics".i18n, - style: TextStyle( - fontWeight: FontWeight.w600, - fontSize: 16.0, - color: AppColors.of(context) - .text - .withOpacity( - settings.xFilcId != "none" - ? 1.0 - : .5), - ), - ), - subtitle: Text( - "Anonymous Usage Analytics".i18n, - style: TextStyle( - color: AppColors.of(context) - .text - .withOpacity( - settings.xFilcId != "none" - ? .5 - : .2), - ), - ), - onChanged: (v) { - String newId; - if (v == false) { - newId = "none"; - } else if (settings.xFilcId == - "none") { - newId = SettingsProvider - .defaultSettings() - .xFilcId; - } else { - newId = settings.xFilcId; - } - settings.update(xFilcId: newId); - }, - value: settings.xFilcId != "none", - activeColor: Theme.of(context) - .colorScheme - .secondary, - ), - ), - ), - ]), - ), - ), - ), - if (settings.developerMode) - Container( - constraints: const BoxConstraints(maxWidth: 500), - child: Padding( - padding: const EdgeInsets.symmetric( - vertical: 12.0, horizontal: 24.0), - child: Panel( - title: const Text("Developer Settings"), - child: Column( - children: [ - Material( - type: MaterialType.transparency, - child: SwitchListTile( - contentPadding: - const EdgeInsets.only(left: 12.0), - shape: RoundedRectangleBorder( - borderRadius: - BorderRadius.circular(12.0)), - title: const Text("Developer Mode", - style: TextStyle( - fontWeight: FontWeight.w500)), - onChanged: (v) => settings.update( - developerMode: false), - value: settings.developerMode, - activeColor: Theme.of(context) - .colorScheme - .secondary, - ), - ), - PanelButton( - leading: const Icon(FeatherIcons.copy), - title: const Text("Copy JWT"), - onPressed: () => Clipboard.setData( - ClipboardData( - text: Provider.of( - context, - listen: false) - .accessToken!)), - ), - // if (Provider.of(context, - // listen: false) - // .hasPremium) - // PanelButton( - // leading: const Icon(FeatherIcons.key), - // title: const Text("Remove Premium"), - // onPressed: () { - // Provider.of( - // context, - // listen: false) - // .activate(removePremium: true); - // settings.update( - // accentColor: AccentColor.filc, - // store: true); - // Provider.of( - // context, - // listen: false) - // .changeTheme(settings.theme); - // }, - // ), - ], - ), - ), - ), - ), - ], - ), - const SizedBox( - height: 40, - ), - SafeArea( - top: false, - child: Center( - child: GestureDetector( - child: const Panel( - title: Text( - "v${const String.fromEnvironment("APPVER", defaultValue: "?")}")), - onTap: () { - if (devmodeCountdown > 0) { - ScaffoldMessenger.of(context) - .showSnackBar(SnackBar( - duration: const Duration(milliseconds: 200), - content: Text( - "You are $devmodeCountdown taps away from Developer Mode."), - )); - - setState(() => devmodeCountdown--); - } else if (devmodeCountdown == 0) { - ScaffoldMessenger.of(context) - .showSnackBar(const SnackBar( - content: Text( - "Developer Mode successfully activated."), - )); - - settings.update(developerMode: true); - - setState(() => devmodeCountdown--); - } - }, - ), - ), - ), - ], - ), - ), - ), - ), - ], - ), - ), - ); - } - - void _openNews(BuildContext context) => - Navigator.of(context, rootNavigator: true) - .push(CupertinoPageRoute(builder: (context) => const NewsScreen())); - void _openUpdates(BuildContext context) => - UpdateView.show(updateProvider.releases.first, context: context); - void _openPrivacy(BuildContext context) => PrivacyView.show(context); -} diff --git a/refilc_desktop_ui/lib/screens/settings/settings_screen.i18n.dart b/refilc_desktop_ui/lib/screens/settings/settings_screen.i18n.dart deleted file mode 100644 index 65dc67e..0000000 --- a/refilc_desktop_ui/lib/screens/settings/settings_screen.i18n.dart +++ /dev/null @@ -1,191 +0,0 @@ -import 'package:i18n_extension/i18n_extension.dart'; - -extension SettingsLocalization on String { - static final _t = Translations.byLocale("hu_hu") + - { - "en_en": { - "personal_details": "Personal Details", - "open_dkt": "Open DCS", - "edit_nickname": "Edit Nickname", - "edit_profile_picture": "Edit Profile Picture", - "remove_profile_picture": "Remove Profile Picture", - "light": "Light", - "dark": "Dark", - "system": "System", - "add_user": "Add User", - "log_out": "Log Out", - "update_available": "Update Available", - "general": "General", - "language": "Language", - "startpage": "Startpage", - "rounding": "Rounding", - "appearance": "Appearance", - "theme": "Theme", - "color": "Color", - "grade_colors": "Grade Colors", - "notifications": "Notifications", - "news": "News", - "extras": "Extras", - "about": "About", - "supporters": "Supporters", - "privacy": "Privacy Policy", - "licenses": "Licenses", - "vibrate": "Vibration", - "voff": "Off", - "vlight": "Light", - "vmedium": "Medium", - "vstrong": "Strong", - "cancel": "Cancel", - "done": "Done", - "reset": "Reset", - "open": "Open", - "data_collected": - "Data collected: Platform (eg. Android), App version (eg. 3.0.0), Unique Install Identifier", - "Analytics": "Analytics", - "Anonymous Usage Analytics": "Anonymous Usage Analytics", - "graph_class_avg": "Class average on graph", - "goodstudent": "Good student mode", - "attention": "Attention!", - "goodstudent_disclaimer": - "reFilc can not be held liable for the usage of this feature.\n\n(if your mother beats you up because you showed her fake grades, you can only blame yourself for it)", - "understand": "I understand", - "secret": "Secret Settings", - "bell_delay": "Bell Delay", - "delay": "Delay", - "hurry": "Hurry", - "sync": "Synchronize", - "sync_help": "Press the Synchronize button when the bell rings.", - "surprise_grades": "Surprise Grades", - "icon_pack": "Icon Pack", - "change_username": "Set a nickname", - "Accent Color": "Accent Color", - "Background Color": "Background Color", - "Highlight Color": "Highlight Color", - "Adaptive Theme": "Adaptive Theme", - }, - "hu_hu": { - "personal_details": "Személyes információk", - "open_dkt": "DKT megnyitása", - "edit_nickname": "Becenév szerkesztése", - "edit_profile_picture": "Profil-kép szerkesztése", - "remove_profile_picture": "Profil-kép törlése", - "light": "Világos", - "dark": "Sötét", - "system": "Rendszer", - "add_user": "Felhasználó hozzáadása", - "log_out": "Kijelentkezés", - "update_available": "Frissítés elérhető", - "general": "Általános", - "language": "Nyelv", - "startpage": "Kezdőlap", - "rounding": "Kerekítés", - "appearance": "Kinézet", - "theme": "Téma", - "color": "Színek", - "grade_colors": "Jegyek színei", - "notifications": "Értesítések", - "news": "Hírek", - "extras": "Extrák", - "about": "Névjegy", - "supporters": "Támogatók", - "privacy": "Adatvédelmi irányelvek", - "licenses": "Licenszek", - "vibrate": "Rezgés", - "voff": "Kikapcsolás", - "vlight": "Alacsony", - "vmedium": "Közepes", - "vstrong": "Erős", - "cancel": "Mégsem", - "done": "Kész", - "reset": "Visszaállítás", - "open": "Megnyitás", - "data_collected": - "Gyűjtött adat: Platform (pl. Android), App verzió (pl. 3.0.0), Egyedi telepítési azonosító", - "Analytics": "Analitika", - "Anonymous Usage Analytics": "Névtelen használati analitika", - "graph_class_avg": "Osztályátlag a grafikonon", - "goodstudent": "Jó tanuló mód", - "attention": "Figyelem!", - "goodstudent_disclaimer": - "A reFilc minden felelősséget elhárít a funkció használatával kapcsolatban.\n\n(Értsd: ha az anyád megver, mert megtévesztő ábrákat mutattál neki, azért csakis magadadat hibáztathatod.)", - "understand": "Értem", - "secret": "Titkos Beállítások", - "bell_delay": "Csengő eltolódása", - "delay": "Késleltetés", - "hurry": "Siettetés", - "sync": "Szinkronizálás", - "sync_help": "Csengetéskor nyomd meg a Szinkronizálás gombot.", - "surprise_grades": "Meglepetés jegyek", - "icon_pack": "Ikon séma", - "change_username": "Becenév beállítása", - "Accent Color": "Egyedi szín", - "Background Color": "Háttér színe", - "Highlight Color": "Panelek színe", - "Adaptive Theme": "Adaptív téma", - }, - "de_de": { - "personal_details": "Persönliche Angaben", - "open_dkt": "Öffnen RDZ", - "edit_nickname": "Spitznamen bearbeiten", - "edit_profile_picture": "Profilbild bearbeiten", - "remove_profile_picture": "Profilbild entfernen", - "light": "Licht", - "dark": "Dunkel", - "system": "System", - "add_user": "Benutzer hinzufügen", - "log_out": "Abmelden", - "update_available": "Update verfügbar", - "general": "Allgemein", - "language": "Sprache", - "startpage": "Startseite", - "rounding": "Rundung", - "appearance": "Erscheinungsbild", - "theme": "Thema", - "color": "Farbe", - "grade_colors": "Grad Farben", - "notifications": "Benachrichtigungen", - "news": "Nachrichten", - "extras": "Extras", - "about": "Informationen", - "supporters": "Unterstützer", - "privacy": "Datenschutzbestimmungen", - "licenses": "Lizenzen", - "vibrate": "Vibration", - "voff": "Aus", - "vlight": "Leicht", - "vmedium": "Mittel", - "vstrong": "Stark", - "cancel": "Abbrechen", - "done": "Fertig", - "reset": "Zurücksetzen", - "open": "Öffnen", - "data_collected": - "Erhobene Daten: Plattform (z.B. Android), App version (z.B. 3.0.0), Eindeutige Installationskennung", - "Analytics": "Analytik", - "Anonymous Usage Analytics": "Anonyme Nutzungsanalyse", - "graph_class_avg": "Klassendurchschnitt in der Grafik", - "goodstudent": "Guter Student Modus", - "attention": "Achtung!", - "goodstudent_disclaimer": "Same in English.", - "understand": "Ich verstehe", - "secret": "Geheime Einstellungen", - "bell_delay": "Klingelverzögerung", - "delay": "Verzögern", - "hurry": "Eile", - "sync": "Synchronisieren", - "sync_help": "Drücken Sie die Sync-Taste, wenn die Glocke läutet.", - "surprise_grades": "Überraschungsnoten", - "icon_pack": "Icon-Pack", - "change_username": "Einen Spitznamen festlegen", - "Accent Color": "Accent Color", - "Background Color": "Background Color", - "Highlight Color": "Highlight Color", - "Adaptive Theme": "Adaptive Theme", - }, - }; - - String get i18n => localize(this, _t); - String fill(List params) => localizeFill(this, params); - String plural(int value) => localizePlural(value, this, _t); - String version(Object modifier) => localizeVersion(modifier, this, _t); -} diff --git a/refilc_desktop_ui/pubspec.yaml b/refilc_desktop_ui/pubspec.yaml deleted file mode 100644 index aaa822c..0000000 --- a/refilc_desktop_ui/pubspec.yaml +++ /dev/null @@ -1,47 +0,0 @@ -name: refilc_desktop_ui -publish_to: "none" - -environment: - sdk: ">=3.3.2 <=3.6.0" - -dependencies: - flutter: - sdk: flutter - - # reFilc Main - refilc: - path: ../refilc/ - # e-KRETA API (kreten) client - refilc_kreta_api: - path: ../refilc_kreta_api/ - # reFilc Plus - refilc_plus: - path: ../refilc_plus/ - # reFilc Mobile - refilc_mobile_ui: - path: ../refilc_mobile_ui/ - - cupertino_icons: ^1.0.2 - flutter_feather_icons: ^2.0.0+1 - provider: ^6.1.1 - url_launcher: ^6.2.5 - flutter_linkify: ^6.0.0 - flutter_markdown: ^0.7.2+1 - animations: ^2.0.11 - confetti: ^0.7.0 - auto_size_text: ^3.0.0 - flutter_acrylic: ^1.1.3 - elegant_notification: ^2.2.0 - flutter_staggered_grid_view: ^0.7.0 - i18n_extension: ^12.0.1 - flutter_expandable_fab: ^2.0.0 - collection: ^1.18.0 - animated_list_plus: ^0.5.2 - intl: ^0.19.0 - flutter_custom_tabs: ^2.0.0+1 - -dev_dependencies: - flutter_lints: ^4.0.0 - -flutter: - uses-material-design: true diff --git a/refilc_mobile_ui/lib/pages/notes/submenu/create_image_note.dart b/refilc_mobile_ui/lib/pages/notes/submenu/create_image_note.dart index 765338b..d7a3d03 100644 --- a/refilc_mobile_ui/lib/pages/notes/submenu/create_image_note.dart +++ b/refilc_mobile_ui/lib/pages/notes/submenu/create_image_note.dart @@ -7,7 +7,7 @@ import 'dart:io'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_feather_icons/flutter_feather_icons.dart'; -import 'package:image_crop/image_crop.dart'; +import 'package:image_crop_plus/image_crop_plus.dart'; import 'package:image_picker/image_picker.dart'; import 'package:provider/provider.dart'; import 'package:refilc/api/providers/database_provider.dart'; diff --git a/refilc_mobile_ui/lib/screens/settings/user/profile_pic.dart b/refilc_mobile_ui/lib/screens/settings/user/profile_pic.dart index 9df85b0..2fcb724 100644 --- a/refilc_mobile_ui/lib/screens/settings/user/profile_pic.dart +++ b/refilc_mobile_ui/lib/screens/settings/user/profile_pic.dart @@ -16,7 +16,7 @@ import 'package:flutter_feather_icons/flutter_feather_icons.dart'; import 'package:refilc_mobile_ui/screens/settings/settings_screen.i18n.dart'; import 'package:provider/provider.dart'; import 'package:image_picker/image_picker.dart'; -import 'package:image_crop/image_crop.dart'; +import 'package:image_crop_plus/image_crop_plus.dart'; // ignore: must_be_immutable class UserMenuProfilePic extends StatelessWidget { diff --git a/refilc_mobile_ui/pubspec.yaml b/refilc_mobile_ui/pubspec.yaml index e180352..e87be26 100644 --- a/refilc_mobile_ui/pubspec.yaml +++ b/refilc_mobile_ui/pubspec.yaml @@ -61,9 +61,7 @@ dependencies: share_plus: ^10.0.3 image_picker: ^1.0.7 path_provider: ^2.1.2 - image_crop: - git: - url: https://github.com/kimaah/image_crop.git + image_crop_plus: ^1.0.0 uuid: ^4.3.3 maps_launcher: ^2.2.0 google_fonts: ^6.1.0