mark as read gesture
This commit is contained in:
parent
3dd315d37a
commit
0d3ca86df9
|
@ -25,7 +25,7 @@ class FeverAPI {
|
||||||
|
|
||||||
late final APICache cache;
|
late final APICache cache;
|
||||||
|
|
||||||
FeverAPI({ this.apiKey, this.apiUrl }) {
|
FeverAPI({this.apiKey, this.apiUrl}) {
|
||||||
cache = APICache(this);
|
cache = APICache(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39,7 +39,7 @@ class FeverAPI {
|
||||||
try {
|
try {
|
||||||
final response = jsonDecode((await http.post(Uri.parse(url))).body);
|
final response = jsonDecode((await http.post(Uri.parse(url))).body);
|
||||||
return response['api_version'] == 3;
|
return response['api_version'] == 3;
|
||||||
} catch(e) {
|
} catch (e) {
|
||||||
print(e);
|
print(e);
|
||||||
return false;
|
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
|
/// Checks whether the given API URL is a valid Fever API endpoint and the given API key is authorized to access it
|
||||||
static Future<bool> isAuthenticated(String url, String key) async {
|
static Future<bool> isAuthenticated(String url, String key) async {
|
||||||
try {
|
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;
|
return response['api_version'] == 3 && response['auth'] == 1;
|
||||||
} catch(e) {
|
} catch (e) {
|
||||||
print(e);
|
print(e);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -71,6 +72,8 @@ class APIRequestBuilder {
|
||||||
final http.Client _httpClient;
|
final http.Client _httpClient;
|
||||||
|
|
||||||
List<String> args = [];
|
List<String> args = [];
|
||||||
|
Item? _markedItem;
|
||||||
|
ItemMarkType? _markedItemAs;
|
||||||
|
|
||||||
APIRequestBuilder(this.api, this._httpClient);
|
APIRequestBuilder(this.api, this._httpClient);
|
||||||
|
|
||||||
|
@ -100,11 +103,23 @@ class APIRequestBuilder {
|
||||||
return this;
|
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
|
/// Executes the API request and returns the JSON data
|
||||||
Future<Map<String, dynamic>> fetch() async {
|
Future<Map<String, dynamic>> 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);
|
final data = jsonDecode((response).body);
|
||||||
if (data['auth'] == 0) throw UnauthenticatedException(data['auth']);
|
if (data['auth'] == 0) throw UnauthenticatedException(data['auth']);
|
||||||
return data;
|
return data;
|
||||||
|
@ -116,8 +131,8 @@ class APIRequestBuilder {
|
||||||
|
|
||||||
if (data.containsKey('groups')) {
|
if (data.containsKey('groups')) {
|
||||||
List<Group> groups = (data['groups'] as List<dynamic>)
|
List<Group> groups = (data['groups'] as List<dynamic>)
|
||||||
.map((json) => Group.fromJSON(api, json))
|
.map((json) => Group.fromJSON(api, json))
|
||||||
.toList();
|
.toList();
|
||||||
|
|
||||||
for (var group in groups) {
|
for (var group in groups) {
|
||||||
api.cache.groups.set(group.id, group);
|
api.cache.groups.set(group.id, group);
|
||||||
|
@ -126,8 +141,8 @@ class APIRequestBuilder {
|
||||||
|
|
||||||
if (data.containsKey('feeds')) {
|
if (data.containsKey('feeds')) {
|
||||||
List<Feed> feeds = (data['feeds'] as List<dynamic>)
|
List<Feed> feeds = (data['feeds'] as List<dynamic>)
|
||||||
.map((json) => Feed.fromJSON(api, json))
|
.map((json) => Feed.fromJSON(api, json))
|
||||||
.toList();
|
.toList();
|
||||||
|
|
||||||
for (var feed in feeds) {
|
for (var feed in feeds) {
|
||||||
api.cache.feeds.set(feed.id, feed);
|
api.cache.feeds.set(feed.id, feed);
|
||||||
|
@ -136,8 +151,8 @@ class APIRequestBuilder {
|
||||||
|
|
||||||
if (data.containsKey('items')) {
|
if (data.containsKey('items')) {
|
||||||
List<Item> items = (data['items'] as List<dynamic>)
|
List<Item> items = (data['items'] as List<dynamic>)
|
||||||
.map((json) => Item.fromJSON(api, json))
|
.map((json) => Item.fromJSON(api, json))
|
||||||
.toList();
|
.toList();
|
||||||
|
|
||||||
for (var item in items) {
|
for (var item in items) {
|
||||||
api.cache.items.set(item.id, item);
|
api.cache.items.set(item.id, item);
|
||||||
|
@ -146,11 +161,36 @@ class APIRequestBuilder {
|
||||||
|
|
||||||
if (data.containsKey('feeds_groups')) {
|
if (data.containsKey('feeds_groups')) {
|
||||||
List<FeedsGroup> feedsGroups = (data['feeds_groups'] as List<dynamic>)
|
List<FeedsGroup> feedsGroups = (data['feeds_groups'] as List<dynamic>)
|
||||||
.map((json) => FeedsGroup.fromJSON(api, json))
|
.map((json) => FeedsGroup.fromJSON(api, json))
|
||||||
.toList();
|
.toList();
|
||||||
|
|
||||||
api.cache.feedsGroups.clear();
|
api.cache.feedsGroups.clear();
|
||||||
api.cache.feedsGroups.addAll(feedsGroups);
|
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,
|
||||||
|
}
|
||||||
|
|
|
@ -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}';
|
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;
|
final Item post;
|
||||||
const HomepagePost({super.key, required this.post});
|
const HomepagePost({super.key, required this.post});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<StatefulWidget> createState() => _HomepagePostState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _HomepagePostState extends State<HomepagePost> {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
var post = widget.post;
|
||||||
return Container(
|
return Container(
|
||||||
margin: const EdgeInsets.symmetric(vertical: 6.0, horizontal: 8.0),
|
margin: const EdgeInsets.symmetric(vertical: 6.0, horizontal: 8.0),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
|
@ -27,9 +33,29 @@ class HomepagePost extends StatelessWidget {
|
||||||
child: InkWell(
|
child: InkWell(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
Navigator.of(context).push(
|
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)),
|
borderRadius: const BorderRadius.all(Radius.circular(15)),
|
||||||
child: Container(
|
child: Container(
|
||||||
margin: const EdgeInsets.all(8.0),
|
margin: const EdgeInsets.all(8.0),
|
||||||
|
|
Loading…
Reference in a new issue