mirror of
https://github.com/git-touch/git-touch
synced 2025-02-02 08:56:54 +01:00
refactor: list scaffold
This commit is contained in:
parent
ac02fd705a
commit
917a8018f3
@ -1,5 +1,4 @@
|
||||
import 'package:json_annotation/json_annotation.dart';
|
||||
import 'package:meta/meta.dart';
|
||||
|
||||
part 'account.g.dart';
|
||||
|
||||
|
@ -415,7 +415,6 @@ class ThemeModel with ChangeNotifier {
|
||||
}
|
||||
|
||||
showActions(BuildContext context, List<ActionItem> actionItems) async {
|
||||
if (actionItems == null) return;
|
||||
final value = await showCupertinoModalPopup<int>(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
|
@ -5,14 +5,14 @@ import 'package:git_touch/models/theme.dart';
|
||||
import 'package:git_touch/scaffolds/common.dart';
|
||||
import 'package:git_touch/utils/utils.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import '../widgets/error_reload.dart';
|
||||
import '../widgets/loading.dart';
|
||||
import '../widgets/empty.dart';
|
||||
import 'package:git_touch/widgets/error_reload.dart';
|
||||
import 'package:git_touch/widgets/loading.dart';
|
||||
import 'package:git_touch/widgets/empty.dart';
|
||||
|
||||
class ListPayload<T, K> {
|
||||
K cursor;
|
||||
Iterable<T>? items;
|
||||
bool? hasMore;
|
||||
Iterable<T> items;
|
||||
bool hasMore;
|
||||
|
||||
ListPayload({
|
||||
required this.items,
|
||||
@ -56,7 +56,15 @@ class _ListStatefulScaffoldState<T, K>
|
||||
void initState() {
|
||||
super.initState();
|
||||
_refresh();
|
||||
_controller.addListener(onScroll);
|
||||
_controller.addListener(() {
|
||||
if (_controller.position.maxScrollExtent - _controller.offset < 100 &&
|
||||
!_controller.position.outOfRange &&
|
||||
!loading &&
|
||||
!loadingMore &&
|
||||
hasMore != false) {
|
||||
_loadMore();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
@ -65,40 +73,17 @@ class _ListStatefulScaffoldState<T, K>
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
void onScroll() {
|
||||
// Fimber.d(_controller.position.maxScrollExtent - _controller.offset);
|
||||
if (_controller.position.maxScrollExtent - _controller.offset < 100 &&
|
||||
!_controller.position.outOfRange &&
|
||||
!loading &&
|
||||
!loadingMore &&
|
||||
hasMore!) {
|
||||
_loadMore();
|
||||
}
|
||||
}
|
||||
|
||||
// if items not enough, fetch next page
|
||||
// This should be triggered after build
|
||||
// TODO: disabled
|
||||
void _makeSureItemsFill() {
|
||||
// Future.delayed(Duration(milliseconds: 300)).then((_) {
|
||||
// onScroll();
|
||||
// });
|
||||
}
|
||||
|
||||
Future<void> _refresh({bool force = false}) async {
|
||||
Future<void> _refresh() async {
|
||||
// Fimber.d('list scaffold refresh');
|
||||
setState(() {
|
||||
error = '';
|
||||
loading = true;
|
||||
if (force) {
|
||||
items = [];
|
||||
}
|
||||
});
|
||||
try {
|
||||
final ListPayload<T, K?> _payload = await widget.fetch(null);
|
||||
items = _payload.items!.toList();
|
||||
cursor = _payload.cursor;
|
||||
hasMore = _payload.hasMore;
|
||||
final ListPayload<T, K> p = await widget.fetch(null);
|
||||
items = p.items.toList();
|
||||
cursor = p.cursor;
|
||||
hasMore = p.hasMore;
|
||||
} catch (err) {
|
||||
error = err.toString();
|
||||
throw err;
|
||||
@ -107,7 +92,6 @@ class _ListStatefulScaffoldState<T, K>
|
||||
setState(() {
|
||||
loading = false;
|
||||
});
|
||||
_makeSureItemsFill();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -118,10 +102,10 @@ class _ListStatefulScaffoldState<T, K>
|
||||
loadingMore = true;
|
||||
});
|
||||
try {
|
||||
ListPayload<T, K?> _payload = await widget.fetch(cursor);
|
||||
items.addAll(_payload.items!);
|
||||
cursor = _payload.cursor;
|
||||
hasMore = _payload.hasMore;
|
||||
ListPayload<T, K> p = await widget.fetch(cursor);
|
||||
items.addAll(p.items);
|
||||
cursor = p.cursor;
|
||||
hasMore = p.hasMore;
|
||||
} catch (err) {
|
||||
error = err.toString();
|
||||
throw err;
|
||||
@ -130,25 +114,22 @@ class _ListStatefulScaffoldState<T, K>
|
||||
setState(() {
|
||||
loadingMore = false;
|
||||
});
|
||||
_makeSureItemsFill();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Widget _buildItem(BuildContext context, int index) {
|
||||
if (index == 2 * items.length) {
|
||||
if (hasMore!) {
|
||||
if (hasMore != false) {
|
||||
return Loading(more: true);
|
||||
} else {
|
||||
return Container();
|
||||
}
|
||||
}
|
||||
|
||||
if (index % 2 == 1) {
|
||||
} else if (index % 2 == 1) {
|
||||
return CommonStyle.border;
|
||||
} else {
|
||||
return widget.itemBuilder(items[index ~/ 2]);
|
||||
}
|
||||
|
||||
return widget.itemBuilder(items[index ~/ 2]);
|
||||
}
|
||||
|
||||
Widget _buildCupertinoSliver() {
|
||||
|
@ -82,34 +82,33 @@ class BbRepoScreen extends StatelessWidget {
|
||||
url:
|
||||
'/bitbucket/$owner/$name/commits/${branch ?? p.mainbranch!.name}',
|
||||
),
|
||||
if (branches != null)
|
||||
TableViewItem(
|
||||
leftIconData: Octicons.git_branch,
|
||||
text: Text(AppLocalizations.of(context)!.branches),
|
||||
rightWidget: Text((branch ?? p.mainbranch!.name)! +
|
||||
' • ' +
|
||||
branches.length.toString()),
|
||||
onTap: () async {
|
||||
if (branches.length < 2) return;
|
||||
TableViewItem(
|
||||
leftIconData: Octicons.git_branch,
|
||||
text: Text(AppLocalizations.of(context)!.branches),
|
||||
rightWidget: Text((branch ?? p.mainbranch!.name)! +
|
||||
' • ' +
|
||||
branches.length.toString()),
|
||||
onTap: () async {
|
||||
if (branches.length < 2) return;
|
||||
|
||||
await theme.showPicker(
|
||||
context,
|
||||
PickerGroupItem(
|
||||
value: branch,
|
||||
items: branches
|
||||
.map((b) => PickerItem(b.name, text: b.name))
|
||||
.toList(),
|
||||
onClose: (ref) {
|
||||
if (ref != branch) {
|
||||
theme.push(context,
|
||||
'/bitbucket/$owner/$name?branch=$ref',
|
||||
replace: true);
|
||||
}
|
||||
},
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
await theme.showPicker(
|
||||
context,
|
||||
PickerGroupItem(
|
||||
value: branch,
|
||||
items: branches
|
||||
.map((b) => PickerItem(b.name, text: b.name))
|
||||
.toList(),
|
||||
onClose: (ref) {
|
||||
if (ref != branch) {
|
||||
theme.push(
|
||||
context, '/bitbucket/$owner/$name?branch=$ref',
|
||||
replace: true);
|
||||
}
|
||||
},
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
CommonStyle.verticalGap,
|
||||
|
@ -159,34 +159,33 @@ class GeRepoScreen extends StatelessWidget {
|
||||
url:
|
||||
'/gitee/$owner/$name/commits?branch=${branch ?? p.defaultBranch}',
|
||||
),
|
||||
if (branches != null)
|
||||
TableViewItem(
|
||||
leftIconData: Octicons.git_branch,
|
||||
text: Text(AppLocalizations.of(context)!.branches),
|
||||
rightWidget: Text((branch ?? p.defaultBranch)! +
|
||||
' • ' +
|
||||
branches.length.toString()),
|
||||
onTap: () async {
|
||||
if (branches.length < 2) return;
|
||||
TableViewItem(
|
||||
leftIconData: Octicons.git_branch,
|
||||
text: Text(AppLocalizations.of(context)!.branches),
|
||||
rightWidget: Text((branch ?? p.defaultBranch)! +
|
||||
' • ' +
|
||||
branches.length.toString()),
|
||||
onTap: () async {
|
||||
if (branches.length < 2) return;
|
||||
|
||||
await theme.showPicker(
|
||||
context,
|
||||
PickerGroupItem(
|
||||
value: branch,
|
||||
items: branches
|
||||
.map((b) => PickerItem(b.name, text: b.name))
|
||||
.toList(),
|
||||
onClose: (ref) {
|
||||
if (ref != branch) {
|
||||
theme.push(
|
||||
context, '/gitee/$owner/$name?branch=$ref',
|
||||
replace: true);
|
||||
}
|
||||
},
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
await theme.showPicker(
|
||||
context,
|
||||
PickerGroupItem(
|
||||
value: branch,
|
||||
items: branches
|
||||
.map((b) => PickerItem(b.name, text: b.name))
|
||||
.toList(),
|
||||
onClose: (ref) {
|
||||
if (ref != branch) {
|
||||
theme.push(
|
||||
context, '/gitee/$owner/$name?branch=$ref',
|
||||
replace: true);
|
||||
}
|
||||
},
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
TableViewItem(
|
||||
leftIconData: Octicons.organization,
|
||||
text: Text('Contributors'),
|
||||
|
@ -50,7 +50,7 @@ class GhCommits extends StatelessWidget {
|
||||
return ListPayload(
|
||||
cursor: history.pageInfo.endCursor,
|
||||
hasMore: history.pageInfo.hasNextPage,
|
||||
items: history.nodes,
|
||||
items: history.nodes ?? [],
|
||||
);
|
||||
},
|
||||
itemBuilder: (p) {
|
||||
|
@ -28,7 +28,7 @@ class GhGistsScreen extends StatelessWidget {
|
||||
final gists = res.data!.user!.gists;
|
||||
return ListPayload(
|
||||
cursor: gists.pageInfo.endCursor,
|
||||
items: gists.nodes,
|
||||
items: gists.nodes ?? [],
|
||||
hasMore: gists.pageInfo.hasNextPage,
|
||||
);
|
||||
},
|
||||
|
@ -30,7 +30,7 @@ class GhReleasesScreen extends StatelessWidget {
|
||||
final releases = res.data!.repository!.releases;
|
||||
return ListPayload(
|
||||
cursor: releases.pageInfo.endCursor,
|
||||
items: releases.nodes,
|
||||
items: releases.nodes ?? [],
|
||||
hasMore: releases.pageInfo.hasNextPage,
|
||||
);
|
||||
},
|
||||
|
@ -75,7 +75,7 @@ class GhRepoScreen extends StatelessWidget {
|
||||
return res.body;
|
||||
}).catchError((err) {
|
||||
// 404
|
||||
return null;
|
||||
return '';
|
||||
});
|
||||
};
|
||||
};
|
||||
|
@ -30,7 +30,7 @@ class GhRepos extends StatelessWidget {
|
||||
return ListPayload(
|
||||
cursor: p.pageInfo.endCursor,
|
||||
hasMore: p.pageInfo.hasNextPage,
|
||||
items: p.nodes,
|
||||
items: p.nodes!,
|
||||
);
|
||||
},
|
||||
itemBuilder: (p) {
|
||||
@ -61,7 +61,7 @@ class GhStars extends StatelessWidget {
|
||||
return ListPayload(
|
||||
cursor: p.pageInfo.endCursor,
|
||||
hasMore: p.pageInfo.hasNextPage,
|
||||
items: p.nodes,
|
||||
items: p.nodes!,
|
||||
);
|
||||
},
|
||||
itemBuilder: (p) {
|
||||
|
@ -29,7 +29,7 @@ class GhFollowers extends StatelessWidget {
|
||||
return ListPayload(
|
||||
cursor: p.pageInfo.endCursor,
|
||||
hasMore: p.pageInfo.hasNextPage,
|
||||
items: p.nodes,
|
||||
items: p.nodes!,
|
||||
);
|
||||
},
|
||||
itemBuilder: (p) {
|
||||
@ -59,7 +59,7 @@ class GhFollowing extends StatelessWidget {
|
||||
return ListPayload(
|
||||
cursor: p.pageInfo.endCursor,
|
||||
hasMore: p.pageInfo.hasNextPage,
|
||||
items: p.nodes,
|
||||
items: p.nodes!,
|
||||
);
|
||||
},
|
||||
itemBuilder: (p) {
|
||||
@ -89,7 +89,7 @@ class GhMembers extends StatelessWidget {
|
||||
return ListPayload(
|
||||
cursor: p.pageInfo.endCursor,
|
||||
hasMore: p.pageInfo.hasNextPage,
|
||||
items: p.nodes,
|
||||
items: p.nodes!,
|
||||
);
|
||||
},
|
||||
itemBuilder: (p) {
|
||||
@ -121,7 +121,7 @@ class GhWachers extends StatelessWidget {
|
||||
return ListPayload(
|
||||
cursor: p.pageInfo.endCursor,
|
||||
hasMore: p.pageInfo.hasNextPage,
|
||||
items: p.nodes,
|
||||
items: p.nodes!,
|
||||
);
|
||||
},
|
||||
itemBuilder: (p) {
|
||||
@ -153,7 +153,7 @@ class GhStargazers extends StatelessWidget {
|
||||
return ListPayload(
|
||||
cursor: p.pageInfo.endCursor,
|
||||
hasMore: p.pageInfo.hasNextPage,
|
||||
items: p.nodes,
|
||||
items: p.nodes!,
|
||||
);
|
||||
},
|
||||
itemBuilder: (p) {
|
||||
|
@ -114,12 +114,10 @@ class GoRepoScreen extends StatelessWidget {
|
||||
TableViewItem(
|
||||
leftIconData: Octicons.git_branch,
|
||||
text: Text(AppLocalizations.of(context)!.branches),
|
||||
rightWidget: Text((branch ?? 'master')! +
|
||||
rightWidget: Text((branch ?? 'master') +
|
||||
' • ' +
|
||||
'${branches == null ? '1' : branches.length.toString()}'),
|
||||
'${branches.length.toString()}'),
|
||||
onTap: () async {
|
||||
if (branches == null) return;
|
||||
|
||||
await theme.showPicker(
|
||||
context,
|
||||
PickerGroupItem(
|
||||
|
@ -119,7 +119,7 @@ List<T> join<T>(T seperator, List<T> xs) {
|
||||
List<T> joinAll<T>(T seperator, List<List<T>> xss) {
|
||||
List<T> result = [];
|
||||
xss.asMap().forEach((index, x) {
|
||||
if (x == null || x.isEmpty) return;
|
||||
if (x.isEmpty) return;
|
||||
|
||||
result.addAll(x);
|
||||
if (index < xss.length - 1) {
|
||||
@ -136,11 +136,6 @@ bool isNotNullOrEmpty(String? text) {
|
||||
return text != null && text.isNotEmpty;
|
||||
}
|
||||
|
||||
String getBranchQueryKey(String branch, {bool withParams = false}) {
|
||||
if (branch == null) return 'defaultBranchRef';
|
||||
return 'ref' + (withParams ? '(qualifiedName: "$branch")' : '');
|
||||
}
|
||||
|
||||
// TODO: Primer
|
||||
class PrimerBranchName extends StatelessWidget {
|
||||
final String? name;
|
||||
|
@ -101,9 +101,7 @@ class ReleaseItem extends StatelessWidget {
|
||||
),
|
||||
rightWidget: IconButton(
|
||||
onPressed: () {
|
||||
if (asset.downloadUrl != null) {
|
||||
theme.push(context, asset.downloadUrl);
|
||||
}
|
||||
theme.push(context, asset.downloadUrl);
|
||||
},
|
||||
icon: Icon(Ionicons.download_outline)),
|
||||
hideRightChevron: true,
|
||||
|
Loading…
x
Reference in New Issue
Block a user