diff --git a/lib/api/api.dart b/lib/api/api.dart index baacb37..37a32c5 100644 --- a/lib/api/api.dart +++ b/lib/api/api.dart @@ -25,7 +25,7 @@ class FeverAPI { late final APICache cache; - FeverAPI({ this.apiKey, this.apiUrl }) { + FeverAPI({this.apiKey, this.apiUrl}) { cache = APICache(this); } @@ -39,7 +39,7 @@ class FeverAPI { try { final response = jsonDecode((await http.post(Uri.parse(url))).body); return response['api_version'] == 3; - } catch(e) { + } catch (e) { print(e); return false; } @@ -48,9 +48,10 @@ class FeverAPI { /// Checks whether the given API URL is a valid Fever API endpoint and the given API key is authorized to access it static Future isAuthenticated(String url, String key) async { try { - final response = jsonDecode((await http.post(Uri.parse(url), body: { 'api_key': key })).body); + final response = jsonDecode( + (await http.post(Uri.parse(url), body: {'api_key': key})).body); return response['api_version'] == 3 && response['auth'] == 1; - } catch(e) { + } catch (e) { print(e); return false; } @@ -71,6 +72,8 @@ class APIRequestBuilder { final http.Client _httpClient; List args = []; + Item? _markedItem; + ItemMarkType? _markedItemAs; APIRequestBuilder(this.api, this._httpClient); @@ -100,11 +103,23 @@ class APIRequestBuilder { return this; } + APIRequestBuilder markItem(Item item, ItemMarkType markAs) { + _addArg('mark=item'); + _addArg('as=${markAs.name}'); + _addArg('id=${item.id}'); + _markedItem = item; + _markedItemAs = markAs; + return this; + } + /// Executes the API request and returns the JSON data Future> fetch() async { - if (api.apiKey == null || api.apiUrl == null) throw Exception('API Key or API URL not set'); + if (api.apiKey == null || api.apiUrl == null) { + throw Exception('API Key or API URL not set'); + } - final response = await _httpClient.post(generateUrl(), body: { 'api_key': api.apiKey }); + final response = + await _httpClient.post(generateUrl(), body: {'api_key': api.apiKey}); final data = jsonDecode((response).body); if (data['auth'] == 0) throw UnauthenticatedException(data['auth']); return data; @@ -116,8 +131,8 @@ class APIRequestBuilder { if (data.containsKey('groups')) { List groups = (data['groups'] as List) - .map((json) => Group.fromJSON(api, json)) - .toList(); + .map((json) => Group.fromJSON(api, json)) + .toList(); for (var group in groups) { api.cache.groups.set(group.id, group); @@ -126,8 +141,8 @@ class APIRequestBuilder { if (data.containsKey('feeds')) { List feeds = (data['feeds'] as List) - .map((json) => Feed.fromJSON(api, json)) - .toList(); + .map((json) => Feed.fromJSON(api, json)) + .toList(); for (var feed in feeds) { api.cache.feeds.set(feed.id, feed); @@ -136,8 +151,8 @@ class APIRequestBuilder { if (data.containsKey('items')) { List items = (data['items'] as List) - .map((json) => Item.fromJSON(api, json)) - .toList(); + .map((json) => Item.fromJSON(api, json)) + .toList(); for (var item in items) { api.cache.items.set(item.id, item); @@ -146,11 +161,36 @@ class APIRequestBuilder { if (data.containsKey('feeds_groups')) { List feedsGroups = (data['feeds_groups'] as List) - .map((json) => FeedsGroup.fromJSON(api, json)) - .toList(); + .map((json) => FeedsGroup.fromJSON(api, json)) + .toList(); api.cache.feedsGroups.clear(); api.cache.feedsGroups.addAll(feedsGroups); } + + if (_markedItem != null && _markedItemAs != null) { + switch (_markedItemAs!) { + case ItemMarkType.read: + _markedItem!.isRead = true; + break; + case ItemMarkType.unread: + _markedItem!.isRead = false; + break; + case ItemMarkType.saved: + _markedItem!.isSaved = true; + break; + case ItemMarkType.unsaved: + _markedItem!.isSaved = false; + break; + } + api.cache.items.set(_markedItem!.id, _markedItem!); + } } } + +enum ItemMarkType { + read, + unread, + saved, + unsaved, +} diff --git a/lib/widgets/homepage_post.dart b/lib/widgets/homepage_post.dart index b1499e9..a381e51 100644 --- a/lib/widgets/homepage_post.dart +++ b/lib/widgets/homepage_post.dart @@ -7,12 +7,18 @@ String formatDate(DateTime date) { return '${date.day}.${date.month}.${date.year}, ${date.hour}:${date.minute < 10 ? '0${date.minute}' : date.minute}'; } -class HomepagePost extends StatelessWidget { +class HomepagePost extends StatefulWidget { final Item post; const HomepagePost({super.key, required this.post}); + @override + State createState() => _HomepagePostState(); +} + +class _HomepagePostState extends State { @override Widget build(BuildContext context) { + var post = widget.post; return Container( margin: const EdgeInsets.symmetric(vertical: 6.0, horizontal: 8.0), decoration: BoxDecoration( @@ -27,9 +33,29 @@ class HomepagePost extends StatelessWidget { child: InkWell( onTap: () { Navigator.of(context).push( - MaterialPageRoute(builder: (context) => ArticlePage(article: post)), + MaterialPageRoute( + builder: (context) => ArticlePage(article: post)), ); }, + onLongPress: () async { + var theme = Theme.of(context); + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text( + 'Marking post as ${post.isRead ? 'Unread' : 'Read'}', + style: TextStyle(color: theme.colorScheme.onBackground) + ), + duration: const Duration(seconds: 2), + backgroundColor: theme.colorScheme.secondaryContainer, + ), + ); + await post.api + .request() + .markItem( + post, post.isRead ? ItemMarkType.unread : ItemMarkType.read) + .execute(); + setState(() {}); + }, borderRadius: const BorderRadius.all(Radius.circular(15)), child: Container( margin: const EdgeInsets.all(8.0),