Files
feeddeck/app/lib/widgets/source/add/add_source_googlenews.dart
Rico Berger 1c7c88a9ca [core] Submit "Add Source" Forms on Enter (#69)
All our forms were submitable via enter except the forms used to add a
new source to a column. This is now changed so that also these forms can
be submitted by pressing enter in a text field.
2023-11-07 23:12:46 +01:00

742 lines
16 KiB
Dart

import 'package:flutter/material.dart';
import 'package:flutter_markdown/flutter_markdown.dart';
import 'package:provider/provider.dart';
import 'package:feeddeck/models/column.dart';
import 'package:feeddeck/models/source.dart';
import 'package:feeddeck/models/sources/googlenews.dart';
import 'package:feeddeck/repositories/app_repository.dart';
import 'package:feeddeck/utils/api_exception.dart';
import 'package:feeddeck/utils/constants.dart';
import 'package:feeddeck/utils/openurl.dart';
import 'package:feeddeck/widgets/source/add/add_source_form.dart';
const _helpText = '''
The Google News source can be used to get the latest news from Google News. You
can provide the url of a Google News page or a search query:
- **URL**: Get the latest news from the provided Google News page, e.g.
`https://news.google.com/topics/CAAqJggKIiBDQkFTRWdvSUwyMHZNRFp1ZEdvU0FtUmxHZ0pFUlNnQVAB?hl=de&gl=DE&ceid=DE%3Ade`
or `https://news.google.com/rss/search?q=Sport&hl=de&gl=DE&ceid=DE:de`.
- **Search**: Get the latest news for the provided search term, e.g. `Sport`.
You also have to select the language and country for which you want to get the
news.
''';
/// The [AddSourceGoogleNews] widget is used to display the form to add a new
/// Google News source.
class AddSourceGoogleNews extends StatefulWidget {
const AddSourceGoogleNews({
super.key,
required this.column,
});
final FDColumn column;
@override
State<AddSourceGoogleNews> createState() => _AddSourceGoogleNewsState();
}
class _AddSourceGoogleNewsState extends State<AddSourceGoogleNews> {
final _formKey = GlobalKey<FormState>();
FDGoogleNewsType _googlenewsType = FDGoogleNewsType.url;
final _googlenewsUrl = TextEditingController();
final _googlenewsSearch = TextEditingController();
GoogleNewsCode _googlenewsCode = googlenewsCodes[0];
bool _isLoading = false;
String _error = '';
/// [_addSource] is used to add a new Google News source. Depending on the
/// selected [_googlenewsType] we need different information to add the source.
/// Which data is required for which type is defined in the [_buildForm]
/// function.
Future<void> _addSource() async {
setState(() {
_isLoading = true;
_error = '';
});
try {
AppRepository app = Provider.of<AppRepository>(context, listen: false);
await app.addSource(
widget.column.id,
FDSourceType.googlenews,
FDSourceOptions(
googlenews: FDGoogleNewsOptions(
type: _googlenewsType,
url: _googlenewsUrl.text,
search: _googlenewsSearch.text,
ceid: _googlenewsCode.ceid,
gl: _googlenewsCode.gl,
hl: _googlenewsCode.hl,
),
),
);
setState(() {
_isLoading = false;
_error = '';
});
if (mounted) {
Navigator.of(context).pop();
}
} on ApiException catch (err) {
setState(() {
_isLoading = false;
_error = 'Failed to add source: ${err.message}';
});
} catch (err) {
setState(() {
_isLoading = false;
_error = 'Failed to add source: ${err.toString()}';
});
}
}
/// [_buildForm] displays the correct fields for the selected
/// [_googlenewsType]. Depending on the type we need different information
/// from the user (e.g. a Google News URl or a search term).
List<Widget> _buildForm() {
if (_googlenewsType == FDGoogleNewsType.url) {
return [
TextFormField(
controller: _googlenewsUrl,
keyboardType: TextInputType.text,
autocorrect: false,
enableSuggestions: true,
maxLines: 1,
decoration: const InputDecoration(
border: OutlineInputBorder(),
labelText: 'Url',
),
onFieldSubmitted: (value) => _addSource(),
),
const SizedBox(height: Constants.spacingMiddle),
];
}
if (_googlenewsType == FDGoogleNewsType.search) {
return [
TextFormField(
controller: _googlenewsSearch,
keyboardType: TextInputType.text,
autocorrect: false,
enableSuggestions: true,
maxLines: 1,
decoration: const InputDecoration(
border: OutlineInputBorder(),
labelText: 'Search',
),
onFieldSubmitted: (value) => _addSource(),
),
const SizedBox(height: Constants.spacingMiddle),
DropdownButton<GoogleNewsCode>(
value: _googlenewsCode,
isExpanded: true,
underline: Container(height: 1, color: Constants.primary),
onChanged: (GoogleNewsCode? value) {
setState(() {
_googlenewsCode = value!;
});
},
items: googlenewsCodes
.map<DropdownMenuItem<GoogleNewsCode>>((GoogleNewsCode value) {
return DropdownMenuItem<GoogleNewsCode>(
value: value,
child: Text(value.name),
);
}).toList(),
),
const SizedBox(height: Constants.spacingMiddle),
];
}
return [];
}
@override
void dispose() {
_googlenewsUrl.dispose();
_googlenewsSearch.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return AddSourceForm(
onTap: _addSource,
isLoading: _isLoading,
error: _error,
child: Form(
key: _formKey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
MarkdownBody(
selectable: true,
data: _helpText,
onTapLink: (text, href, title) {
try {
if (href != null) {
openUrl(href);
}
} catch (_) {}
},
),
const SizedBox(
height: Constants.spacingMiddle,
),
DropdownButton<FDGoogleNewsType>(
value: _googlenewsType,
isExpanded: true,
underline: Container(height: 1, color: Constants.primary),
onChanged: (FDGoogleNewsType? value) {
setState(() {
_googlenewsType = value!;
});
},
items: FDGoogleNewsType.values
.map<DropdownMenuItem<FDGoogleNewsType>>(
(FDGoogleNewsType value) {
return DropdownMenuItem<FDGoogleNewsType>(
value: value,
child: Text(value.toLocalizedString()),
);
}).toList(),
),
const SizedBox(
height: Constants.spacingMiddle,
),
..._buildForm(),
],
),
),
);
}
}
/// [GoogleNewsCode] is the model for a supported language and region by Google
/// News.
class GoogleNewsCode {
String ceid;
String name;
String gl;
String hl;
GoogleNewsCode({
required this.ceid,
required this.name,
required this.gl,
required this.hl,
});
}
/// [googlenewsCodes] is the list of all supported languages and regions by
/// Google News.
final googlenewsCodes = <GoogleNewsCode>[
GoogleNewsCode(
ceid: 'DE:de',
name: 'Deutsch (Deutschland)',
gl: 'DE',
hl: 'de',
),
GoogleNewsCode(
ceid: 'AT:de',
name: 'Deutsch (Österreich)',
gl: 'AT',
hl: 'de',
),
GoogleNewsCode(
ceid: 'CH:de',
name: 'Deutsch (Schweiz)',
gl: 'CH',
hl: 'de',
),
GoogleNewsCode(
ceid: 'ID:id',
name: 'Bahasa Indonesia (Indonesia)',
gl: 'ID',
hl: 'id',
),
GoogleNewsCode(
ceid: 'CZ:cs',
name: 'Čeština (Česko)',
gl: 'CZ',
hl: 'cs',
),
GoogleNewsCode(
ceid: 'AU:en',
name: 'English (Australia)',
gl: 'AU',
hl: 'en',
),
GoogleNewsCode(
ceid: 'BW:en',
name: 'English (Botswana)',
gl: 'BW',
hl: 'en',
),
GoogleNewsCode(
ceid: 'CA:en',
name: 'English (Canada)',
gl: 'CA',
hl: 'en',
),
GoogleNewsCode(
ceid: 'ET:en',
name: 'English (Ethiopia)',
gl: 'ET',
hl: 'en',
),
GoogleNewsCode(
ceid: 'GH:en',
name: 'English (Ghana)',
gl: 'GH',
hl: 'en',
),
GoogleNewsCode(
ceid: 'IN:en',
name: 'English (India)',
gl: 'IN',
hl: 'en',
),
GoogleNewsCode(
ceid: 'ID:en',
name: 'English (Indonesia)',
gl: 'ID',
hl: 'en',
),
GoogleNewsCode(
ceid: 'IE:en',
name: 'English (Ireland)',
gl: 'IE',
hl: 'en',
),
GoogleNewsCode(
ceid: 'IL:en',
name: 'English (Israel)',
gl: 'IL',
hl: 'en',
),
GoogleNewsCode(
ceid: 'KE:en',
name: 'English (Kenya)',
gl: 'KE',
hl: 'en',
),
GoogleNewsCode(
ceid: 'LV:en',
name: 'English (Latvia)',
gl: 'LV',
hl: 'en',
),
GoogleNewsCode(
ceid: 'MY:en',
name: 'English (Malaysia)',
gl: 'MY',
hl: 'en',
),
GoogleNewsCode(
ceid: 'NA:en',
name: 'English (Namibia)',
gl: 'NA',
hl: 'en',
),
GoogleNewsCode(
ceid: 'NZ:en',
name: 'English (New Zealand)',
gl: 'NZ',
hl: 'en',
),
GoogleNewsCode(
ceid: 'NG:en',
name: 'English (Nigeria)',
gl: 'NG',
hl: 'en',
),
GoogleNewsCode(
ceid: 'PK:en',
name: 'English (Pakistan)',
gl: 'PK',
hl: 'en',
),
GoogleNewsCode(
ceid: 'PH:en',
name: 'English (Philippines)',
gl: 'PH',
hl: 'en',
),
GoogleNewsCode(
ceid: 'SG:en',
name: 'English (Singapore)',
gl: 'SG',
hl: 'en',
),
GoogleNewsCode(
ceid: 'ZA:en',
name: 'English (South Africa)',
gl: 'ZA',
hl: 'en',
),
GoogleNewsCode(
ceid: 'TZ:en',
name: 'English (Tanzania)',
gl: 'TZ',
hl: 'en',
),
GoogleNewsCode(
ceid: 'UG:en',
name: 'English (Uganda)',
gl: 'UG',
hl: 'en',
),
GoogleNewsCode(
ceid: 'GB:en',
name: 'English (United Kingdom)',
gl: 'GB',
hl: 'en',
),
GoogleNewsCode(
ceid: 'US:en',
name: 'English (United States)',
gl: 'US',
hl: 'en',
),
GoogleNewsCode(
ceid: 'ZW:en',
name: 'English (Zimbabwe)',
gl: 'ZW',
hl: 'en',
),
GoogleNewsCode(
ceid: 'AR:es-419',
name: 'Español (Argentina)',
gl: 'AR',
hl: 'es-419',
),
GoogleNewsCode(
ceid: 'CL:es-419',
name: 'Español (Chile)',
gl: 'CL',
hl: 'es-419',
),
GoogleNewsCode(
ceid: 'CO:es-419',
name: 'Español (Colombia)',
gl: 'CO',
hl: 'es-419',
),
GoogleNewsCode(
ceid: 'CU:es-419',
name: 'Español (Cuba)',
gl: 'CU',
hl: 'es-419',
),
GoogleNewsCode(
ceid: 'ES:es',
name: 'Español (España)',
gl: 'ES',
hl: 'es',
),
GoogleNewsCode(
ceid: 'US:es-419',
name: 'Español (Estados Unidos)',
gl: 'US',
hl: 'es-419',
),
GoogleNewsCode(
ceid: 'MX:es-419',
name: 'Español (México)',
gl: 'MX',
hl: 'es-419',
),
GoogleNewsCode(
ceid: 'PE:es-419',
name: 'Español (Perú)',
gl: 'PE',
hl: 'es-419',
),
GoogleNewsCode(
ceid: 'VE:es-419',
name: 'Español (Venezuela)',
gl: 'VE',
hl: 'es-419',
),
GoogleNewsCode(
ceid: 'BE:fr',
name: 'Français (Belgique)',
gl: 'BE',
hl: 'fr',
),
GoogleNewsCode(
ceid: 'CA:fr',
name: 'Français (Canada)',
gl: 'CA',
hl: 'fr',
),
GoogleNewsCode(
ceid: 'FR:fr',
name: 'Français (France)',
gl: 'FR',
hl: 'fr',
),
GoogleNewsCode(
ceid: 'MA:fr',
name: 'Français (Maroc)',
gl: 'MA',
hl: 'fr',
),
GoogleNewsCode(
ceid: 'SN:fr',
name: 'Français (Sénégal)',
gl: 'SN',
hl: 'fr',
),
GoogleNewsCode(
ceid: 'CH:fr',
name: 'Français (Suisse)',
gl: 'CH',
hl: 'fr',
),
GoogleNewsCode(
ceid: 'IT:it',
name: 'Italiano (Italia)',
gl: 'IT',
hl: 'it',
),
GoogleNewsCode(
ceid: 'LV:lv',
name: 'Latviešu (Latvija)',
gl: 'LV',
hl: 'lv',
),
GoogleNewsCode(
ceid: 'LT:lt',
name: 'Lietuvių (Lietuva)',
gl: 'LT',
hl: 'lt',
),
GoogleNewsCode(
ceid: 'HU:hu',
name: 'Magyar (Magyarország)',
gl: 'HU',
hl: 'hu',
),
GoogleNewsCode(
ceid: 'BE:nl',
name: 'Nederlands (België)',
gl: 'BE',
hl: 'nl',
),
GoogleNewsCode(
ceid: 'NL:nl',
name: 'Nederlands (Nederland)',
gl: 'NL',
hl: 'nl',
),
GoogleNewsCode(
ceid: 'NO:no',
name: 'Norsk (Norge)',
gl: 'NO',
hl: 'no',
),
GoogleNewsCode(
ceid: 'PL:pl',
name: 'Polski (Polska)',
gl: 'PL',
hl: 'pl',
),
GoogleNewsCode(
ceid: 'BR:pt-419',
name: 'Português (Brasil)',
gl: 'BR',
hl: 'pt-BR',
),
GoogleNewsCode(
ceid: 'PT:pt-150',
name: 'Português (Portugal)',
gl: 'PT',
hl: 'pt-PT',
),
GoogleNewsCode(
ceid: 'RO:ro',
name: 'Română (România)',
gl: 'RO',
hl: 'ro',
),
GoogleNewsCode(
ceid: 'SK:sk',
name: 'Slovenčina (Slovensko)',
gl: 'SK',
hl: 'sk',
),
GoogleNewsCode(
ceid: 'SI:sl',
name: 'Slovenščina (Slovenija)',
gl: 'SI',
hl: 'sl',
),
GoogleNewsCode(
ceid: 'SE:sv',
name: 'Svenska (Sverige)',
gl: 'SE',
hl: 'sv',
),
GoogleNewsCode(
ceid: 'VN:vi',
name: 'Tiếng Việt (Việt Nam)',
gl: 'VN',
hl: 'vi',
),
GoogleNewsCode(
ceid: 'TR:tr',
name: 'Türkçe (Türkiye)',
gl: 'TR',
hl: 'tr',
),
GoogleNewsCode(
ceid: 'GR:el',
name: 'Ελληνικά (Ελλάδα)',
gl: 'GR',
hl: 'el',
),
GoogleNewsCode(
ceid: 'BG:bg',
name: 'Български (България)',
gl: 'BG',
hl: 'bg',
),
GoogleNewsCode(
ceid: 'RU:ru',
name: 'Русский (Россия)',
gl: 'RU',
hl: 'ru',
),
GoogleNewsCode(
ceid: 'UA:ru',
name: 'Русский (Украина)',
gl: 'UA',
hl: 'ru',
),
GoogleNewsCode(
ceid: 'RS:sr',
name: 'Српски (Србија)',
gl: 'RS',
hl: 'sr',
),
GoogleNewsCode(
ceid: 'UA:uk',
name: 'Українська (Україна)',
gl: 'UA',
hl: 'uk',
),
GoogleNewsCode(
ceid: 'IL:he',
name: 'עברית (ישראל)',
gl: 'IL',
hl: 'he',
),
GoogleNewsCode(
ceid: 'AE:ar',
name: 'العربية (الإمارات العربية المتحدة)',
gl: 'AE',
hl: 'ar',
),
GoogleNewsCode(
ceid: 'SA:ar',
name: 'العربية (المملكة العربية السعودية)',
gl: 'SA',
hl: 'ar',
),
GoogleNewsCode(
ceid: 'LB:ar',
name: 'العربية (لبنان)',
gl: 'LB',
hl: 'ar',
),
GoogleNewsCode(
ceid: 'EG:ar',
name: 'العربية (مصر)',
gl: 'EG',
hl: 'ar',
),
GoogleNewsCode(
ceid: 'IN:mr',
name: 'मराठी (भारत)',
gl: 'IN',
hl: 'mr',
),
GoogleNewsCode(
ceid: 'IN:hi',
name: 'हिन्दी (भारत)',
gl: 'IN',
hl: 'hi',
),
GoogleNewsCode(
ceid: 'BD:bn',
name: 'বাংলা (বাংলাদেশ)',
gl: 'BD',
hl: 'bn',
),
GoogleNewsCode(
ceid: 'IN:bn',
name: 'বাংলা (ভারত)',
gl: 'IN',
hl: 'bn',
),
GoogleNewsCode(
ceid: 'IN:ta',
name: 'தமிழ் (இந்தியா)',
gl: 'IN',
hl: 'ta',
),
GoogleNewsCode(
ceid: 'IN:te',
name: 'తెలుగు (భారతదేశం)',
gl: 'IN',
hl: 'te',
),
GoogleNewsCode(
ceid: 'IN:ml',
name: 'മലയാളം (ഇന്ത്യ)',
gl: 'IN',
hl: 'ml',
),
GoogleNewsCode(
ceid: 'TH:th',
name: 'ไทย (ไทย)',
gl: 'TH',
hl: 'th',
),
GoogleNewsCode(
ceid: 'CN:zh-Hans',
name: '中文 (中国)',
gl: 'CN',
hl: 'zh-Hans',
),
GoogleNewsCode(
ceid: 'TW:zh-Hant',
name: '中文 (台灣)',
gl: 'TW',
hl: 'zh-TW',
),
GoogleNewsCode(
ceid: 'HK:zh-Hant',
name: '中文 (香港)',
gl: 'HK',
hl: 'zh-HK',
),
GoogleNewsCode(
ceid: 'JP:ja',
name: '日本語 (日本)',
gl: 'JP',
hl: 'ja',
),
GoogleNewsCode(
ceid: 'KR:ko',
name: '한국어 (대한민국)',
gl: 'KR',
hl: 'ko',
),
];