parent
8a490abb10
commit
d2bb3c4a5c
|
@ -111,3 +111,12 @@ class GiteaIssue {
|
|||
factory GiteaIssue.fromJson(Map<String, dynamic> json) =>
|
||||
_$GiteaIssueFromJson(json);
|
||||
}
|
||||
|
||||
@JsonSerializable(fieldRename: FieldRename.snake)
|
||||
class GiteaHeatmapItem {
|
||||
int timestamp;
|
||||
int contributions;
|
||||
GiteaHeatmapItem();
|
||||
factory GiteaHeatmapItem.fromJson(Map<String, dynamic> json) =>
|
||||
_$GiteaHeatmapItemFromJson(json);
|
||||
}
|
||||
|
|
|
@ -196,3 +196,15 @@ Map<String, dynamic> _$GiteaIssueToJson(GiteaIssue instance) =>
|
|||
'updated_at': instance.updatedAt?.toIso8601String(),
|
||||
'html_url': instance.htmlUrl,
|
||||
};
|
||||
|
||||
GiteaHeatmapItem _$GiteaHeatmapItemFromJson(Map<String, dynamic> json) {
|
||||
return GiteaHeatmapItem()
|
||||
..timestamp = json['timestamp'] as int
|
||||
..contributions = json['contributions'] as int;
|
||||
}
|
||||
|
||||
Map<String, dynamic> _$GiteaHeatmapItemToJson(GiteaHeatmapItem instance) =>
|
||||
<String, dynamic>{
|
||||
'timestamp': instance.timestamp,
|
||||
'contributions': instance.contributions,
|
||||
};
|
||||
|
|
|
@ -6,6 +6,7 @@ import 'package:git_touch/scaffolds/refresh_stateful.dart';
|
|||
import 'package:git_touch/utils/utils.dart';
|
||||
import 'package:git_touch/widgets/action_entry.dart';
|
||||
import 'package:git_touch/widgets/app_bar_title.dart';
|
||||
import 'package:git_touch/widgets/contribution.dart';
|
||||
import 'package:git_touch/widgets/mutation_button.dart';
|
||||
import 'package:git_touch/widgets/entry_item.dart';
|
||||
import 'package:git_touch/widgets/repository_item.dart';
|
||||
|
@ -112,37 +113,12 @@ class GhUserScreen extends StatelessWidget {
|
|||
),
|
||||
]),
|
||||
CommonStyle.border,
|
||||
Container(
|
||||
alignment: Alignment.center,
|
||||
padding: CommonStyle.padding,
|
||||
child: SingleChildScrollView(
|
||||
scrollDirection: Axis.horizontal,
|
||||
reverse: true,
|
||||
child: Wrap(
|
||||
spacing: 3,
|
||||
children: p.contributionsCollection.contributionCalendar.weeks
|
||||
.map((week) {
|
||||
return Wrap(
|
||||
direction: Axis.vertical,
|
||||
spacing: 3,
|
||||
children: week.contributionDays.map((day) {
|
||||
var color = convertColor(day.color);
|
||||
if (theme.brightness == Brightness.dark) {
|
||||
color = Color.fromRGBO(0xff - color.red,
|
||||
0xff - color.green, 0xff - color.blue, 1);
|
||||
}
|
||||
return SizedBox(
|
||||
width: 10,
|
||||
height: 10,
|
||||
child: DecoratedBox(
|
||||
decoration: BoxDecoration(color: color),
|
||||
),
|
||||
);
|
||||
}).toList(),
|
||||
);
|
||||
}).toList(),
|
||||
),
|
||||
),
|
||||
ContributionWidget(
|
||||
weeks: p.contributionsCollection.contributionCalendar.weeks.map((e) {
|
||||
return e.contributionDays.map((d) {
|
||||
return ContributionDay(hexColor: d.color);
|
||||
});
|
||||
}),
|
||||
),
|
||||
CommonStyle.border,
|
||||
TableView(
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import 'dart:math';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:git_touch/models/auth.dart';
|
||||
|
@ -5,6 +6,7 @@ import 'package:git_touch/models/gitea.dart';
|
|||
import 'package:git_touch/scaffolds/refresh_stateful.dart';
|
||||
import 'package:git_touch/utils/utils.dart';
|
||||
import 'package:git_touch/widgets/action_entry.dart';
|
||||
import 'package:git_touch/widgets/contribution.dart';
|
||||
import 'package:git_touch/widgets/repository_item.dart';
|
||||
import 'package:git_touch/widgets/user_header.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
@ -18,17 +20,42 @@ class GtUserScreen extends StatelessWidget {
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return RefreshStatefulScaffold<Tuple2<GiteaUser, List<GiteaRepository>>>(
|
||||
return RefreshStatefulScaffold<
|
||||
Tuple3<GiteaUser, List<GiteaRepository>, List<List<ContributionDay>>>>(
|
||||
title: Text(isViewer ? 'Me' : 'User'),
|
||||
fetchData: () async {
|
||||
final auth = context.read<AuthModel>();
|
||||
final res = await Future.wait([
|
||||
auth.fetchGitea(isViewer ? '/user' : '/users/$login'),
|
||||
auth.fetchGitea(isViewer ? '/user/repos' : '/users/$login/repos'),
|
||||
auth.fetchGitea(
|
||||
'/users/${login ?? auth.activeAccount.login}/heatmap'),
|
||||
]);
|
||||
return Tuple2(
|
||||
final heatmapItems = [
|
||||
for (final v in res[2]) GiteaHeatmapItem.fromJson(v)
|
||||
];
|
||||
List<List<ContributionDay>> heatmapWeeks = [[]];
|
||||
for (var i = 0; i < heatmapItems.length; i++) {
|
||||
if (i > 0 &&
|
||||
heatmapItems[i].timestamp - heatmapItems[i - 1].timestamp >
|
||||
86400) {
|
||||
if (heatmapWeeks.last.length == 7) {
|
||||
heatmapWeeks.add([]);
|
||||
}
|
||||
heatmapWeeks.last.add(ContributionDay(count: 0));
|
||||
} else {
|
||||
if (heatmapWeeks.last.length == 7) {
|
||||
heatmapWeeks.add([]);
|
||||
}
|
||||
heatmapWeeks.last
|
||||
.add(ContributionDay(count: heatmapItems[i].contributions));
|
||||
}
|
||||
}
|
||||
|
||||
return Tuple3(
|
||||
GiteaUser.fromJson(res[0]),
|
||||
[for (var v in res[1]) GiteaRepository.fromJson(v)],
|
||||
heatmapWeeks,
|
||||
);
|
||||
},
|
||||
action: isViewer
|
||||
|
@ -40,6 +67,7 @@ class GtUserScreen extends StatelessWidget {
|
|||
bodyBuilder: (data, _) {
|
||||
final user = data.item1;
|
||||
final repos = data.item2;
|
||||
final heatmapWeeks = data.item3;
|
||||
|
||||
return Column(
|
||||
children: <Widget>[
|
||||
|
@ -51,6 +79,8 @@ class GtUserScreen extends StatelessWidget {
|
|||
bio: '',
|
||||
),
|
||||
CommonStyle.border,
|
||||
ContributionWidget(weeks: heatmapWeeks),
|
||||
CommonStyle.border,
|
||||
Column(
|
||||
children: <Widget>[
|
||||
for (var v in repos)
|
||||
|
|
|
@ -0,0 +1,87 @@
|
|||
import 'dart:math';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:git_touch/models/theme.dart';
|
||||
import 'package:git_touch/utils/utils.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
class ContributionDay {
|
||||
String hexColor;
|
||||
int count;
|
||||
Color color;
|
||||
ContributionDay({this.hexColor, this.count, this.color})
|
||||
: assert(hexColor != null || count != null || color != null);
|
||||
}
|
||||
|
||||
class ContributionWidget extends StatelessWidget {
|
||||
final Iterable<Iterable<ContributionDay>> weeks;
|
||||
ContributionWidget({@required this.weeks}) {
|
||||
int maxCount;
|
||||
for (var week in weeks) {
|
||||
for (var day in week) {
|
||||
if (day.count != null) {
|
||||
if (maxCount == null) {
|
||||
for (var week in weeks) {
|
||||
for (var day in week) {
|
||||
maxCount = max(day.count, maxCount ?? 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (day.count == 0) {
|
||||
day.hexColor = emptyColor;
|
||||
} else {
|
||||
final level = (day.count * 4) ~/ (maxCount + 1);
|
||||
day.hexColor = colors[level];
|
||||
}
|
||||
}
|
||||
if (day.hexColor != null) {
|
||||
day.color = convertColor(day.hexColor);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static const emptyColor = '#ebedf0';
|
||||
static const colors = ['#9be9a8', '#40c463', '#30a14e', '#216e39'];
|
||||
|
||||
static Color _revert(Color color) {
|
||||
return Color.fromRGBO(
|
||||
0xff - color.red, 0xff - color.green, 0xff - color.blue, 1);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final theme = context.watch<ThemeModel>();
|
||||
return Container(
|
||||
alignment: Alignment.center,
|
||||
padding: CommonStyle.padding,
|
||||
child: SingleChildScrollView(
|
||||
scrollDirection: Axis.horizontal,
|
||||
reverse: true,
|
||||
child: Wrap(
|
||||
spacing: 3,
|
||||
children: [
|
||||
for (final week in weeks)
|
||||
Wrap(
|
||||
direction: Axis.vertical,
|
||||
spacing: 3,
|
||||
children: [
|
||||
for (final day in week)
|
||||
SizedBox(
|
||||
width: 10,
|
||||
height: 10,
|
||||
child: DecoratedBox(
|
||||
decoration: BoxDecoration(
|
||||
color: theme.brightness == Brightness.dark
|
||||
? _revert(day.color)
|
||||
: day.color),
|
||||
),
|
||||
)
|
||||
],
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue