diff --git a/uni/lib/controller/local_storage/database/app_exams_database.dart b/uni/lib/controller/local_storage/database/app_exams_database.dart index 49f6bcc0c..8d53df3da 100644 --- a/uni/lib/controller/local_storage/database/app_exams_database.dart +++ b/uni/lib/controller/local_storage/database/app_exams_database.dart @@ -11,20 +11,6 @@ import 'package:uni/model/entities/exam.dart'; class AppExamsDatabase extends AppDatabase { AppExamsDatabase() : super('exams.db', [_createScript], onUpgrade: migrate, version: 5); - Map months = { - 'Janeiro': '01', - 'Fevereiro': '02', - 'Março': '03', - 'Abril': '04', - 'Maio': '05', - 'Junho': '06', - 'Julho': '07', - 'Agosto': '08', - 'Setembro': '09', - 'Outubro': '10', - 'Novembro': '11', - 'Dezembro': '12', - }; static const _createScript = ''' CREATE TABLE exams(id TEXT, subject TEXT, begin TEXT, end TEXT, diff --git a/uni/lib/controller/networking/url_launcher.dart b/uni/lib/controller/networking/url_launcher.dart new file mode 100644 index 000000000..f4ff85ae5 --- /dev/null +++ b/uni/lib/controller/networking/url_launcher.dart @@ -0,0 +1,18 @@ +import 'dart:async'; + +import 'package:flutter/cupertino.dart'; +import 'package:uni/generated/l10n.dart'; +import 'package:uni/view/common_widgets/toast_message.dart'; +import 'package:url_launcher/url_launcher.dart'; + +Future launchUrlWithToast(BuildContext context, String url) async { + final validUrl = Uri.parse(url); + if (url != '' && canLaunchUrl(validUrl) as bool) { + await launchUrl(Uri.parse(url)); + } else { + await ToastMessage.error( + context, + S.of(context).no_link, + ); + } +} diff --git a/uni/lib/generated/intl/messages_en.dart b/uni/lib/generated/intl/messages_en.dart index e7a668037..c06126f51 100644 --- a/uni/lib/generated/intl/messages_en.dart +++ b/uni/lib/generated/intl/messages_en.dart @@ -115,6 +115,7 @@ class MessageLookup extends MessageLookupByLibrary { "edit_on": MessageLookupByLibrary.simpleMessage("Finish editing"), "empty_text": MessageLookupByLibrary.simpleMessage("Please fill in this field"), + "exam_of": MessageLookupByLibrary.simpleMessage("of"), "exams_filter": MessageLookupByLibrary.simpleMessage("Exams Filter Settings"), "exit_confirm": @@ -184,6 +185,8 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("No favorite restaurants"), "no_info": MessageLookupByLibrary.simpleMessage( "There is no information to display"), + "no_link": + MessageLookupByLibrary.simpleMessage("We couldn\'t open the link"), "no_library_info": MessageLookupByLibrary.simpleMessage( "No library occupation information available"), "no_menu_info": MessageLookupByLibrary.simpleMessage( diff --git a/uni/lib/generated/intl/messages_pt_PT.dart b/uni/lib/generated/intl/messages_pt_PT.dart index d77b84c82..ad9b90048 100644 --- a/uni/lib/generated/intl/messages_pt_PT.dart +++ b/uni/lib/generated/intl/messages_pt_PT.dart @@ -114,6 +114,7 @@ class MessageLookup extends MessageLookupByLibrary { "edit_on": MessageLookupByLibrary.simpleMessage("Concluir edição"), "empty_text": MessageLookupByLibrary.simpleMessage( "Por favor preenche este campo"), + "of_month": MessageLookupByLibrary.simpleMessage("de"), "exams_filter": MessageLookupByLibrary.simpleMessage("Definições Filtro de Exames"), "exit_confirm": MessageLookupByLibrary.simpleMessage( @@ -185,6 +186,8 @@ class MessageLookup extends MessageLookupByLibrary { MessageLookupByLibrary.simpleMessage("Sem restaurantes favoritos"), "no_info": MessageLookupByLibrary.simpleMessage( "Não existem informações para apresentar"), + "no_link": MessageLookupByLibrary.simpleMessage( + "Não conseguimos abrir o link"), "no_library_info": MessageLookupByLibrary.simpleMessage("Sem informação de ocupação"), "no_menu_info": MessageLookupByLibrary.simpleMessage( diff --git a/uni/lib/generated/l10n.dart b/uni/lib/generated/l10n.dart index eadc9bcee..cf6efa4a5 100644 --- a/uni/lib/generated/l10n.dart +++ b/uni/lib/generated/l10n.dart @@ -1106,6 +1106,26 @@ class S { ); } + /// `of` + String get of_month { + return Intl.message( + 'of', + name: 'of_month', + desc: '', + args: [], + ); + } + + /// `We couldn't open the link` + String get no_link { + return Intl.message( + 'We couldn\'t open the link', + name: 'no_link', + desc: '', + args: [], + ); + } + /// `Other links` String get other_links { return Intl.message( diff --git a/uni/lib/l10n/intl_en.arb b/uni/lib/l10n/intl_en.arb index 4b696bfe3..49b2c447d 100644 --- a/uni/lib/l10n/intl_en.arb +++ b/uni/lib/l10n/intl_en.arb @@ -216,6 +216,10 @@ "@no_library_info": {}, "occurrence_type": "Type of occurrence", "@occurrence_type": {}, + "of_month": "of", + "@of_month": {}, + "no_link": "We couldn't open the link", + "@no_link": {}, "other_links": "Other links", "@other_links": {}, "pass_change_request": "For security reasons, passwords must be changed periodically.", diff --git a/uni/lib/l10n/intl_pt_PT.arb b/uni/lib/l10n/intl_pt_PT.arb index 4de2a08af..229106c98 100644 --- a/uni/lib/l10n/intl_pt_PT.arb +++ b/uni/lib/l10n/intl_pt_PT.arb @@ -216,6 +216,10 @@ "@no_library_info": {}, "occurrence_type": "Tipo de ocorrência", "@occurrence_type": {}, + "of_month": "de", + "@of_month": {}, + "no_link": "Não conseguimos abrir o link", + "@no_link": {}, "other_links": "Outros links", "@other_links": {}, "pass_change_request": "Por razões de segurança, as palavras-passe têm de ser alteradas periodicamente.", diff --git a/uni/lib/view/about/widgets/terms_and_conditions.dart b/uni/lib/view/about/widgets/terms_and_conditions.dart index 10e046352..1943a73f0 100644 --- a/uni/lib/view/about/widgets/terms_and_conditions.dart +++ b/uni/lib/view/about/widgets/terms_and_conditions.dart @@ -2,15 +2,15 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_markdown/flutter_markdown.dart'; import 'package:uni/controller/fetchers/terms_and_conditions_fetcher.dart'; +import 'package:uni/controller/networking/url_launcher.dart'; import 'package:uni/generated/l10n.dart'; -import 'package:url_launcher/url_launcher.dart'; class TermsAndConditions extends StatelessWidget { const TermsAndConditions({super.key}); @override Widget build(BuildContext context) { - var termsAndConditionsSaved = S.of(context).loading_terms; + String? termsAndConditionsSaved = S.of(context).loading_terms; final termsAndConditionsFuture = fetchTermsAndConditions(); return FutureBuilder( future: termsAndConditionsFuture, @@ -18,16 +18,14 @@ class TermsAndConditions extends StatelessWidget { (BuildContext context, AsyncSnapshot termsAndConditions) { if (termsAndConditions.connectionState == ConnectionState.done && termsAndConditions.hasData) { - termsAndConditionsSaved = termsAndConditions.data!; + termsAndConditionsSaved = termsAndConditions.data; } return MarkdownBody( styleSheet: MarkdownStyleSheet(), shrinkWrap: false, - data: termsAndConditionsSaved, + data: termsAndConditionsSaved!, onTapLink: (text, url, title) async { - if (await canLaunchUrl(Uri.parse(url!))) { - await launchUrl(Uri.parse(url)); - } + await launchUrlWithToast(context, url!); }, ); }, diff --git a/uni/lib/view/exams/widgets/day_title.dart b/uni/lib/view/exams/widgets/day_title.dart index 56710245a..b0626a86b 100644 --- a/uni/lib/view/exams/widgets/day_title.dart +++ b/uni/lib/view/exams/widgets/day_title.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:uni/generated/l10n.dart'; class DayTitle extends StatelessWidget { const DayTitle({ @@ -17,7 +18,7 @@ class DayTitle extends StatelessWidget { padding: const EdgeInsets.only(top: 15, bottom: 3), alignment: Alignment.center, child: Text( - '$weekDay, $day de $month', + '$weekDay, $day ${S.of(context).of_month} $month', style: Theme.of(context).textTheme.titleLarge, ), ); diff --git a/uni/lib/view/schedule/widgets/schedule_slot.dart b/uni/lib/view/schedule/widgets/schedule_slot.dart index 89f935bb2..efea349fc 100644 --- a/uni/lib/view/schedule/widgets/schedule_slot.dart +++ b/uni/lib/view/schedule/widgets/schedule_slot.dart @@ -1,8 +1,8 @@ import 'package:flutter/material.dart'; import 'package:intl/intl.dart'; import 'package:uni/controller/networking/network_router.dart'; +import 'package:uni/controller/networking/url_launcher.dart'; import 'package:uni/view/common_widgets/row_container.dart'; -import 'package:url_launcher/url_launcher.dart'; class ScheduleSlot extends StatelessWidget { const ScheduleSlot({ @@ -113,9 +113,9 @@ class SubjectButtonWidget extends StatelessWidget { 'UCURR_GERAL.FICHA_UC_VIEW?pv_ocorrencia_id=$occurrId'; } - Future _launchURL() async { + Future _launchURL(BuildContext context) async { final url = toUcLink(occurrId); - await launchUrl(Uri.parse(url)); + await launchUrlWithToast(context, url); } @override @@ -133,7 +133,7 @@ class SubjectButtonWidget extends StatelessWidget { color: Colors.grey, alignment: Alignment.centerRight, tooltip: 'Abrir página da UC no browser', - onPressed: _launchURL, + onPressed: () => _launchURL(context), ), ], ); diff --git a/uni/lib/view/useful_info/widgets/link_button.dart b/uni/lib/view/useful_info/widgets/link_button.dart index 4fc901bfb..f146bb074 100644 --- a/uni/lib/view/useful_info/widgets/link_button.dart +++ b/uni/lib/view/useful_info/widgets/link_button.dart @@ -1,5 +1,5 @@ import 'package:flutter/material.dart'; -import 'package:url_launcher/url_launcher.dart'; +import 'package:uni/controller/networking/url_launcher.dart'; class LinkButton extends StatelessWidget { const LinkButton({ @@ -27,7 +27,7 @@ class LinkButton extends StatelessWidget { .headlineSmall! .copyWith(decoration: TextDecoration.underline), ), - onTap: () => launchUrl(Uri.parse(link)), + onTap: () => launchUrlWithToast(context, link), ), ), ], diff --git a/uni/lib/view/useful_info/widgets/text_components.dart b/uni/lib/view/useful_info/widgets/text_components.dart index 345685277..7ef70043e 100644 --- a/uni/lib/view/useful_info/widgets/text_components.dart +++ b/uni/lib/view/useful_info/widgets/text_components.dart @@ -1,5 +1,5 @@ import 'package:flutter/material.dart'; -import 'package:url_launcher/url_launcher.dart'; +import 'package:uni/controller/networking/url_launcher.dart'; Container h1(String text, BuildContext context, {bool initial = false}) { final marginTop = initial ? 15.0 : 30.0; @@ -44,7 +44,7 @@ Container infoText( .bodyLarge! .apply(color: Theme.of(context).colorScheme.tertiary), ), - onTap: () => link != '' ? launchUrl(Uri.parse(link)) : null, + onTap: () => launchUrlWithToast(context, link), ), ), );