Add default feed mode, explore feed sort, and comment sort options
This commit is contained in:
parent
e15c4e862f
commit
6e16a3ac1d
|
@ -0,0 +1,35 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:interstellar/src/widgets/selection_menu.dart';
|
||||||
|
|
||||||
|
enum CommentSort { newest, top, hot, active, oldest }
|
||||||
|
|
||||||
|
const SelectionMenu<CommentSort> commentSortSelect = SelectionMenu(
|
||||||
|
'Sort Comments',
|
||||||
|
[
|
||||||
|
SelectionMenuItem(
|
||||||
|
value: CommentSort.hot,
|
||||||
|
title: 'Hot',
|
||||||
|
icon: Icons.local_fire_department,
|
||||||
|
),
|
||||||
|
SelectionMenuItem(
|
||||||
|
value: CommentSort.top,
|
||||||
|
title: 'Top',
|
||||||
|
icon: Icons.trending_up,
|
||||||
|
),
|
||||||
|
SelectionMenuItem(
|
||||||
|
value: CommentSort.newest,
|
||||||
|
title: 'Newest',
|
||||||
|
icon: Icons.auto_awesome_rounded,
|
||||||
|
),
|
||||||
|
SelectionMenuItem(
|
||||||
|
value: CommentSort.active,
|
||||||
|
title: 'Active',
|
||||||
|
icon: Icons.rocket_launch,
|
||||||
|
),
|
||||||
|
SelectionMenuItem(
|
||||||
|
value: CommentSort.oldest,
|
||||||
|
title: 'Oldest',
|
||||||
|
icon: Icons.access_time_outlined,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
|
@ -1,17 +1,16 @@
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
|
|
||||||
import 'package:http/http.dart' as http;
|
import 'package:http/http.dart' as http;
|
||||||
|
import 'package:interstellar/src/api/comment.dart';
|
||||||
import 'package:interstellar/src/models/entry_comment.dart';
|
import 'package:interstellar/src/models/entry_comment.dart';
|
||||||
import 'package:interstellar/src/utils/utils.dart';
|
import 'package:interstellar/src/utils/utils.dart';
|
||||||
|
|
||||||
enum CommentsSort { newest, top, hot, active, oldest }
|
|
||||||
|
|
||||||
Future<EntryCommentListModel> fetchComments(
|
Future<EntryCommentListModel> fetchComments(
|
||||||
http.Client client,
|
http.Client client,
|
||||||
String instanceHost,
|
String instanceHost,
|
||||||
int entryId, {
|
int entryId, {
|
||||||
int? page,
|
int? page,
|
||||||
CommentsSort? sort,
|
CommentSort? sort,
|
||||||
}) async {
|
}) async {
|
||||||
final response = await client.get(Uri.https(
|
final response = await client.get(Uri.https(
|
||||||
instanceHost,
|
instanceHost,
|
|
@ -1,17 +1,16 @@
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
|
|
||||||
import 'package:http/http.dart' as http;
|
import 'package:http/http.dart' as http;
|
||||||
|
import 'package:interstellar/src/api/comment.dart';
|
||||||
import 'package:interstellar/src/models/post_comment.dart';
|
import 'package:interstellar/src/models/post_comment.dart';
|
||||||
import 'package:interstellar/src/utils/utils.dart';
|
import 'package:interstellar/src/utils/utils.dart';
|
||||||
|
|
||||||
enum CommentsSort { newest, top, hot, active, oldest }
|
|
||||||
|
|
||||||
Future<PostCommentListModel> fetchComments(
|
Future<PostCommentListModel> fetchComments(
|
||||||
http.Client client,
|
http.Client client,
|
||||||
String instanceHost,
|
String instanceHost,
|
||||||
int postId, {
|
int postId, {
|
||||||
int? page,
|
int? page,
|
||||||
CommentsSort? sort,
|
CommentSort? sort,
|
||||||
}) async {
|
}) async {
|
||||||
final response = await client.get(Uri.https(
|
final response = await client.get(Uri.https(
|
||||||
instanceHost,
|
instanceHost,
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:interstellar/src/api/comments.dart' as api_comments;
|
import 'package:interstellar/src/api/entry_comments.dart' as api_comments;
|
||||||
import 'package:interstellar/src/models/entry_comment.dart';
|
import 'package:interstellar/src/models/entry_comment.dart';
|
||||||
import 'package:interstellar/src/screens/entries/entry_comment_screen.dart';
|
import 'package:interstellar/src/screens/entries/entry_comment_screen.dart';
|
||||||
import 'package:interstellar/src/screens/settings/settings_controller.dart';
|
import 'package:interstellar/src/screens/settings/settings_controller.dart';
|
||||||
|
@ -134,8 +134,10 @@ class _EntryCommentState extends State<EntryComment> {
|
||||||
TextButton(
|
TextButton(
|
||||||
onPressed: () => Navigator.of(context).push(
|
onPressed: () => Navigator.of(context).push(
|
||||||
MaterialPageRoute(
|
MaterialPageRoute(
|
||||||
builder: (context) =>
|
builder: (context) => EntryCommentScreen(
|
||||||
EntryCommentScreen(widget.comment.commentId, opUserId: widget.opUserId),
|
widget.comment.commentId,
|
||||||
|
opUserId: widget.opUserId,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
child: Text(
|
child: Text(
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:interstellar/src/api/comments.dart';
|
import 'package:interstellar/src/api/entry_comments.dart';
|
||||||
import 'package:interstellar/src/models/entry_comment.dart';
|
import 'package:interstellar/src/models/entry_comment.dart';
|
||||||
import 'package:interstellar/src/screens/entries/entry_comment.dart';
|
import 'package:interstellar/src/screens/entries/entry_comment.dart';
|
||||||
import 'package:interstellar/src/screens/settings/settings_controller.dart';
|
import 'package:interstellar/src/screens/settings/settings_controller.dart';
|
||||||
|
@ -49,11 +49,11 @@ class _EntryCommentScreenState extends State<EntryCommentScreen> {
|
||||||
vertical: 4,
|
vertical: 4,
|
||||||
),
|
),
|
||||||
child: EntryComment(
|
child: EntryComment(
|
||||||
_comment!,
|
_comment!,
|
||||||
(newComment) => setState(() {
|
(newComment) => setState(() {
|
||||||
_comment = newComment;
|
_comment = newComment;
|
||||||
}), opUserId: widget.opUserId
|
}),
|
||||||
),
|
opUserId: widget.opUserId),
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:infinite_scroll_pagination/infinite_scroll_pagination.dart';
|
import 'package:infinite_scroll_pagination/infinite_scroll_pagination.dart';
|
||||||
import 'package:interstellar/src/api/comments.dart' as api_comments;
|
import 'package:interstellar/src/api/comment.dart';
|
||||||
import 'package:interstellar/src/api/entries.dart' as api_entries;
|
import 'package:interstellar/src/api/entries.dart' as api_entries;
|
||||||
|
import 'package:interstellar/src/api/entry_comments.dart' as api_comments;
|
||||||
import 'package:interstellar/src/models/entry.dart';
|
import 'package:interstellar/src/models/entry.dart';
|
||||||
import 'package:interstellar/src/models/entry_comment.dart';
|
import 'package:interstellar/src/models/entry_comment.dart';
|
||||||
import 'package:interstellar/src/screens/entries/entry_comment.dart';
|
import 'package:interstellar/src/screens/entries/entry_comment.dart';
|
||||||
|
@ -27,7 +28,7 @@ class EntryPage extends StatefulWidget {
|
||||||
class _EntryPageState extends State<EntryPage> {
|
class _EntryPageState extends State<EntryPage> {
|
||||||
EntryModel? _data;
|
EntryModel? _data;
|
||||||
|
|
||||||
api_comments.CommentsSort commentsSort = api_comments.CommentsSort.hot;
|
CommentSort commentSort = CommentSort.hot;
|
||||||
|
|
||||||
final PagingController<int, EntryCommentModel> _pagingController =
|
final PagingController<int, EntryCommentModel> _pagingController =
|
||||||
PagingController(firstPageKey: 1);
|
PagingController(firstPageKey: 1);
|
||||||
|
@ -37,6 +38,7 @@ class _EntryPageState extends State<EntryPage> {
|
||||||
super.initState();
|
super.initState();
|
||||||
|
|
||||||
_data = widget.initData;
|
_data = widget.initData;
|
||||||
|
commentSort = context.read<SettingsController>().defaultCommentSort;
|
||||||
|
|
||||||
_pagingController.addPageRequestListener(_fetchPage);
|
_pagingController.addPageRequestListener(_fetchPage);
|
||||||
}
|
}
|
||||||
|
@ -55,7 +57,7 @@ class _EntryPageState extends State<EntryPage> {
|
||||||
context.read<SettingsController>().instanceHost,
|
context.read<SettingsController>().instanceHost,
|
||||||
_data!.entryId,
|
_data!.entryId,
|
||||||
page: pageKey,
|
page: pageKey,
|
||||||
sort: commentsSort,
|
sort: commentSort,
|
||||||
);
|
);
|
||||||
|
|
||||||
// Check BuildContext
|
// Check BuildContext
|
||||||
|
@ -88,6 +90,25 @@ class _EntryPageState extends State<EntryPage> {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: Text(_data?.title ?? ''),
|
title: Text(_data?.title ?? ''),
|
||||||
|
actions: [
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.only(right: 8),
|
||||||
|
child: IconButton(
|
||||||
|
onPressed: () async {
|
||||||
|
final newSort = await commentSortSelect.inquireSelection(
|
||||||
|
context, commentSort);
|
||||||
|
|
||||||
|
if (newSort != null && newSort != commentSort) {
|
||||||
|
setState(() {
|
||||||
|
commentSort = newSort;
|
||||||
|
_pagingController.refresh();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
icon: const Icon(Icons.sort),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
body: RefreshIndicator(
|
body: RefreshIndicator(
|
||||||
onRefresh: () => Future.sync(
|
onRefresh: () => Future.sync(
|
||||||
|
@ -153,48 +174,6 @@ class _EntryPageState extends State<EntryPage> {
|
||||||
: null,
|
: null,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
SliverToBoxAdapter(
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.all(12),
|
|
||||||
child: Row(
|
|
||||||
children: [
|
|
||||||
DropdownButton<api_comments.CommentsSort>(
|
|
||||||
value: commentsSort,
|
|
||||||
onChanged: (newSort) {
|
|
||||||
if (newSort != null) {
|
|
||||||
setState(() {
|
|
||||||
commentsSort = newSort;
|
|
||||||
_pagingController.refresh();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
items: const [
|
|
||||||
DropdownMenuItem(
|
|
||||||
value: api_comments.CommentsSort.hot,
|
|
||||||
child: Text('Hot'),
|
|
||||||
),
|
|
||||||
DropdownMenuItem(
|
|
||||||
value: api_comments.CommentsSort.top,
|
|
||||||
child: Text('Top'),
|
|
||||||
),
|
|
||||||
DropdownMenuItem(
|
|
||||||
value: api_comments.CommentsSort.newest,
|
|
||||||
child: Text('Newest'),
|
|
||||||
),
|
|
||||||
DropdownMenuItem(
|
|
||||||
value: api_comments.CommentsSort.active,
|
|
||||||
child: Text('Active'),
|
|
||||||
),
|
|
||||||
DropdownMenuItem(
|
|
||||||
value: api_comments.CommentsSort.oldest,
|
|
||||||
child: Text('Oldest'),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
PagedSliverList<int, EntryCommentModel>(
|
PagedSliverList<int, EntryCommentModel>(
|
||||||
pagingController: _pagingController,
|
pagingController: _pagingController,
|
||||||
builderDelegate: PagedChildBuilderDelegate<EntryCommentModel>(
|
builderDelegate: PagedChildBuilderDelegate<EntryCommentModel>(
|
||||||
|
|
|
@ -35,14 +35,19 @@ class FeedScreen extends StatefulWidget {
|
||||||
enum FeedMode { entries, posts }
|
enum FeedMode { entries, posts }
|
||||||
|
|
||||||
class _FeedScreenState extends State<FeedScreen> {
|
class _FeedScreenState extends State<FeedScreen> {
|
||||||
FeedMode _feedMode = FeedMode.entries;
|
FeedMode _mode = FeedMode.entries;
|
||||||
FeedSort _sort = FeedSort.hot;
|
FeedSort _sort = FeedSort.hot;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
|
|
||||||
_sort = context.read<SettingsController>().defaultFeedSort;
|
_mode = (widget.source ?? const FeedSourceAll()).getPostsPath() != null
|
||||||
|
? context.read<SettingsController>().defaultFeedMode
|
||||||
|
: FeedMode.entries;
|
||||||
|
_sort = widget.source == null
|
||||||
|
? context.read<SettingsController>().defaultFeedSort
|
||||||
|
: context.read<SettingsController>().defaultExploreFeedSort;
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -76,10 +81,10 @@ class _FeedScreenState extends State<FeedScreen> {
|
||||||
tapTargetSize: MaterialTapTargetSize.shrinkWrap,
|
tapTargetSize: MaterialTapTargetSize.shrinkWrap,
|
||||||
visualDensity: VisualDensity(horizontal: -3, vertical: -3),
|
visualDensity: VisualDensity(horizontal: -3, vertical: -3),
|
||||||
),
|
),
|
||||||
selected: <FeedMode>{_feedMode},
|
selected: <FeedMode>{_mode},
|
||||||
onSelectionChanged: (Set<FeedMode> newSelection) {
|
onSelectionChanged: (Set<FeedMode> newSelection) {
|
||||||
setState(() {
|
setState(() {
|
||||||
_feedMode = newSelection.first;
|
_mode = newSelection.first;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
@ -99,7 +104,7 @@ class _FeedScreenState extends State<FeedScreen> {
|
||||||
},
|
},
|
||||||
icon: const Icon(Icons.sort),
|
icon: const Icon(Icons.sort),
|
||||||
),
|
),
|
||||||
)
|
),
|
||||||
],
|
],
|
||||||
bottom: widget.source == null
|
bottom: widget.source == null
|
||||||
? whenLoggedIn(
|
? whenLoggedIn(
|
||||||
|
@ -129,7 +134,7 @@ class _FeedScreenState extends State<FeedScreen> {
|
||||||
? FeedScreenBody(
|
? FeedScreenBody(
|
||||||
source: widget.source!,
|
source: widget.source!,
|
||||||
sort: _sort,
|
sort: _sort,
|
||||||
mode: _feedMode,
|
mode: _mode,
|
||||||
details: widget.details,
|
details: widget.details,
|
||||||
)
|
)
|
||||||
: whenLoggedIn(
|
: whenLoggedIn(
|
||||||
|
@ -139,25 +144,25 @@ class _FeedScreenState extends State<FeedScreen> {
|
||||||
FeedScreenBody(
|
FeedScreenBody(
|
||||||
source: const FeedSourceSub(),
|
source: const FeedSourceSub(),
|
||||||
sort: _sort,
|
sort: _sort,
|
||||||
mode: _feedMode,
|
mode: _mode,
|
||||||
details: widget.details,
|
details: widget.details,
|
||||||
),
|
),
|
||||||
FeedScreenBody(
|
FeedScreenBody(
|
||||||
source: const FeedSourceMod(),
|
source: const FeedSourceMod(),
|
||||||
sort: _sort,
|
sort: _sort,
|
||||||
mode: _feedMode,
|
mode: _mode,
|
||||||
details: widget.details,
|
details: widget.details,
|
||||||
),
|
),
|
||||||
FeedScreenBody(
|
FeedScreenBody(
|
||||||
source: const FeedSourceFav(),
|
source: const FeedSourceFav(),
|
||||||
sort: _sort,
|
sort: _sort,
|
||||||
mode: _feedMode,
|
mode: _mode,
|
||||||
details: widget.details,
|
details: widget.details,
|
||||||
),
|
),
|
||||||
FeedScreenBody(
|
FeedScreenBody(
|
||||||
source: const FeedSourceAll(),
|
source: const FeedSourceAll(),
|
||||||
sort: _sort,
|
sort: _sort,
|
||||||
mode: _feedMode,
|
mode: _mode,
|
||||||
details: widget.details,
|
details: widget.details,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
@ -165,7 +170,7 @@ class _FeedScreenState extends State<FeedScreen> {
|
||||||
otherwise: FeedScreenBody(
|
otherwise: FeedScreenBody(
|
||||||
source: const FeedSourceAll(),
|
source: const FeedSourceAll(),
|
||||||
sort: _sort,
|
sort: _sort,
|
||||||
mode: _feedMode,
|
mode: _mode,
|
||||||
details: widget.details,
|
details: widget.details,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:infinite_scroll_pagination/infinite_scroll_pagination.dart';
|
import 'package:infinite_scroll_pagination/infinite_scroll_pagination.dart';
|
||||||
|
import 'package:interstellar/src/api/comment.dart';
|
||||||
import 'package:interstellar/src/api/post_comments.dart' as api_comments;
|
import 'package:interstellar/src/api/post_comments.dart' as api_comments;
|
||||||
import 'package:interstellar/src/api/posts.dart' as api_posts;
|
import 'package:interstellar/src/api/posts.dart' as api_posts;
|
||||||
import 'package:interstellar/src/models/post.dart';
|
import 'package:interstellar/src/models/post.dart';
|
||||||
|
@ -27,7 +28,7 @@ class PostPage extends StatefulWidget {
|
||||||
class _PostPageState extends State<PostPage> {
|
class _PostPageState extends State<PostPage> {
|
||||||
PostModel? _data;
|
PostModel? _data;
|
||||||
|
|
||||||
api_comments.CommentsSort commentsSort = api_comments.CommentsSort.hot;
|
CommentSort commentSort = CommentSort.hot;
|
||||||
|
|
||||||
final PagingController<int, PostCommentModel> _pagingController =
|
final PagingController<int, PostCommentModel> _pagingController =
|
||||||
PagingController(firstPageKey: 1);
|
PagingController(firstPageKey: 1);
|
||||||
|
@ -37,6 +38,7 @@ class _PostPageState extends State<PostPage> {
|
||||||
super.initState();
|
super.initState();
|
||||||
|
|
||||||
_data = widget.initData;
|
_data = widget.initData;
|
||||||
|
commentSort = context.read<SettingsController>().defaultCommentSort;
|
||||||
|
|
||||||
_pagingController.addPageRequestListener(_fetchPage);
|
_pagingController.addPageRequestListener(_fetchPage);
|
||||||
}
|
}
|
||||||
|
@ -55,7 +57,7 @@ class _PostPageState extends State<PostPage> {
|
||||||
context.read<SettingsController>().instanceHost,
|
context.read<SettingsController>().instanceHost,
|
||||||
_data!.postId,
|
_data!.postId,
|
||||||
page: pageKey,
|
page: pageKey,
|
||||||
sort: commentsSort,
|
sort: commentSort,
|
||||||
);
|
);
|
||||||
|
|
||||||
// Check BuildContext
|
// Check BuildContext
|
||||||
|
@ -86,6 +88,25 @@ class _PostPageState extends State<PostPage> {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: Text(_data?.user.username ?? ''),
|
title: Text(_data?.user.username ?? ''),
|
||||||
|
actions: [
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.only(right: 8),
|
||||||
|
child: IconButton(
|
||||||
|
onPressed: () async {
|
||||||
|
final newSort = await commentSortSelect.inquireSelection(
|
||||||
|
context, commentSort);
|
||||||
|
|
||||||
|
if (newSort != null && newSort != commentSort) {
|
||||||
|
setState(() {
|
||||||
|
commentSort = newSort;
|
||||||
|
_pagingController.refresh();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
icon: const Icon(Icons.sort),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
body: RefreshIndicator(
|
body: RefreshIndicator(
|
||||||
onRefresh: () => Future.sync(
|
onRefresh: () => Future.sync(
|
||||||
|
@ -149,48 +170,6 @@ class _PostPageState extends State<PostPage> {
|
||||||
: null,
|
: null,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
SliverToBoxAdapter(
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.all(12),
|
|
||||||
child: Row(
|
|
||||||
children: [
|
|
||||||
DropdownButton<api_comments.CommentsSort>(
|
|
||||||
value: commentsSort,
|
|
||||||
onChanged: (newSort) {
|
|
||||||
if (newSort != null) {
|
|
||||||
setState(() {
|
|
||||||
commentsSort = newSort;
|
|
||||||
_pagingController.refresh();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
items: const [
|
|
||||||
DropdownMenuItem(
|
|
||||||
value: api_comments.CommentsSort.hot,
|
|
||||||
child: Text('Hot'),
|
|
||||||
),
|
|
||||||
DropdownMenuItem(
|
|
||||||
value: api_comments.CommentsSort.top,
|
|
||||||
child: Text('Top'),
|
|
||||||
),
|
|
||||||
DropdownMenuItem(
|
|
||||||
value: api_comments.CommentsSort.newest,
|
|
||||||
child: Text('Newest'),
|
|
||||||
),
|
|
||||||
DropdownMenuItem(
|
|
||||||
value: api_comments.CommentsSort.active,
|
|
||||||
child: Text('Active'),
|
|
||||||
),
|
|
||||||
DropdownMenuItem(
|
|
||||||
value: api_comments.CommentsSort.oldest,
|
|
||||||
child: Text('Oldest'),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
PagedSliverList<int, PostCommentModel>(
|
PagedSliverList<int, PostCommentModel>(
|
||||||
pagingController: _pagingController,
|
pagingController: _pagingController,
|
||||||
builderDelegate: PagedChildBuilderDelegate<PostCommentModel>(
|
builderDelegate: PagedChildBuilderDelegate<PostCommentModel>(
|
||||||
|
|
|
@ -2,16 +2,24 @@ import 'dart:convert';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:http/http.dart' as http;
|
import 'package:http/http.dart' as http;
|
||||||
|
import 'package:interstellar/src/api/comment.dart';
|
||||||
import 'package:interstellar/src/api/feed_source.dart';
|
import 'package:interstellar/src/api/feed_source.dart';
|
||||||
import 'package:interstellar/src/api/oauth.dart';
|
import 'package:interstellar/src/api/oauth.dart';
|
||||||
|
import 'package:interstellar/src/screens/feed_screen.dart';
|
||||||
import 'package:oauth2/oauth2.dart' as oauth2;
|
import 'package:oauth2/oauth2.dart' as oauth2;
|
||||||
import 'package:shared_preferences/shared_preferences.dart';
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
|
|
||||||
class SettingsController with ChangeNotifier {
|
class SettingsController with ChangeNotifier {
|
||||||
late ThemeMode _themeMode;
|
late ThemeMode _themeMode;
|
||||||
ThemeMode get themeMode => _themeMode;
|
ThemeMode get themeMode => _themeMode;
|
||||||
|
late FeedMode _defaultFeedMode;
|
||||||
|
FeedMode get defaultFeedMode => _defaultFeedMode;
|
||||||
late FeedSort _defaultFeedSort;
|
late FeedSort _defaultFeedSort;
|
||||||
FeedSort get defaultFeedSort => _defaultFeedSort;
|
FeedSort get defaultFeedSort => _defaultFeedSort;
|
||||||
|
late FeedSort _defaultExploreFeedSort;
|
||||||
|
FeedSort get defaultExploreFeedSort => _defaultExploreFeedSort;
|
||||||
|
late CommentSort _defaultCommentSort;
|
||||||
|
CommentSort get defaultCommentSort => _defaultCommentSort;
|
||||||
|
|
||||||
late Map<String, String> _oauthIdentifiers;
|
late Map<String, String> _oauthIdentifiers;
|
||||||
late Map<String, oauth2.Credentials?> _oauthCredentials;
|
late Map<String, oauth2.Credentials?> _oauthCredentials;
|
||||||
|
@ -31,9 +39,18 @@ class SettingsController with ChangeNotifier {
|
||||||
_themeMode = prefs.getString('themeMode') != null
|
_themeMode = prefs.getString('themeMode') != null
|
||||||
? ThemeMode.values.byName(prefs.getString("themeMode")!)
|
? ThemeMode.values.byName(prefs.getString("themeMode")!)
|
||||||
: ThemeMode.system;
|
: ThemeMode.system;
|
||||||
|
_defaultFeedMode = prefs.getString('defaultFeedMode') != null
|
||||||
|
? FeedMode.values.byName(prefs.getString("defaultFeedMode")!)
|
||||||
|
: FeedMode.entries;
|
||||||
_defaultFeedSort = prefs.getString('defaultFeedSort') != null
|
_defaultFeedSort = prefs.getString('defaultFeedSort') != null
|
||||||
? FeedSort.values.byName(prefs.getString("defaultFeedSort")!)
|
? FeedSort.values.byName(prefs.getString("defaultFeedSort")!)
|
||||||
: FeedSort.hot;
|
: FeedSort.hot;
|
||||||
|
_defaultExploreFeedSort = prefs.getString('defaultExploreFeedSort') != null
|
||||||
|
? FeedSort.values.byName(prefs.getString("defaultExploreFeedSort")!)
|
||||||
|
: FeedSort.newest;
|
||||||
|
_defaultCommentSort = prefs.getString('defaultCommentSort') != null
|
||||||
|
? CommentSort.values.byName(prefs.getString("defaultCommentSort")!)
|
||||||
|
: CommentSort.hot;
|
||||||
|
|
||||||
_oauthIdentifiers = (jsonDecode(prefs.getString('oauthIdentifiers') ?? '{}')
|
_oauthIdentifiers = (jsonDecode(prefs.getString('oauthIdentifiers') ?? '{}')
|
||||||
as Map<String, dynamic>)
|
as Map<String, dynamic>)
|
||||||
|
@ -62,6 +79,19 @@ class SettingsController with ChangeNotifier {
|
||||||
await prefs.setString('themeMode', newThemeMode.name);
|
await prefs.setString('themeMode', newThemeMode.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> updateDefaultFeedMode(FeedMode? newDefaultFeedMode) async {
|
||||||
|
if (newDefaultFeedMode == null) return;
|
||||||
|
|
||||||
|
if (newDefaultFeedMode == _defaultFeedMode) return;
|
||||||
|
|
||||||
|
_defaultFeedMode = newDefaultFeedMode;
|
||||||
|
|
||||||
|
notifyListeners();
|
||||||
|
|
||||||
|
final SharedPreferences prefs = await SharedPreferences.getInstance();
|
||||||
|
await prefs.setString('defaultFeedMode', newDefaultFeedMode.name);
|
||||||
|
}
|
||||||
|
|
||||||
Future<void> updateDefaultFeedSort(FeedSort? newDefaultFeedSort) async {
|
Future<void> updateDefaultFeedSort(FeedSort? newDefaultFeedSort) async {
|
||||||
if (newDefaultFeedSort == null) return;
|
if (newDefaultFeedSort == null) return;
|
||||||
|
|
||||||
|
@ -75,6 +105,37 @@ class SettingsController with ChangeNotifier {
|
||||||
await prefs.setString('defaultFeedSort', newDefaultFeedSort.name);
|
await prefs.setString('defaultFeedSort', newDefaultFeedSort.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> updateDefaultExploreFeedSort(
|
||||||
|
FeedSort? newDefaultExploreFeedSort,
|
||||||
|
) async {
|
||||||
|
if (newDefaultExploreFeedSort == null) return;
|
||||||
|
|
||||||
|
if (newDefaultExploreFeedSort == _defaultExploreFeedSort) return;
|
||||||
|
|
||||||
|
_defaultExploreFeedSort = newDefaultExploreFeedSort;
|
||||||
|
|
||||||
|
notifyListeners();
|
||||||
|
|
||||||
|
final SharedPreferences prefs = await SharedPreferences.getInstance();
|
||||||
|
await prefs.setString(
|
||||||
|
'defaultExploreFeedSort', newDefaultExploreFeedSort.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> updateDefaultCommentSort(
|
||||||
|
CommentSort? newDefaultCommentSort,
|
||||||
|
) async {
|
||||||
|
if (newDefaultCommentSort == null) return;
|
||||||
|
|
||||||
|
if (newDefaultCommentSort == _defaultCommentSort) return;
|
||||||
|
|
||||||
|
_defaultCommentSort = newDefaultCommentSort;
|
||||||
|
|
||||||
|
notifyListeners();
|
||||||
|
|
||||||
|
final SharedPreferences prefs = await SharedPreferences.getInstance();
|
||||||
|
await prefs.setString('defaultCommentSort', newDefaultCommentSort.name);
|
||||||
|
}
|
||||||
|
|
||||||
Future<String> getOAuthIdentifier(String instanceHost) async {
|
Future<String> getOAuthIdentifier(String instanceHost) async {
|
||||||
if (_oauthIdentifiers.containsKey(instanceHost)) {
|
if (_oauthIdentifiers.containsKey(instanceHost)) {
|
||||||
return _oauthIdentifiers[instanceHost]!;
|
return _oauthIdentifiers[instanceHost]!;
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:interstellar/src/api/comment.dart';
|
||||||
import 'package:interstellar/src/screens/feed_screen.dart';
|
import 'package:interstellar/src/screens/feed_screen.dart';
|
||||||
import 'package:interstellar/src/screens/settings/login.dart';
|
import 'package:interstellar/src/screens/settings/login.dart';
|
||||||
|
import 'package:interstellar/src/widgets/selection_menu.dart';
|
||||||
|
|
||||||
import 'settings_controller.dart';
|
import 'settings_controller.dart';
|
||||||
|
|
||||||
|
@ -11,9 +13,21 @@ class SettingsScreen extends StatelessWidget {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
final currentThemeMode = themeModeSelect.options.firstWhere(
|
||||||
|
(option) => option.value == controller.themeMode,
|
||||||
|
);
|
||||||
|
final currentDefaultFeedMode = feedModeSelect.options.firstWhere(
|
||||||
|
(option) => option.value == controller.defaultFeedMode,
|
||||||
|
);
|
||||||
final currentDefaultFeedSort = feedSortSelect.options.firstWhere(
|
final currentDefaultFeedSort = feedSortSelect.options.firstWhere(
|
||||||
(option) => option.value == controller.defaultFeedSort,
|
(option) => option.value == controller.defaultFeedSort,
|
||||||
);
|
);
|
||||||
|
final currentDefaultExploreFeedSort = feedSortSelect.options.firstWhere(
|
||||||
|
(option) => option.value == controller.defaultExploreFeedSort,
|
||||||
|
);
|
||||||
|
final currentDefaultCommentSort = commentSortSelect.options.firstWhere(
|
||||||
|
(option) => option.value == controller.defaultCommentSort,
|
||||||
|
);
|
||||||
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
|
@ -27,28 +41,50 @@ class SettingsScreen extends StatelessWidget {
|
||||||
child:
|
child:
|
||||||
Text('Theme', style: Theme.of(context).textTheme.titleMedium),
|
Text('Theme', style: Theme.of(context).textTheme.titleMedium),
|
||||||
),
|
),
|
||||||
DropdownButton<ThemeMode>(
|
ListTile(
|
||||||
value: controller.themeMode,
|
title: const Text('Theme Mode'),
|
||||||
onChanged: controller.updateThemeMode,
|
leading: const Icon(Icons.palette),
|
||||||
items: const [
|
onTap: () async {
|
||||||
DropdownMenuItem(
|
controller.updateThemeMode(
|
||||||
value: ThemeMode.system,
|
await themeModeSelect.inquireSelection(
|
||||||
child: Text('System Theme'),
|
context,
|
||||||
),
|
currentThemeMode.value,
|
||||||
DropdownMenuItem(
|
),
|
||||||
value: ThemeMode.light,
|
);
|
||||||
child: Text('Light Theme'),
|
},
|
||||||
),
|
trailing: Row(
|
||||||
DropdownMenuItem(
|
mainAxisSize: MainAxisSize.min,
|
||||||
value: ThemeMode.dark,
|
children: [
|
||||||
child: Text('Dark Theme'),
|
Icon(currentThemeMode.icon),
|
||||||
)
|
const SizedBox(width: 4),
|
||||||
],
|
Text(currentThemeMode.title),
|
||||||
|
],
|
||||||
|
),
|
||||||
),
|
),
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.symmetric(vertical: 8),
|
padding: const EdgeInsets.symmetric(vertical: 8),
|
||||||
child: Text('Feed', style: Theme.of(context).textTheme.titleMedium),
|
child: Text('Feed', style: Theme.of(context).textTheme.titleMedium),
|
||||||
),
|
),
|
||||||
|
ListTile(
|
||||||
|
title: const Text('Default Feed Mode'),
|
||||||
|
leading: const Icon(Icons.tab),
|
||||||
|
onTap: () async {
|
||||||
|
controller.updateDefaultFeedMode(
|
||||||
|
await feedModeSelect.inquireSelection(
|
||||||
|
context,
|
||||||
|
currentDefaultFeedMode.value,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
trailing: Row(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
Icon(currentDefaultFeedMode.icon),
|
||||||
|
const SizedBox(width: 4),
|
||||||
|
Text(currentDefaultFeedMode.title),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
ListTile(
|
ListTile(
|
||||||
title: const Text('Default Feed Sort'),
|
title: const Text('Default Feed Sort'),
|
||||||
leading: const Icon(Icons.sort),
|
leading: const Icon(Icons.sort),
|
||||||
|
@ -69,6 +105,46 @@ class SettingsScreen extends StatelessWidget {
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
ListTile(
|
||||||
|
title: const Text('Default Explore Feed Sort'),
|
||||||
|
leading: const Icon(Icons.sort),
|
||||||
|
onTap: () async {
|
||||||
|
controller.updateDefaultExploreFeedSort(
|
||||||
|
await feedSortSelect.inquireSelection(
|
||||||
|
context,
|
||||||
|
currentDefaultExploreFeedSort.value,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
trailing: Row(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
Icon(currentDefaultExploreFeedSort.icon),
|
||||||
|
const SizedBox(width: 4),
|
||||||
|
Text(currentDefaultExploreFeedSort.title),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
ListTile(
|
||||||
|
title: const Text('Default Comment Sort'),
|
||||||
|
leading: const Icon(Icons.comment),
|
||||||
|
onTap: () async {
|
||||||
|
controller.updateDefaultCommentSort(
|
||||||
|
await commentSortSelect.inquireSelection(
|
||||||
|
context,
|
||||||
|
currentDefaultCommentSort.value,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
trailing: Row(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
Icon(currentDefaultCommentSort.icon),
|
||||||
|
const SizedBox(width: 4),
|
||||||
|
Text(currentDefaultCommentSort.title),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.symmetric(vertical: 8),
|
padding: const EdgeInsets.symmetric(vertical: 8),
|
||||||
child: Text('Accounts',
|
child: Text('Accounts',
|
||||||
|
@ -110,19 +186,58 @@ class SettingsScreen extends StatelessWidget {
|
||||||
},
|
},
|
||||||
icon: const Icon(Icons.delete_outline)),
|
icon: const Icon(Icons.delete_outline)),
|
||||||
)),
|
)),
|
||||||
const SizedBox(height: 8),
|
Padding(
|
||||||
OutlinedButton(
|
padding: const EdgeInsets.all(8.0),
|
||||||
onPressed: () {
|
child: OutlinedButton(
|
||||||
Navigator.of(context).push(
|
onPressed: () {
|
||||||
MaterialPageRoute(
|
Navigator.of(context).push(
|
||||||
builder: (context) => const LoginScreen(),
|
MaterialPageRoute(
|
||||||
),
|
builder: (context) => const LoginScreen(),
|
||||||
);
|
),
|
||||||
},
|
);
|
||||||
child: const Text('Add Account'),
|
},
|
||||||
|
child: const Text('Add Account'),
|
||||||
|
),
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const SelectionMenu<ThemeMode> themeModeSelect = SelectionMenu(
|
||||||
|
'Theme Mode',
|
||||||
|
[
|
||||||
|
SelectionMenuItem(
|
||||||
|
value: ThemeMode.system,
|
||||||
|
title: 'System',
|
||||||
|
icon: Icons.auto_mode,
|
||||||
|
),
|
||||||
|
SelectionMenuItem(
|
||||||
|
value: ThemeMode.light,
|
||||||
|
title: 'Light',
|
||||||
|
icon: Icons.light_mode,
|
||||||
|
),
|
||||||
|
SelectionMenuItem(
|
||||||
|
value: ThemeMode.dark,
|
||||||
|
title: 'Dark',
|
||||||
|
icon: Icons.dark_mode,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
const SelectionMenu<FeedMode> feedModeSelect = SelectionMenu(
|
||||||
|
'Feed Mode',
|
||||||
|
[
|
||||||
|
SelectionMenuItem(
|
||||||
|
value: FeedMode.entries,
|
||||||
|
title: 'Threads',
|
||||||
|
icon: Icons.feed,
|
||||||
|
),
|
||||||
|
SelectionMenuItem(
|
||||||
|
value: FeedMode.posts,
|
||||||
|
title: 'Posts',
|
||||||
|
icon: Icons.chat,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
Loading…
Reference in New Issue