Merge pull request #43 from krawieck/big-cleanup
This commit is contained in:
commit
87c14483c7
|
@ -5,6 +5,7 @@ linter:
|
||||||
public_member_api_docs: false
|
public_member_api_docs: false
|
||||||
prefer_expression_function_bodies: true
|
prefer_expression_function_bodies: true
|
||||||
prefer_single_quotes: true
|
prefer_single_quotes: true
|
||||||
|
prefer_final_locals: true
|
||||||
analyzer:
|
analyzer:
|
||||||
exclude:
|
exclude:
|
||||||
- '**/*.g.dart'
|
- "**/*.g.dart"
|
||||||
|
|
|
@ -21,7 +21,7 @@ class CommentTree {
|
||||||
|
|
||||||
static List<CommentTree> fromList(List<CommentView> comments) {
|
static List<CommentTree> fromList(List<CommentView> comments) {
|
||||||
CommentTree gatherChildren(CommentTree parent) {
|
CommentTree gatherChildren(CommentTree parent) {
|
||||||
for (var el in comments) {
|
for (final el in comments) {
|
||||||
if (el.parentId == parent.comment.id) {
|
if (el.parentId == parent.comment.id) {
|
||||||
parent.children.add(gatherChildren(CommentTree(el)));
|
parent.children.add(gatherChildren(CommentTree(el)));
|
||||||
}
|
}
|
||||||
|
@ -29,7 +29,7 @@ class CommentTree {
|
||||||
return parent;
|
return parent;
|
||||||
}
|
}
|
||||||
|
|
||||||
var parents = <CommentTree>[];
|
final parents = <CommentTree>[];
|
||||||
|
|
||||||
// first pass to get all the parents
|
// first pass to get all the parents
|
||||||
for (var i = 0; i < comments.length; i++) {
|
for (var i = 0; i < comments.length; i++) {
|
||||||
|
@ -38,7 +38,7 @@ class CommentTree {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var result = parents.map(gatherChildren).toList();
|
final result = parents.map(gatherChildren).toList();
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,7 +63,7 @@ class CommentTree {
|
||||||
|
|
||||||
void _sort(int compare(CommentTree a, CommentTree b)) {
|
void _sort(int compare(CommentTree a, CommentTree b)) {
|
||||||
children.sort(compare);
|
children.sort(compare);
|
||||||
for (var el in children) {
|
for (final el in children) {
|
||||||
el._sort(compare);
|
el._sort(compare);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,9 +23,9 @@ class DelayedLoading {
|
||||||
/// and loading is triggered after [delayDuration].
|
/// and loading is triggered after [delayDuration].
|
||||||
/// Everything can be reset with [.cancel()]
|
/// Everything can be reset with [.cancel()]
|
||||||
DelayedLoading useDelayedLoading(Duration delayDuration) {
|
DelayedLoading useDelayedLoading(Duration delayDuration) {
|
||||||
var loading = useState(false);
|
final loading = useState(false);
|
||||||
var pending = useState(false);
|
final pending = useState(false);
|
||||||
var timerHandle = useRef<Timer>(null);
|
final timerHandle = useRef<Timer>(null);
|
||||||
|
|
||||||
return DelayedLoading(
|
return DelayedLoading(
|
||||||
loading: loading.value,
|
loading: loading.value,
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
|
import '../stores/accounts_store.dart';
|
||||||
|
import '../stores/config_store.dart';
|
||||||
|
|
||||||
|
AccountsStore useAccountsStore() => useContext().watch<AccountsStore>();
|
||||||
|
ConfigStore useConfigStore() => useContext().watch<ConfigStore>();
|
116
lib/main.dart
116
lib/main.dart
|
@ -1,17 +1,23 @@
|
||||||
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
|
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
|
import 'hooks/stores.dart';
|
||||||
|
import 'pages/profile_tab.dart';
|
||||||
import 'stores/accounts_store.dart';
|
import 'stores/accounts_store.dart';
|
||||||
import 'stores/config_store.dart';
|
import 'stores/config_store.dart';
|
||||||
|
|
||||||
Future<void> main() async {
|
Future<void> main() async {
|
||||||
WidgetsFlutterBinding.ensureInitialized();
|
WidgetsFlutterBinding.ensureInitialized();
|
||||||
|
|
||||||
var configStore = ConfigStore();
|
final configStore = ConfigStore();
|
||||||
await configStore.load();
|
await configStore.load();
|
||||||
|
|
||||||
var accountsStore = AccountsStore();
|
final accountsStore = AccountsStore();
|
||||||
await accountsStore.load();
|
await accountsStore.load();
|
||||||
|
|
||||||
runApp(
|
runApp(
|
||||||
|
@ -31,71 +37,51 @@ Future<void> main() async {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
class MyApp extends StatelessWidget {
|
class MyApp extends HookWidget {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) => Observer(
|
Widget build(BuildContext context) {
|
||||||
builder: (ctx) {
|
final configStore = useConfigStore();
|
||||||
var maybeAmoledColor =
|
|
||||||
ctx.watch<ConfigStore>().amoledDarkMode ? Colors.black : null;
|
|
||||||
|
|
||||||
return MaterialApp(
|
return Observer(
|
||||||
title: 'Flutter Demo',
|
builder: (ctx) {
|
||||||
themeMode: ctx.watch<ConfigStore>().theme,
|
final maybeAmoledColor =
|
||||||
darkTheme: ThemeData.dark().copyWith(
|
configStore.amoledDarkMode ? Colors.black : null;
|
||||||
scaffoldBackgroundColor: maybeAmoledColor,
|
|
||||||
backgroundColor: maybeAmoledColor,
|
|
||||||
canvasColor: maybeAmoledColor,
|
|
||||||
cardColor: maybeAmoledColor,
|
|
||||||
splashColor: maybeAmoledColor,
|
|
||||||
),
|
|
||||||
theme: ThemeData(
|
|
||||||
visualDensity: VisualDensity.adaptivePlatformDensity,
|
|
||||||
),
|
|
||||||
home: MyHomePage(title: 'Flutter hello world'),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
class MyHomePage extends StatefulWidget {
|
return MaterialApp(
|
||||||
MyHomePage({Key key, this.title}) : super(key: key);
|
title: 'Lemmur',
|
||||||
|
themeMode: configStore.theme,
|
||||||
final String title;
|
darkTheme: ThemeData.dark().copyWith(
|
||||||
|
scaffoldBackgroundColor: maybeAmoledColor,
|
||||||
@override
|
backgroundColor: maybeAmoledColor,
|
||||||
_MyHomePageState createState() => _MyHomePageState();
|
canvasColor: maybeAmoledColor,
|
||||||
}
|
cardColor: maybeAmoledColor,
|
||||||
|
splashColor: maybeAmoledColor,
|
||||||
class _MyHomePageState extends State<MyHomePage> {
|
|
||||||
int _counter = 0;
|
|
||||||
|
|
||||||
void _incrementCounter() {
|
|
||||||
setState(() {
|
|
||||||
_counter++;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) => Scaffold(
|
|
||||||
appBar: AppBar(
|
|
||||||
title: Text(widget.title),
|
|
||||||
),
|
|
||||||
body: Center(
|
|
||||||
child: Column(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
children: <Widget>[
|
|
||||||
Text('You have pushed the button this many times:'),
|
|
||||||
Text(
|
|
||||||
'$_counter',
|
|
||||||
style: Theme.of(context).textTheme.headline4,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
),
|
theme: ThemeData(
|
||||||
floatingActionButton: FloatingActionButton(
|
visualDensity: VisualDensity.adaptivePlatformDensity,
|
||||||
onPressed: _incrementCounter,
|
),
|
||||||
tooltip: 'Increment',
|
home: MyHomePage(),
|
||||||
child: Icon(Icons.add),
|
);
|
||||||
),
|
},
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class MyHomePage extends HookWidget {
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final theme = Theme.of(context);
|
||||||
|
|
||||||
|
useEffect(() {
|
||||||
|
Future.microtask(
|
||||||
|
() => SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle(
|
||||||
|
systemNavigationBarColor: theme.scaffoldBackgroundColor,
|
||||||
|
)),
|
||||||
|
);
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}, [theme.scaffoldBackgroundColor]);
|
||||||
|
|
||||||
|
return UserProfileTab();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,10 +5,10 @@ import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||||
import 'package:fuzzy/fuzzy.dart';
|
import 'package:fuzzy/fuzzy.dart';
|
||||||
import 'package:lemmy_api_client/lemmy_api_client.dart';
|
import 'package:lemmy_api_client/lemmy_api_client.dart';
|
||||||
import 'package:provider/provider.dart';
|
|
||||||
|
|
||||||
import '../hooks/delayed_loading.dart';
|
import '../hooks/delayed_loading.dart';
|
||||||
import '../stores/accounts_store.dart';
|
import '../hooks/memo_future.dart';
|
||||||
|
import '../hooks/stores.dart';
|
||||||
import '../util/extensions/iterators.dart';
|
import '../util/extensions/iterators.dart';
|
||||||
import '../util/text_color.dart';
|
import '../util/text_color.dart';
|
||||||
|
|
||||||
|
@ -17,23 +17,18 @@ class CommunitiesTab extends HookWidget {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
var theme = Theme.of(context);
|
final theme = Theme.of(context);
|
||||||
var filterController = useTextEditingController();
|
final filterController = useTextEditingController();
|
||||||
useValueListenable(filterController);
|
useValueListenable(filterController);
|
||||||
var amountOfDisplayInstances = useMemoized(() {
|
final accountsStore = useAccountsStore();
|
||||||
var accountsStore = context.watch<AccountsStore>();
|
|
||||||
|
|
||||||
return accountsStore.users.keys
|
final amountOfDisplayInstances = useMemoized(() => accountsStore.users.keys
|
||||||
.where((e) => !accountsStore.isAnonymousFor(e))
|
.where((e) => !accountsStore.isAnonymousFor(e))
|
||||||
.length;
|
.length);
|
||||||
});
|
final isCollapsed = useState(List.filled(amountOfDisplayInstances, false));
|
||||||
var isCollapsed = useState(List.filled(amountOfDisplayInstances, false));
|
|
||||||
|
|
||||||
// TODO: use useMemoFuture
|
final instancesSnap = useMemoFuture(() {
|
||||||
var instancesFut = useMemoized(() {
|
final futures = accountsStore.users.keys
|
||||||
var accountsStore = context.watch<AccountsStore>();
|
|
||||||
|
|
||||||
var futures = accountsStore.users.keys
|
|
||||||
.where((e) => !accountsStore.isAnonymousFor(e))
|
.where((e) => !accountsStore.isAnonymousFor(e))
|
||||||
.map(
|
.map(
|
||||||
(instanceUrl) =>
|
(instanceUrl) =>
|
||||||
|
@ -43,10 +38,8 @@ class CommunitiesTab extends HookWidget {
|
||||||
|
|
||||||
return Future.wait(futures);
|
return Future.wait(futures);
|
||||||
});
|
});
|
||||||
var communitiesFut = useMemoized(() {
|
final communitiesSnap = useMemoFuture(() {
|
||||||
var accountsStore = context.watch<AccountsStore>();
|
final futures = accountsStore.users.keys
|
||||||
|
|
||||||
var futures = accountsStore.users.keys
|
|
||||||
.where((e) => !accountsStore.isAnonymousFor(e))
|
.where((e) => !accountsStore.isAnonymousFor(e))
|
||||||
.map(
|
.map(
|
||||||
(instanceUrl) => LemmyApi(instanceUrl)
|
(instanceUrl) => LemmyApi(instanceUrl)
|
||||||
|
@ -63,9 +56,6 @@ class CommunitiesTab extends HookWidget {
|
||||||
return Future.wait(futures);
|
return Future.wait(futures);
|
||||||
});
|
});
|
||||||
|
|
||||||
var communitiesSnap = useFuture(communitiesFut);
|
|
||||||
var instancesSnap = useFuture(instancesFut);
|
|
||||||
|
|
||||||
if (communitiesSnap.hasError || instancesSnap.hasError) {
|
if (communitiesSnap.hasError || instancesSnap.hasError) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(),
|
appBar: AppBar(),
|
||||||
|
@ -93,12 +83,12 @@ class CommunitiesTab extends HookWidget {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
var instances = instancesSnap.data;
|
final instances = instancesSnap.data;
|
||||||
var communities = communitiesSnap.data
|
final communities = communitiesSnap.data
|
||||||
..forEach(
|
..forEach(
|
||||||
(e) => e.sort((a, b) => a.communityName.compareTo(b.communityName)));
|
(e) => e.sort((a, b) => a.communityName.compareTo(b.communityName)));
|
||||||
|
|
||||||
var filterIcon = () {
|
final filterIcon = () {
|
||||||
if (filterController.text.isEmpty) {
|
if (filterController.text.isEmpty) {
|
||||||
return Icon(Icons.filter_list);
|
return Icon(Icons.filter_list);
|
||||||
}
|
}
|
||||||
|
@ -113,7 +103,7 @@ class CommunitiesTab extends HookWidget {
|
||||||
}();
|
}();
|
||||||
|
|
||||||
filterCommunities(List<CommunityFollowerView> comm) {
|
filterCommunities(List<CommunityFollowerView> comm) {
|
||||||
var matches = Fuzzy(
|
final matches = Fuzzy(
|
||||||
comm.map((e) => e.communityName).toList(),
|
comm.map((e) => e.communityName).toList(),
|
||||||
options: FuzzyOptions(threshold: 0.5),
|
options: FuzzyOptions(threshold: 0.5),
|
||||||
).search(filterController.text).map((e) => e.item);
|
).search(filterController.text).map((e) => e.item);
|
||||||
|
@ -146,7 +136,7 @@ class CommunitiesTab extends HookWidget {
|
||||||
),
|
),
|
||||||
body: ListView(
|
body: ListView(
|
||||||
children: [
|
children: [
|
||||||
for (var i in Iterable.generate(amountOfDisplayInstances))
|
for (final i in Iterable.generate(amountOfDisplayInstances))
|
||||||
Column(
|
Column(
|
||||||
children: [
|
children: [
|
||||||
ListTile(
|
ListTile(
|
||||||
|
@ -178,7 +168,7 @@ class CommunitiesTab extends HookWidget {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
if (!isCollapsed.value[i])
|
if (!isCollapsed.value[i])
|
||||||
for (var comm in filterCommunities(communities[i]))
|
for (final comm in filterCommunities(communities[i]))
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.only(left: 17),
|
padding: const EdgeInsets.only(left: 17),
|
||||||
child: ListTile(
|
child: ListTile(
|
||||||
|
@ -236,9 +226,10 @@ class _CommunitySubscribeToggle extends HookWidget {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
var theme = Theme.of(context);
|
final theme = Theme.of(context);
|
||||||
var subbed = useState(true);
|
final subbed = useState(true);
|
||||||
var delayed = useDelayedLoading(const Duration(milliseconds: 500));
|
final delayed = useDelayedLoading(const Duration(milliseconds: 500));
|
||||||
|
final accountsStore = useAccountsStore();
|
||||||
|
|
||||||
handleTap() async {
|
handleTap() async {
|
||||||
delayed.start();
|
delayed.start();
|
||||||
|
@ -247,10 +238,7 @@ class _CommunitySubscribeToggle extends HookWidget {
|
||||||
await LemmyApi(instanceUrl).v1.followCommunity(
|
await LemmyApi(instanceUrl).v1.followCommunity(
|
||||||
communityId: communityId,
|
communityId: communityId,
|
||||||
follow: !subbed.value,
|
follow: !subbed.value,
|
||||||
auth: context
|
auth: accountsStore.defaultTokenFor(instanceUrl).raw,
|
||||||
.read<AccountsStore>()
|
|
||||||
.defaultTokenFor(instanceUrl)
|
|
||||||
.raw,
|
|
||||||
);
|
);
|
||||||
subbed.value = !subbed.value;
|
subbed.value = !subbed.value;
|
||||||
} on Exception catch (err) {
|
} on Exception catch (err) {
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
import 'dart:async';
|
|
||||||
|
|
||||||
import 'package:cached_network_image/cached_network_image.dart';
|
import 'package:cached_network_image/cached_network_image.dart';
|
||||||
import 'package:esys_flutter_share/esys_flutter_share.dart';
|
import 'package:esys_flutter_share/esys_flutter_share.dart';
|
||||||
import 'package:flutter/gestures.dart';
|
import 'package:flutter/gestures.dart';
|
||||||
|
@ -7,11 +5,11 @@ import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||||
import 'package:intl/intl.dart';
|
import 'package:intl/intl.dart';
|
||||||
import 'package:lemmy_api_client/lemmy_api_client.dart';
|
import 'package:lemmy_api_client/lemmy_api_client.dart';
|
||||||
import 'package:provider/provider.dart';
|
|
||||||
import 'package:url_launcher/url_launcher.dart' as ul;
|
import 'package:url_launcher/url_launcher.dart' as ul;
|
||||||
|
|
||||||
|
import '../hooks/delayed_loading.dart';
|
||||||
import '../hooks/memo_future.dart';
|
import '../hooks/memo_future.dart';
|
||||||
import '../stores/accounts_store.dart';
|
import '../hooks/stores.dart';
|
||||||
import '../util/api_extensions.dart';
|
import '../util/api_extensions.dart';
|
||||||
import '../util/goto.dart';
|
import '../util/goto.dart';
|
||||||
import '../util/intl.dart';
|
import '../util/intl.dart';
|
||||||
|
@ -49,8 +47,10 @@ class CommunityPage extends HookWidget {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final theme = Theme.of(context);
|
final theme = Theme.of(context);
|
||||||
var fullCommunitySnap = useMemoFuture(() {
|
final accountsStore = useAccountsStore();
|
||||||
final token = context.watch<AccountsStore>().defaultTokenFor(instanceUrl);
|
|
||||||
|
final fullCommunitySnap = useMemoFuture(() {
|
||||||
|
final token = accountsStore.defaultTokenFor(instanceUrl);
|
||||||
|
|
||||||
if (communityId != null) {
|
if (communityId != null) {
|
||||||
return LemmyApi(instanceUrl).v1.getCommunity(
|
return LemmyApi(instanceUrl).v1.getCommunity(
|
||||||
|
@ -535,13 +535,11 @@ class _FollowButton extends HookWidget {
|
||||||
final theme = Theme.of(context);
|
final theme = Theme.of(context);
|
||||||
final isSubbed = useState(community.subscribed ?? false);
|
final isSubbed = useState(community.subscribed ?? false);
|
||||||
|
|
||||||
final colorOnTopOfAccent = textColorBasedOnBackground(theme.accentColor);
|
final token = useAccountsStore().defaultTokenFor(community.instanceUrl);
|
||||||
final token =
|
|
||||||
context.watch<AccountsStore>().defaultTokenFor(community.instanceUrl);
|
|
||||||
|
|
||||||
// TODO: use hook for handling spinner and pending
|
final delayed = useDelayedLoading(const Duration(milliseconds: 500));
|
||||||
final showSpinner = useState(false);
|
|
||||||
final isPending = useState(false);
|
final colorOnTopOfAccent = textColorBasedOnBackground(theme.accentColor);
|
||||||
|
|
||||||
subscribe() async {
|
subscribe() async {
|
||||||
if (token == null) {
|
if (token == null) {
|
||||||
|
@ -550,13 +548,10 @@ class _FollowButton extends HookWidget {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
isPending.value = true;
|
delayed.start();
|
||||||
var spinnerTimer =
|
|
||||||
Timer(Duration(milliseconds: 500), () => showSpinner.value = true);
|
|
||||||
|
|
||||||
final api = LemmyApi(community.instanceUrl).v1;
|
|
||||||
try {
|
try {
|
||||||
await api.followCommunity(
|
await LemmyApi(community.instanceUrl).v1.followCommunity(
|
||||||
communityId: community.id,
|
communityId: community.id,
|
||||||
follow: !isSubbed.value,
|
follow: !isSubbed.value,
|
||||||
auth: token?.raw);
|
auth: token?.raw);
|
||||||
|
@ -574,17 +569,14 @@ class _FollowButton extends HookWidget {
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
// clean up
|
delayed.cancel();
|
||||||
spinnerTimer.cancel();
|
|
||||||
isPending.value = false;
|
|
||||||
showSpinner.value = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return Center(
|
return Center(
|
||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
height: 27,
|
height: 27,
|
||||||
width: 160,
|
width: 160,
|
||||||
child: showSpinner.value
|
child: delayed.loading
|
||||||
? RaisedButton(
|
? RaisedButton(
|
||||||
onPressed: null,
|
onPressed: null,
|
||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
|
@ -598,7 +590,7 @@ class _FollowButton extends HookWidget {
|
||||||
)
|
)
|
||||||
: RaisedButton.icon(
|
: RaisedButton.icon(
|
||||||
padding: EdgeInsets.symmetric(vertical: 5, horizontal: 20),
|
padding: EdgeInsets.symmetric(vertical: 5, horizontal: 20),
|
||||||
onPressed: isPending.value ? () {} : subscribe,
|
onPressed: delayed.pending ? () {} : subscribe,
|
||||||
icon: isSubbed.value
|
icon: isSubbed.value
|
||||||
? Icon(Icons.remove, size: 18, color: colorOnTopOfAccent)
|
? Icon(Icons.remove, size: 18, color: colorOnTopOfAccent)
|
||||||
: Icon(Icons.add, size: 18, color: colorOnTopOfAccent),
|
: Icon(Icons.add, size: 18, color: colorOnTopOfAccent),
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import 'package:cached_network_image/cached_network_image.dart';
|
import 'package:cached_network_image/cached_network_image.dart';
|
||||||
import 'package:esys_flutter_share/esys_flutter_share.dart';
|
import 'package:esys_flutter_share/esys_flutter_share.dart';
|
||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||||
import 'package:intl/intl.dart';
|
import 'package:intl/intl.dart';
|
||||||
|
@ -272,10 +273,11 @@ class _AboutTab extends HookWidget {
|
||||||
}
|
}
|
||||||
|
|
||||||
void goToBannedUsers(BuildContext c) {
|
void goToBannedUsers(BuildContext c) {
|
||||||
Navigator.of(c).push(MaterialPageRoute(
|
goTo(
|
||||||
builder: (_) => UsersListPage(
|
c,
|
||||||
|
(_) => UsersListPage(
|
||||||
users: site.banned.reversed.toList(), title: 'Banned users'),
|
users: site.banned.reversed.toList(), title: 'Banned users'),
|
||||||
));
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -284,11 +286,12 @@ class _AboutTab extends HookWidget {
|
||||||
final commSnap = useFuture(communitiesFuture);
|
final commSnap = useFuture(communitiesFuture);
|
||||||
|
|
||||||
void goToCommunities() {
|
void goToCommunities() {
|
||||||
Navigator.of(context).push(MaterialPageRoute(
|
goTo(
|
||||||
builder: (_) => CommunitiesListPage(
|
context,
|
||||||
|
(_) => CommunitiesListPage(
|
||||||
communities: commSnap.data,
|
communities: commSnap.data,
|
||||||
title: 'Communities of ${site.site.name}'),
|
title: 'Communities of ${site.site.name}'),
|
||||||
));
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return SingleChildScrollView(
|
return SingleChildScrollView(
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||||
import 'package:provider/provider.dart';
|
|
||||||
|
|
||||||
import '../stores/accounts_store.dart';
|
import '../hooks/stores.dart';
|
||||||
import '../util/api_extensions.dart';
|
import '../util/api_extensions.dart';
|
||||||
|
import '../util/goto.dart';
|
||||||
import '../widgets/bottom_modal.dart';
|
import '../widgets/bottom_modal.dart';
|
||||||
import '../widgets/user_profile.dart';
|
import '../widgets/user_profile.dart';
|
||||||
import 'settings.dart';
|
import 'settings.dart';
|
||||||
|
@ -14,11 +15,12 @@ class UserProfileTab extends HookWidget {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
var theme = Theme.of(context);
|
final theme = Theme.of(context);
|
||||||
|
final accountsStore = useAccountsStore();
|
||||||
|
|
||||||
return Observer(
|
return Observer(
|
||||||
builder: (ctx) {
|
builder: (ctx) {
|
||||||
if (ctx.watch<AccountsStore>().hasNoAccount) {
|
if (accountsStore.hasNoAccount) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
body: Center(
|
body: Center(
|
||||||
child: Column(
|
child: Column(
|
||||||
|
@ -27,8 +29,7 @@ class UserProfileTab extends HookWidget {
|
||||||
Text('No account was added.'),
|
Text('No account was added.'),
|
||||||
FlatButton.icon(
|
FlatButton.icon(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
Navigator.of(context).push(MaterialPageRoute(
|
goTo(context, (_) => AccountsConfigPage());
|
||||||
builder: (_) => AccountsConfigPage()));
|
|
||||||
},
|
},
|
||||||
icon: Icon(Icons.add),
|
icon: Icon(Icons.add),
|
||||||
label: Text('Add account'),
|
label: Text('Add account'),
|
||||||
|
@ -39,7 +40,7 @@ class UserProfileTab extends HookWidget {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
var user = ctx.watch<AccountsStore>().defaultUser;
|
final user = accountsStore.defaultUser;
|
||||||
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
extendBodyBehindAppBar: true,
|
extendBodyBehindAppBar: true,
|
||||||
|
@ -68,12 +69,9 @@ class UserProfileTab extends HookWidget {
|
||||||
context: context,
|
context: context,
|
||||||
backgroundColor: Colors.transparent,
|
backgroundColor: Colors.transparent,
|
||||||
builder: (_) {
|
builder: (_) {
|
||||||
var userTags = <String>[];
|
final userTags = <String>[];
|
||||||
|
|
||||||
ctx
|
accountsStore.users.forEach((instanceUrl, value) {
|
||||||
.read<AccountsStore>()
|
|
||||||
.users
|
|
||||||
.forEach((instanceUrl, value) {
|
|
||||||
value.forEach((username, _) {
|
value.forEach((username, _) {
|
||||||
userTags.add('$username@$instanceUrl');
|
userTags.add('$username@$instanceUrl');
|
||||||
});
|
});
|
||||||
|
@ -81,8 +79,8 @@ class UserProfileTab extends HookWidget {
|
||||||
|
|
||||||
return Observer(
|
return Observer(
|
||||||
builder: (ctx) {
|
builder: (ctx) {
|
||||||
var user = ctx.watch<AccountsStore>().defaultUser;
|
final user = accountsStore.defaultUser;
|
||||||
var instanceUrl = user.instanceUrl;
|
final instanceUrl = user.instanceUrl;
|
||||||
|
|
||||||
return BottomModal(
|
return BottomModal(
|
||||||
title: 'account',
|
title: 'account',
|
||||||
|
@ -94,8 +92,8 @@ class UserProfileTab extends HookWidget {
|
||||||
title: Text(tag),
|
title: Text(tag),
|
||||||
groupValue: '${user.name}@$instanceUrl',
|
groupValue: '${user.name}@$instanceUrl',
|
||||||
onChanged: (selected) {
|
onChanged: (selected) {
|
||||||
var userTag = selected.split('@');
|
final userTag = selected.split('@');
|
||||||
ctx.read<AccountsStore>().setDefaultAccount(
|
accountsStore.setDefaultAccount(
|
||||||
userTag[1], userTag[0]);
|
userTag[1], userTag[0]);
|
||||||
Navigator.of(ctx).pop();
|
Navigator.of(ctx).pop();
|
||||||
},
|
},
|
||||||
|
@ -113,8 +111,7 @@ class UserProfileTab extends HookWidget {
|
||||||
IconButton(
|
IconButton(
|
||||||
icon: Icon(Icons.settings),
|
icon: Icon(Icons.settings),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
Navigator.of(context)
|
goTo(context, (_) => SettingsPage());
|
||||||
.push(MaterialPageRoute(builder: (_) => SettingsPage()));
|
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
|
|
|
@ -1,15 +1,15 @@
|
||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||||
import 'package:provider/provider.dart';
|
|
||||||
|
|
||||||
import '../stores/accounts_store.dart';
|
import '../hooks/stores.dart';
|
||||||
import '../stores/config_store.dart';
|
import '../util/goto.dart';
|
||||||
|
|
||||||
class SettingsPage extends StatelessWidget {
|
class SettingsPage extends StatelessWidget {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
var theme = Theme.of(context);
|
final theme = Theme.of(context);
|
||||||
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
|
@ -26,16 +26,14 @@ class SettingsPage extends StatelessWidget {
|
||||||
leading: Icon(Icons.person),
|
leading: Icon(Icons.person),
|
||||||
title: Text('Accounts'),
|
title: Text('Accounts'),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
Navigator.of(context).push(
|
goTo(context, (_) => AccountsConfigPage());
|
||||||
MaterialPageRoute(builder: (_) => AccountsConfigPage()));
|
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
ListTile(
|
ListTile(
|
||||||
leading: Icon(Icons.color_lens),
|
leading: Icon(Icons.color_lens),
|
||||||
title: Text('Appearance'),
|
title: Text('Appearance'),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
Navigator.of(context).push(
|
goTo(context, (_) => AppearanceConfigPage());
|
||||||
MaterialPageRoute(builder: (_) => AppearanceConfigPage()));
|
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
|
@ -45,10 +43,11 @@ class SettingsPage extends StatelessWidget {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class AppearanceConfigPage extends StatelessWidget {
|
class AppearanceConfigPage extends HookWidget {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
var theme = Theme.of(context);
|
final theme = Theme.of(context);
|
||||||
|
final configStore = useConfigStore();
|
||||||
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
|
@ -66,16 +65,16 @@ class AppearanceConfigPage extends StatelessWidget {
|
||||||
RadioListTile<ThemeMode>(
|
RadioListTile<ThemeMode>(
|
||||||
value: theme,
|
value: theme,
|
||||||
title: Text(theme.toString().split('.')[1]),
|
title: Text(theme.toString().split('.')[1]),
|
||||||
groupValue: ctx.watch<ConfigStore>().theme,
|
groupValue: configStore.theme,
|
||||||
onChanged: (selected) {
|
onChanged: (selected) {
|
||||||
ctx.read<ConfigStore>().theme = selected;
|
configStore.theme = selected;
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
SwitchListTile(
|
SwitchListTile(
|
||||||
title: Text('AMOLED dark mode'),
|
title: Text('AMOLED dark mode'),
|
||||||
value: ctx.watch<ConfigStore>().amoledDarkMode,
|
value: configStore.amoledDarkMode,
|
||||||
onChanged: (checked) {
|
onChanged: (checked) {
|
||||||
ctx.read<ConfigStore>().amoledDarkMode = checked;
|
configStore.amoledDarkMode = checked;
|
||||||
})
|
})
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
@ -89,7 +88,8 @@ class AccountsConfigPage extends HookWidget {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
var theme = Theme.of(context);
|
final theme = Theme.of(context);
|
||||||
|
final accountsStore = useAccountsStore();
|
||||||
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
key: _scaffoldKey,
|
key: _scaffoldKey,
|
||||||
|
@ -112,14 +112,13 @@ class AccountsConfigPage extends HookWidget {
|
||||||
),
|
),
|
||||||
body: Observer(
|
body: Observer(
|
||||||
builder: (ctx) {
|
builder: (ctx) {
|
||||||
var accountsStore = ctx.watch<AccountsStore>();
|
final theme = Theme.of(context);
|
||||||
var theme = Theme.of(context);
|
|
||||||
|
|
||||||
return ListView(
|
return ListView(
|
||||||
children: [
|
children: [
|
||||||
for (var entry in accountsStore.users.entries) ...[
|
for (final entry in accountsStore.users.entries) ...[
|
||||||
_SectionHeading(entry.key),
|
_SectionHeading(entry.key),
|
||||||
for (var username in entry.value.keys) ...[
|
for (final username in entry.value.keys) ...[
|
||||||
ListTile(
|
ListTile(
|
||||||
trailing:
|
trailing:
|
||||||
username == accountsStore.defaultUserFor(entry.key).name
|
username == accountsStore.defaultUserFor(entry.key).name
|
||||||
|
@ -166,17 +165,16 @@ class _AccountsConfigAddInstanceDialog extends HookWidget {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
var instanceController = useTextEditingController();
|
final instanceController = useTextEditingController();
|
||||||
useValueListenable(instanceController);
|
useValueListenable(instanceController);
|
||||||
|
final accountsStore = useAccountsStore();
|
||||||
|
|
||||||
var loading = useState(false);
|
final loading = useState(false);
|
||||||
|
|
||||||
handleOnAdd() async {
|
handleOnAdd() async {
|
||||||
try {
|
try {
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
await context
|
await accountsStore.addInstance(instanceController.text);
|
||||||
.read<AccountsStore>()
|
|
||||||
.addInstance(instanceController.text);
|
|
||||||
scaffoldKey.currentState.hideCurrentSnackBar();
|
scaffoldKey.currentState.hideCurrentSnackBar();
|
||||||
} on Exception catch (err) {
|
} on Exception catch (err) {
|
||||||
scaffoldKey.currentState.showSnackBar(SnackBar(
|
scaffoldKey.currentState.showSnackBar(SnackBar(
|
||||||
|
@ -222,21 +220,22 @@ class _AccountsConfigAddAccountDialog extends HookWidget {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
var usernameController = useTextEditingController();
|
final usernameController = useTextEditingController();
|
||||||
var passwordController = useTextEditingController();
|
final passwordController = useTextEditingController();
|
||||||
useValueListenable(usernameController);
|
useValueListenable(usernameController);
|
||||||
useValueListenable(passwordController);
|
useValueListenable(passwordController);
|
||||||
|
final accountsStore = useAccountsStore();
|
||||||
|
|
||||||
var loading = useState(false);
|
final loading = useState(false);
|
||||||
|
|
||||||
handleOnAdd() async {
|
handleOnAdd() async {
|
||||||
try {
|
try {
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
await context.read<AccountsStore>().addAccount(
|
await accountsStore.addAccount(
|
||||||
instanceUrl,
|
instanceUrl,
|
||||||
usernameController.text,
|
usernameController.text,
|
||||||
passwordController.text,
|
passwordController.text,
|
||||||
);
|
);
|
||||||
} on Exception catch (err) {
|
} on Exception catch (err) {
|
||||||
scaffoldKey.currentState.showSnackBar(SnackBar(
|
scaffoldKey.currentState.showSnackBar(SnackBar(
|
||||||
content: Text(err.toString()),
|
content: Text(err.toString()),
|
||||||
|
|
|
@ -30,9 +30,9 @@ class UserPage extends HookWidget {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
var userViewSnap = useFuture(_userView);
|
final userViewSnap = useFuture(_userView);
|
||||||
|
|
||||||
var body = () {
|
final body = () {
|
||||||
if (userViewSnap.hasData) {
|
if (userViewSnap.hasData) {
|
||||||
return UserProfile.fromUserView(userViewSnap.data);
|
return UserProfile.fromUserView(userViewSnap.data);
|
||||||
} else if (userViewSnap.hasError) {
|
} else if (userViewSnap.hasError) {
|
||||||
|
|
|
@ -14,7 +14,6 @@ abstract class _AccountsStore with Store {
|
||||||
_AccountsStore() {
|
_AccountsStore() {
|
||||||
// persistently save settings each time they are changed
|
// persistently save settings each time they are changed
|
||||||
_saveReactionDisposer = reaction(
|
_saveReactionDisposer = reaction(
|
||||||
// TODO: does not react to deep changes in users and tokens
|
|
||||||
(_) => [
|
(_) => [
|
||||||
users.forEach((k, submap) =>
|
users.forEach((k, submap) =>
|
||||||
MapEntry(k, submap.forEach((k2, v2) => MapEntry(k2, v2)))),
|
MapEntry(k, submap.forEach((k2, v2) => MapEntry(k2, v2)))),
|
||||||
|
@ -32,7 +31,7 @@ abstract class _AccountsStore with Store {
|
||||||
}
|
}
|
||||||
|
|
||||||
void load() async {
|
void load() async {
|
||||||
var prefs = await SharedPreferences.getInstance();
|
final prefs = await SharedPreferences.getInstance();
|
||||||
|
|
||||||
nestedMapsCast<T>(String key, T f(Map<String, dynamic> json)) =>
|
nestedMapsCast<T>(String key, T f(Map<String, dynamic> json)) =>
|
||||||
ObservableMap.of(
|
ObservableMap.of(
|
||||||
|
@ -59,7 +58,7 @@ abstract class _AccountsStore with Store {
|
||||||
}
|
}
|
||||||
|
|
||||||
void save() async {
|
void save() async {
|
||||||
var prefs = await SharedPreferences.getInstance();
|
final prefs = await SharedPreferences.getInstance();
|
||||||
|
|
||||||
await prefs.setString('defaultAccount', _defaultAccount);
|
await prefs.setString('defaultAccount', _defaultAccount);
|
||||||
await prefs.setString('defaultAccounts', jsonEncode(_defaultAccounts));
|
await prefs.setString('defaultAccounts', jsonEncode(_defaultAccounts));
|
||||||
|
@ -93,7 +92,7 @@ abstract class _AccountsStore with Store {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
var userTag = _defaultAccount.split('@');
|
final userTag = _defaultAccount.split('@');
|
||||||
return users[userTag[1]][userTag[0]];
|
return users[userTag[1]][userTag[0]];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -103,7 +102,7 @@ abstract class _AccountsStore with Store {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
var userTag = _defaultAccount.split('@');
|
final userTag = _defaultAccount.split('@');
|
||||||
return tokens[userTag[1]][userTag[0]];
|
return tokens[userTag[1]][userTag[0]];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -159,13 +158,13 @@ abstract class _AccountsStore with Store {
|
||||||
throw Exception('No such instance was added');
|
throw Exception('No such instance was added');
|
||||||
}
|
}
|
||||||
|
|
||||||
var lemmy = LemmyApi(instanceUrl).v1;
|
final lemmy = LemmyApi(instanceUrl).v1;
|
||||||
|
|
||||||
var token = await lemmy.login(
|
final token = await lemmy.login(
|
||||||
usernameOrEmail: usernameOrEmail,
|
usernameOrEmail: usernameOrEmail,
|
||||||
password: password,
|
password: password,
|
||||||
);
|
);
|
||||||
var userData =
|
final userData =
|
||||||
await lemmy.getSite(auth: token.raw).then((value) => value.myUser);
|
await lemmy.getSite(auth: token.raw).then((value) => value.myUser);
|
||||||
|
|
||||||
// first account for this instance
|
// first account for this instance
|
||||||
|
|
|
@ -22,14 +22,14 @@ abstract class _ConfigStore with Store {
|
||||||
}
|
}
|
||||||
|
|
||||||
void load() async {
|
void load() async {
|
||||||
var prefs = await SharedPreferences.getInstance();
|
final prefs = await SharedPreferences.getInstance();
|
||||||
// load saved settings or create defaults
|
// load saved settings or create defaults
|
||||||
theme = _themeModeFromString(prefs.getString('theme') ?? 'system');
|
theme = _themeModeFromString(prefs.getString('theme') ?? 'system');
|
||||||
amoledDarkMode = prefs.getBool('amoledDarkMode') ?? false;
|
amoledDarkMode = prefs.getBool('amoledDarkMode') ?? false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void save() async {
|
void save() async {
|
||||||
var prefs = await SharedPreferences.getInstance();
|
final prefs = await SharedPreferences.getInstance();
|
||||||
|
|
||||||
await prefs.setString('theme', describeEnum(theme));
|
await prefs.setString('theme', describeEnum(theme));
|
||||||
await prefs.setBool('amoledDarkMode', amoledDarkMode);
|
await prefs.setBool('amoledDarkMode', amoledDarkMode);
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
import 'package:url_launcher/url_launcher.dart' as ul;
|
import 'package:url_launcher/url_launcher.dart' as ul;
|
||||||
|
@ -7,6 +8,7 @@ import 'pages/full_post.dart';
|
||||||
import 'pages/instance.dart';
|
import 'pages/instance.dart';
|
||||||
import 'pages/user.dart';
|
import 'pages/user.dart';
|
||||||
import 'stores/accounts_store.dart';
|
import 'stores/accounts_store.dart';
|
||||||
|
import 'util/goto.dart';
|
||||||
|
|
||||||
Future<void> linkLauncher({
|
Future<void> linkLauncher({
|
||||||
@required BuildContext context,
|
@required BuildContext context,
|
||||||
|
@ -14,7 +16,7 @@ Future<void> linkLauncher({
|
||||||
@required String instanceUrl,
|
@required String instanceUrl,
|
||||||
}) async {
|
}) async {
|
||||||
push(Widget Function() builder) {
|
push(Widget Function() builder) {
|
||||||
Navigator.of(context).push(MaterialPageRoute(builder: (c) => builder()));
|
goTo(context, (c) => builder());
|
||||||
}
|
}
|
||||||
|
|
||||||
final instances = context.read<AccountsStore>().users.keys.toList();
|
final instances = context.read<AccountsStore>().users.keys.toList();
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
import '../pages/community.dart';
|
import '../pages/community.dart';
|
||||||
|
@ -5,41 +6,46 @@ import '../pages/full_post.dart';
|
||||||
import '../pages/instance.dart';
|
import '../pages/instance.dart';
|
||||||
import '../pages/user.dart';
|
import '../pages/user.dart';
|
||||||
|
|
||||||
void goToInstance(BuildContext context, String instanceUrl) =>
|
Future<dynamic> goTo(
|
||||||
Navigator.of(context).push(MaterialPageRoute(
|
BuildContext context,
|
||||||
builder: (context) => InstancePage(instanceUrl: instanceUrl),
|
Widget Function(BuildContext context) builder,
|
||||||
|
) =>
|
||||||
|
Navigator.of(context).push(CupertinoPageRoute(
|
||||||
|
builder: builder,
|
||||||
));
|
));
|
||||||
|
|
||||||
|
void goToInstance(BuildContext context, String instanceUrl) =>
|
||||||
|
goTo(context, (context) => InstancePage(instanceUrl: instanceUrl));
|
||||||
|
|
||||||
// ignore: camel_case_types
|
// ignore: camel_case_types
|
||||||
abstract class goToCommunity {
|
abstract class goToCommunity {
|
||||||
/// Navigates to `CommunityPage`
|
/// Navigates to `CommunityPage`
|
||||||
static void byId(BuildContext context, String instanceUrl, int communityId) =>
|
static void byId(BuildContext context, String instanceUrl, int communityId) =>
|
||||||
Navigator.of(context).push(MaterialPageRoute(
|
goTo(
|
||||||
builder: (context) => CommunityPage.fromId(
|
context,
|
||||||
|
(context) => CommunityPage.fromId(
|
||||||
instanceUrl: instanceUrl, communityId: communityId),
|
instanceUrl: instanceUrl, communityId: communityId),
|
||||||
));
|
);
|
||||||
|
|
||||||
static void byName(
|
static void byName(
|
||||||
BuildContext context, String instanceUrl, String communityName) =>
|
BuildContext context, String instanceUrl, String communityName) =>
|
||||||
Navigator.of(context).push(MaterialPageRoute(
|
goTo(
|
||||||
builder: (context) => CommunityPage.fromName(
|
context,
|
||||||
|
(context) => CommunityPage.fromName(
|
||||||
instanceUrl: instanceUrl, communityName: communityName),
|
instanceUrl: instanceUrl, communityName: communityName),
|
||||||
));
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ignore: camel_case_types
|
// ignore: camel_case_types
|
||||||
abstract class goToUser {
|
abstract class goToUser {
|
||||||
static void byId(BuildContext context, String instanceUrl, int userId) =>
|
static void byId(BuildContext context, String instanceUrl, int userId) =>
|
||||||
Navigator.of(context).push(MaterialPageRoute(
|
goTo(context,
|
||||||
builder: (context) =>
|
(context) => UserPage(instanceUrl: instanceUrl, userId: userId));
|
||||||
UserPage(instanceUrl: instanceUrl, userId: userId)));
|
|
||||||
|
|
||||||
static void byName(
|
static void byName(
|
||||||
BuildContext context, String instanceUrl, String userName) =>
|
BuildContext context, String instanceUrl, String userName) =>
|
||||||
throw UnimplementedError('need to create UserProfile constructor first');
|
throw UnimplementedError('need to create UserProfile constructor first');
|
||||||
}
|
}
|
||||||
|
|
||||||
void goToPost(BuildContext context, String instanceUrl, int postId) =>
|
void goToPost(BuildContext context, String instanceUrl, int postId) => goTo(
|
||||||
Navigator.of(context).push(MaterialPageRoute(
|
context, (context) => FullPostPage(instanceUrl: instanceUrl, id: postId));
|
||||||
builder: (context) =>
|
|
||||||
FullPostPage(instanceUrl: instanceUrl, id: postId)));
|
|
||||||
|
|
|
@ -11,7 +11,7 @@ class Badge extends StatelessWidget {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
var theme = Theme.of(context);
|
final theme = Theme.of(context);
|
||||||
|
|
||||||
return Container(
|
return Container(
|
||||||
height: 25,
|
height: 25,
|
||||||
|
|
|
@ -8,7 +8,7 @@ class BottomModal extends StatelessWidget {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
var theme = Theme.of(context);
|
final theme = Theme.of(context);
|
||||||
|
|
||||||
return SafeArea(
|
return SafeArea(
|
||||||
child: Padding(
|
child: Padding(
|
||||||
|
|
|
@ -314,7 +314,7 @@ class Comment extends HookWidget {
|
||||||
: BorderSide.none,
|
: BorderSide.none,
|
||||||
top: BorderSide(width: 0.2))),
|
top: BorderSide(width: 0.2))),
|
||||||
),
|
),
|
||||||
for (var c in commentTree.children)
|
for (final c in commentTree.children)
|
||||||
Comment(
|
Comment(
|
||||||
c,
|
c,
|
||||||
indent: indent + 1,
|
indent: indent + 1,
|
||||||
|
|
|
@ -34,9 +34,9 @@ class CommentSection extends HookWidget {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
var sorting = useState(sortType);
|
final sorting = useState(sortType);
|
||||||
var rawComms = useState(rawComments);
|
final rawComms = useState(rawComments);
|
||||||
var comms = useState(comments);
|
final comms = useState(comments);
|
||||||
|
|
||||||
void sortComments(CommentSortType sort) {
|
void sortComments(CommentSortType sort) {
|
||||||
if (sort != sorting.value && sort != CommentSortType.chat) {
|
if (sort != sorting.value && sort != CommentSortType.chat) {
|
||||||
|
@ -106,7 +106,8 @@ class CommentSection extends HookWidget {
|
||||||
postCreatorId: postCreatorId,
|
postCreatorId: postCreatorId,
|
||||||
)
|
)
|
||||||
else
|
else
|
||||||
for (var com in comms.value) Comment(com, postCreatorId: postCreatorId),
|
for (final com in comms.value)
|
||||||
|
Comment(com, postCreatorId: postCreatorId),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
import '../pages/media_view.dart';
|
import '../pages/media_view.dart';
|
||||||
|
import '../util/goto.dart';
|
||||||
|
|
||||||
class FullscreenableImage extends StatelessWidget {
|
class FullscreenableImage extends StatelessWidget {
|
||||||
final String url;
|
final String url;
|
||||||
|
@ -13,9 +15,7 @@ class FullscreenableImage extends StatelessWidget {
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
|
|
||||||
_onTap(BuildContext c) {
|
_onTap(BuildContext c) {
|
||||||
Navigator.of(c).push(MaterialPageRoute(
|
goTo(c, (context) => MediaViewPage(url));
|
||||||
builder: (context) => MediaViewPage(url),
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import 'package:cached_network_image/cached_network_image.dart';
|
import 'package:cached_network_image/cached_network_image.dart';
|
||||||
import 'package:esys_flutter_share/esys_flutter_share.dart';
|
import 'package:esys_flutter_share/esys_flutter_share.dart';
|
||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
import 'package:flutter/gestures.dart';
|
import 'package:flutter/gestures.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:intl/intl.dart';
|
import 'package:intl/intl.dart';
|
||||||
|
@ -150,7 +151,7 @@ class Post extends StatelessWidget {
|
||||||
final urlDomain = () {
|
final urlDomain = () {
|
||||||
if (post.url == null) return null;
|
if (post.url == null) return null;
|
||||||
|
|
||||||
var url = post.url.split('/')[2];
|
final url = post.url.split('/')[2];
|
||||||
if (url.startsWith('www.')) return url.substring(4);
|
if (url.startsWith('www.')) return url.substring(4);
|
||||||
return url;
|
return url;
|
||||||
}();
|
}();
|
||||||
|
@ -425,9 +426,10 @@ class Post extends StatelessWidget {
|
||||||
child: InkWell(
|
child: InkWell(
|
||||||
onTap: fullPost
|
onTap: fullPost
|
||||||
? null
|
? null
|
||||||
: () => Navigator.of(context).push(MaterialPageRoute(
|
: () => goTo(
|
||||||
builder: (context) => FullPostPage.fromPostView(
|
context,
|
||||||
post))), //, instanceUrl, post.id),
|
(context) =>
|
||||||
|
FullPostPage.fromPostView(post)), //, instanceUrl, post.id),
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
info(),
|
info(),
|
||||||
|
|
|
@ -16,7 +16,7 @@ class PostListOptions extends HookWidget {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
var sort = useState(defaultSort);
|
final sort = useState(defaultSort);
|
||||||
|
|
||||||
void selectSortType(BuildContext context) {
|
void selectSortType(BuildContext context) {
|
||||||
showModalBottomSheet(
|
showModalBottomSheet(
|
||||||
|
@ -27,7 +27,7 @@ class PostListOptions extends HookWidget {
|
||||||
title: 'sort by',
|
title: 'sort by',
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
for (var x in SortType.values)
|
for (final x in SortType.values)
|
||||||
RadioListTile<SortType>(
|
RadioListTile<SortType>(
|
||||||
value: x,
|
value: x,
|
||||||
groupValue: sort.value,
|
groupValue: sort.value,
|
||||||
|
|
|
@ -29,13 +29,13 @@ class UserProfile extends HookWidget {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
var theme = Theme.of(context);
|
final theme = Theme.of(context);
|
||||||
final colorOnTopOfAccentColor =
|
final colorOnTopOfAccentColor =
|
||||||
textColorBasedOnBackground(theme.accentColor);
|
textColorBasedOnBackground(theme.accentColor);
|
||||||
|
|
||||||
var userViewSnap = useFuture(_userView, preserveState: false);
|
final userViewSnap = useFuture(_userView, preserveState: false);
|
||||||
|
|
||||||
Widget bio = () {
|
final bio = () {
|
||||||
if (userViewSnap.hasData) {
|
if (userViewSnap.hasData) {
|
||||||
if (userViewSnap.data.bio != null) {
|
if (userViewSnap.data.bio != null) {
|
||||||
return Padding(
|
return Padding(
|
||||||
|
|
Loading…
Reference in New Issue