Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • android/org.benoitharrault.scrobbles
1 result
Show changes
Showing
with 580 additions and 73 deletions
import 'dart:convert';
class StatisticsGlobalData {
final int totalCount;
final DateTime lastScrobble;
final int? totalCount;
final DateTime? lastScrobble;
const StatisticsGlobalData({
required this.totalCount,
required this.lastScrobble,
});
factory StatisticsGlobalData.fromJson(Map<String, dynamic> json) {
factory StatisticsGlobalData.fromJson(Map<String, dynamic>? json) {
return StatisticsGlobalData(
totalCount: json['totalCount'] != null ? json['totalCount'] as int : 0,
lastScrobble: (json['lastScrobble'] != null && json['lastScrobble']['date'] != null)
totalCount: (json?['totalCount'] != null) ? (json?['totalCount'] as int) : null,
lastScrobble: (json?['lastScrobble'] != null && json?['lastScrobble']['date'] != null)
? DateTime.parse(
json['lastScrobble']['date'],
json?['lastScrobble']['date'],
)
: DateTime.now(),
: null,
);
}
factory StatisticsGlobalData.createEmpty() {
return StatisticsGlobalData.fromJson({});
}
String toString() {
Map<String, dynamic> map = {
Map<String, Object?>? toJson() {
return <String, Object?>{
'totalCount': this.totalCount,
'lastScrobble': {
'date': this.lastScrobble.toString(),
'date': this.lastScrobble != null ? this.lastScrobble.toString() : null,
},
};
}
return jsonEncode(map);
String toString() {
return jsonEncode(this.toJson());
}
}
import 'dart:convert';
class StatisticsRecentData {
final int recentCount;
final int firstPlayedArtistsCount;
final int firstPlayedTracksCount;
final int selectedPeriod;
final int? recentCount;
final int? firstPlayedArtistsCount;
final int? firstPlayedTracksCount;
final int? selectedPeriod;
const StatisticsRecentData({
required this.recentCount,
......@@ -13,29 +13,30 @@ class StatisticsRecentData {
required this.selectedPeriod,
});
factory StatisticsRecentData.fromJson(Map<String, dynamic> json) {
factory StatisticsRecentData.fromJson(Map<String, dynamic>? json) {
return StatisticsRecentData(
recentCount: json['recentCount'] != null ? json['recentCount'] as int : 0,
firstPlayedArtistsCount:
json['firstPlayedArtistsCount'] != null ? json['firstPlayedArtistsCount'] as int : 0,
firstPlayedTracksCount:
json['firstPlayedTracksCount'] != null ? json['firstPlayedTracksCount'] as int : 0,
selectedPeriod: json['selectedPeriod'] != null ? json['selectedPeriod'] as int : 0,
recentCount: (json?['recentCount'] != null) ? (json?['recentCount'] as int) : null,
firstPlayedArtistsCount: (json?['firstPlayedArtistsCount'] != null)
? (json?['firstPlayedArtistsCount'] as int)
: null,
firstPlayedTracksCount: (json?['firstPlayedTracksCount'] != null)
? (json?['firstPlayedTracksCount'] as int)
: null,
selectedPeriod:
(json?['selectedPeriod'] != null) ? (json?['selectedPeriod'] as int) : null,
);
}
factory StatisticsRecentData.createEmpty() {
return StatisticsRecentData.fromJson({});
}
String toString() {
Map<String, dynamic> map = {
Map<String, Object?>? toJson() {
return <String, Object?>{
'recentCount': this.recentCount,
'firstPlayedArtistsCount': this.firstPlayedArtistsCount,
'firstPlayedTracksCount': this.firstPlayedTracksCount,
'selectedPeriod': this.selectedPeriod,
};
}
return jsonEncode(map);
String toString() {
return jsonEncode(this.toJson());
}
}
......@@ -6,10 +6,10 @@ class TimelineDataValue {
const TimelineDataValue({required this.counts, required this.eclecticism});
factory TimelineDataValue.fromJson(Map<String, dynamic> json) {
factory TimelineDataValue.fromJson(Map<String, dynamic>? json) {
return TimelineDataValue(
counts: json['counts'] as int,
eclecticism: json['eclecticism'] as int,
counts: json?['counts'] as int,
eclecticism: json?['eclecticism'] as int,
);
}
}
......@@ -21,10 +21,10 @@ class TimelineData {
required this.data,
});
factory TimelineData.fromJson(Map<String, dynamic> json) {
factory TimelineData.fromJson(Map<String, dynamic>? json) {
Map<String, TimelineDataValue> data = {};
json.keys.forEach((date) {
json?.keys.forEach((date) {
TimelineDataValue value = TimelineDataValue(
counts: json[date]['counts'] as int,
eclecticism: json[date]['eclecticism'] as int,
......@@ -36,11 +36,7 @@ class TimelineData {
return TimelineData(data: data);
}
factory TimelineData.createEmpty() {
return TimelineData.fromJson({});
}
String toString() {
Map<String, Object?>? toJson() {
Map<String, Map<String, int>> map = {};
this.data.keys.forEach((element) {
......@@ -51,6 +47,10 @@ class TimelineData {
};
});
return jsonEncode(map);
return map;
}
String toString() {
return jsonEncode(this.toJson());
}
}
import 'dart:convert';
class TopArtistsDataValue {
final String artistName;
final int count;
const TopArtistsDataValue({required this.artistName, required this.count});
factory TopArtistsDataValue.fromJson(Map<String, dynamic>? json) {
return TopArtistsDataValue(
artistName: json?['artistName'] as String,
count: json?['count'] as int,
);
}
}
class TopArtistsData {
final List<TopArtistsDataValue> topArtists;
const TopArtistsData({
required this.topArtists,
});
factory TopArtistsData.fromJson(Map<String, dynamic>? json) {
List<TopArtistsDataValue> topArtists = [];
json?['top-artists'].forEach((element) {
TopArtistsDataValue value = TopArtistsDataValue(
artistName: element['artistName'] as String,
count: element['count'] as int,
);
topArtists.add(value);
});
return TopArtistsData(
topArtists: topArtists,
);
}
Map<String, Object?>? toJson() {
List<Map<String, Object>> listArtists = [];
this.topArtists.forEach((TopArtistsDataValue? item) {
listArtists.add({
'artistName': item != null ? item.artistName : '',
'count': item != null ? item.count : 0,
});
});
return {
'top-artists': listArtists,
};
}
String toString() {
return jsonEncode(this.toJson());
}
}
import 'dart:convert';
import 'package:http/http.dart' as http;
import '../models/counts_by_day.dart';
import '../models/counts_by_hour.dart';
import '../models/discoveries.dart';
import '../models/statistics_global.dart';
import '../models/statistics_recent.dart';
import '../models/timeline.dart';
import 'package:scrobbles/models/counts_by_day.dart';
import 'package:scrobbles/models/counts_by_hour.dart';
import 'package:scrobbles/models/discoveries.dart';
import 'package:scrobbles/models/statistics_global.dart';
import 'package:scrobbles/models/statistics_recent.dart';
import 'package:scrobbles/models/timeline.dart';
import 'package:scrobbles/models/topartists.dart';
class ScrobblesApi {
static String baseUrl = 'https://scrobble.harrault.fr';
......@@ -82,4 +83,16 @@ class ScrobblesApi {
throw Exception('Failed to get data from API.');
}
}
static Future<TopArtistsData> fetchTopArtists(int daysCount) async {
final String url = baseUrl + '/data/' + daysCount.toString() + '/top-artists';
print('fetching ' + url);
final response = await http.get(Uri.parse(url));
if (response.statusCode == 200) {
return TopArtistsData.fromJson(jsonDecode(response.body) as Map<String, dynamic>);
} else {
throw Exception('Failed to get data from API.');
}
}
}
import 'package:flutter/material.dart';
import '../widgets/main_screen/discoveries_card.dart';
import 'package:scrobbles/ui/widgets/cards/discoveries.dart';
class DiscoveriesScreen extends StatefulWidget {
const DiscoveriesScreen({super.key});
class ScreenDiscoveries extends StatefulWidget {
const ScreenDiscoveries({super.key});
@override
State<DiscoveriesScreen> createState() => _DiscoveriesScreenState();
State<ScreenDiscoveries> createState() => _ScreenDiscoveriesState();
}
class _DiscoveriesScreenState extends State<DiscoveriesScreen> {
class _ScreenDiscoveriesState extends State<ScreenDiscoveries> {
@override
Widget build(BuildContext context) {
return Material(
......@@ -19,7 +19,7 @@ class _DiscoveriesScreenState extends State<DiscoveriesScreen> {
physics: const BouncingScrollPhysics(),
children: <Widget>[
const SizedBox(height: 8),
const ChartDiscoveriesCard(),
const CardDiscoveries(),
const SizedBox(height: 36),
],
),
......
import 'package:flutter/material.dart';
import '../widgets/main_screen/statistics_global_card.dart';
import '../widgets/main_screen/statistics_recent_card.dart';
import '../widgets/main_screen/timeline_card.dart';
import 'package:scrobbles/ui/widgets/cards/statistics_global.dart';
import 'package:scrobbles/ui/widgets/cards/statistics_recent.dart';
import 'package:scrobbles/ui/widgets/cards/timeline.dart';
import 'package:scrobbles/ui/widgets/cards/top_artists.dart';
class HomeScreen extends StatefulWidget {
const HomeScreen({super.key});
class ScreenHome extends StatefulWidget {
const ScreenHome({super.key});
@override
State<HomeScreen> createState() => _HomeScreenState();
State<ScreenHome> createState() => _ScreenHomeState();
}
class _HomeScreenState extends State<HomeScreen> {
class _ScreenHomeState extends State<ScreenHome> {
@override
Widget build(BuildContext context) {
return Material(
......@@ -21,11 +22,13 @@ class _HomeScreenState extends State<HomeScreen> {
physics: const BouncingScrollPhysics(),
children: <Widget>[
const SizedBox(height: 8),
const StatisticsGlobalCard(),
const CardStatisticsGlobal(),
const SizedBox(height: 6),
const StatisticsRecentCard(),
const CardStatisticsRecent(),
const SizedBox(height: 6),
const ChartTimelineCard(),
const CardTimeline(),
const SizedBox(height: 6),
const CardTopArtists(),
const SizedBox(height: 36),
],
),
......
import 'package:flutter/material.dart';
import '../widgets/main_screen/counts_by_day_card.dart';
import '../widgets/main_screen/counts_by_hour_card.dart';
import 'package:scrobbles/ui/widgets/cards/counts_by_day.dart';
import 'package:scrobbles/ui/widgets/cards/counts_by_hour.dart';
class StatisticsScreen extends StatefulWidget {
const StatisticsScreen({super.key});
class ScreenStatistics extends StatefulWidget {
const ScreenStatistics({super.key});
@override
State<StatisticsScreen> createState() => _StatisticsScreenState();
State<ScreenStatistics> createState() => _ScreenStatisticsState();
}
class _StatisticsScreenState extends State<StatisticsScreen> {
class _ScreenStatisticsState extends State<ScreenStatistics> {
@override
Widget build(BuildContext context) {
return Material(
......@@ -20,9 +20,9 @@ class _StatisticsScreenState extends State<StatisticsScreen> {
physics: const BouncingScrollPhysics(),
children: <Widget>[
const SizedBox(height: 8),
const ChartCountsByDayCard(),
const CardCountsByDay(),
const SizedBox(height: 6),
const ChartCountsByHourCard(),
const CardCountsByHour(),
const SizedBox(height: 36),
],
),
......
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_swipe/flutter_swipe.dart';
import '../../cubit/bottom_nav_cubit.dart';
import '../widgets/app_bar.dart';
import '../widgets/bottom_nav_bar.dart';
import 'discoveries_screen.dart';
import 'home_screen.dart';
import 'statistics_screen.dart';
import 'package:scrobbles/cubit/bottom_nav_cubit.dart';
import 'package:scrobbles/ui/screens/discoveries.dart';
import 'package:scrobbles/ui/screens/home.dart';
import 'package:scrobbles/ui/screens/statistics.dart';
import 'package:scrobbles/ui/widgets/app_bar.dart';
import 'package:scrobbles/ui/widgets/bottom_nav_bar.dart';
class SkeletonScreen extends StatefulWidget {
const SkeletonScreen({super.key});
......@@ -20,37 +20,40 @@ class _SkeletonScreenState extends State<SkeletonScreen> {
@override
Widget build(BuildContext context) {
const List<Widget> pageNavigation = <Widget>[
const HomeScreen(),
const DiscoveriesScreen(),
const StatisticsScreen(),
const ScreenHome(),
const ScreenDiscoveries(),
const ScreenStatistics(),
];
return BlocProvider<BottomNavCubit>(
create: (BuildContext context) => BottomNavCubit(),
child: BlocBuilder<BottomNavCubit, int>(
builder: (BuildContext context, int state) {
return GestureDetector(
onHorizontalDragEnd: (dragDetail) {
if (dragDetail.velocity.pixelsPerSecond.dx < 1) {
context.read<BottomNavCubit>().moveNext();
} else {
context.read<BottomNavCubit>().movePrevious();
}
},
child: Scaffold(
appBar: StandardAppBar(notifyParent: refresh),
extendBodyBehindAppBar: false,
body: BlocBuilder<BottomNavCubit, int>(
builder: (BuildContext context, int state) {
return AnimatedSwitcher(
duration: const Duration(milliseconds: 300),
child: pageNavigation.elementAt(state),
);
},
return Scaffold(
appBar: StandardAppBar(notifyParent: refresh),
extendBodyBehindAppBar: false,
body: Swiper(
itemCount: BlocProvider.of<BottomNavCubit>(context).pagesCount,
itemBuilder: (BuildContext context, int index) {
return AnimatedSwitcher(
duration: const Duration(milliseconds: 300),
child: pageNavigation.elementAt(index),
);
},
pagination: SwiperPagination(
builder: SwiperCustomPagination(
builder: (BuildContext context, SwiperPluginConfig config) {
return BottomNavBar(swipeController: config.controller);
},
),
),
bottomNavigationBar: const BottomNavBar(),
backgroundColor: Theme.of(context).colorScheme.background,
onIndexChanged: (newPageIndex) {
BlocProvider.of<BottomNavCubit>(context).updateIndex(newPageIndex);
},
outer: true,
loop: false,
),
backgroundColor: Theme.of(context).colorScheme.background,
);
},
),
......
......@@ -2,12 +2,13 @@ import 'package:easy_localization/easy_localization.dart';
import 'package:fl_chart/fl_chart.dart';
import 'package:flutter/material.dart';
import '../../../config/app_colors.dart';
import '../../../utils/color_extensions.dart';
import 'package:scrobbles/config/app_colors.dart';
import 'package:scrobbles/utils/color_extensions.dart';
class CustomBarChart extends StatelessWidget {
CustomBarChart({super.key});
final Widget placeholder = Text('⏳');
final double chartHeight = 150.0;
final double verticalTicksInterval = 10;
final String verticalAxisTitleSuffix = '';
......
import 'package:fl_chart/fl_chart.dart';
import 'package:flutter/material.dart';
import '../../../config/app_colors.dart';
import 'package:scrobbles/config/app_colors.dart';
class CustomLineChart extends StatelessWidget {
CustomLineChart({super.key});
final Widget placeholder = Text('⏳');
final double chartHeight = 150.0;
final double titleFontSize = 10;
......
import 'package:flutter/material.dart';
import 'package:unicons/unicons.dart';
import '../widgets/header.dart';
import 'package:scrobbles/ui/widgets/update_data.dart';
import 'package:scrobbles/ui/widgets/header_app.dart';
class StandardAppBar extends StatelessWidget implements PreferredSizeWidget {
final Function() notifyParent;
......@@ -11,8 +12,9 @@ class StandardAppBar extends StatelessWidget implements PreferredSizeWidget {
@override
Widget build(BuildContext context) {
return AppBar(
title: const Header(text: 'app_name'),
title: const AppHeader(text: 'app_name'),
actions: [
UpdateData(),
IconButton(
onPressed: () {
this.notifyParent();
......
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_swipe/flutter_swipe.dart';
import 'package:ionicons/ionicons.dart';
import '../../cubit/bottom_nav_cubit.dart';
import 'package:scrobbles/cubit/bottom_nav_cubit.dart';
class BottomNavBar extends StatelessWidget {
const BottomNavBar({super.key});
const BottomNavBar({super.key, required this.swipeController});
final SwiperController swipeController;
@override
Widget build(BuildContext context) {
return Card(
margin: const EdgeInsets.only(top: 1, right: 4, left: 4),
margin: const EdgeInsets.only(
top: 1,
right: 0,
left: 0,
),
elevation: 4,
shadowColor: Theme.of(context).colorScheme.shadow,
color: Theme.of(context).colorScheme.surfaceVariant,
......@@ -25,7 +32,10 @@ class BottomNavBar extends StatelessWidget {
builder: (BuildContext context, int state) {
return BottomNavigationBar(
currentIndex: state,
onTap: (int index) => context.read<BottomNavCubit>().updateIndex(index),
onTap: (int index) {
context.read<BottomNavCubit>().updateIndex(index);
swipeController.move(index);
},
type: BottomNavigationBarType.fixed,
elevation: 0,
backgroundColor: Colors.transparent,
......
import 'package:flutter/material.dart';
class CardContent extends StatelessWidget {
const CardContent({
super.key,
required this.title,
required this.color,
required this.content,
});
final String title;
final Color color;
final Widget content;
@override
Widget build(BuildContext context) {
return Card(
elevation: 2,
shadowColor: Theme.of(context).colorScheme.shadow,
color: this.color,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.all(
Radius.circular(8),
),
),
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
this.title,
style: Theme.of(context).primaryTextTheme.titleLarge!.apply(fontWeightDelta: 2),
),
const SizedBox(height: 8),
this.content,
],
),
),
);
}
}
import 'dart:convert';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:scrobbles/config/settings.dart';
import 'package:scrobbles/cubit/data_counts_by_day_cubit.dart';
import 'package:scrobbles/models/counts_by_day.dart';
import 'package:scrobbles/ui/widgets/card_content.dart';
import 'package:scrobbles/ui/widgets/charts/counts_by_day.dart';
class CardCountsByDay extends StatelessWidget {
const CardCountsByDay({super.key});
@override
Widget build(BuildContext context) {
final int daysCount = Settings.countsByDayDaysCount;
return BlocProvider<DataCountsByDayCubit>(
create: (BuildContext context) => DataCountsByDayCubit(),
child: BlocBuilder<DataCountsByDayCubit, DataCountsByDayState>(
builder: (BuildContext context, DataCountsByDayState state) {
return CardContent(
color: Theme.of(context).colorScheme.surface,
title: 'counts_by_day'.tr(
namedArgs: {
'daysCount': daysCount.toString(),
},
),
content: ChartCountsByDay(
chartData: CountsByDayData.fromJson(jsonDecode(state.countsByDay.toString())),
isLoading: false,
),
);
},
),
);
}
}
import 'dart:convert';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:scrobbles/config/settings.dart';
import 'package:scrobbles/cubit/data_counts_by_hour_cubit.dart';
import 'package:scrobbles/models/counts_by_hour.dart';
import 'package:scrobbles/ui/widgets/card_content.dart';
import 'package:scrobbles/ui/widgets/charts/counts_by_hour.dart';
class CardCountsByHour extends StatelessWidget {
const CardCountsByHour({super.key});
@override
Widget build(BuildContext context) {
final int daysCount = Settings.countsByHourDaysCount;
return BlocProvider<DataCountsByHourCubit>(
create: (BuildContext context) => DataCountsByHourCubit(),
child: BlocBuilder<DataCountsByHourCubit, DataCountsByHourState>(
builder: (BuildContext context, DataCountsByHourState state) {
return CardContent(
color: Theme.of(context).colorScheme.surface,
title: 'counts_by_hour'.tr(
namedArgs: {
'daysCount': daysCount.toString(),
},
),
content: ChartCountsByHour(
chartData: CountsByHourData.fromJson(jsonDecode(state.countsByHour.toString())),
isLoading: false,
),
);
},
),
);
}
}
import 'dart:convert';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:scrobbles/config/settings.dart';
import 'package:scrobbles/cubit/data_discoveries_cubit.dart';
import 'package:scrobbles/models/discoveries.dart';
import 'package:scrobbles/ui/widgets/card_content.dart';
import 'package:scrobbles/ui/widgets/charts/discoveries_artists.dart';
import 'package:scrobbles/ui/widgets/charts/discoveries_tracks.dart';
class CardDiscoveries extends StatelessWidget {
const CardDiscoveries({super.key});
@override
Widget build(BuildContext context) {
final int daysCount = Settings.discoveriesDaysCount;
return BlocProvider<DataDiscoveriesCubit>(
create: (BuildContext context) => DataDiscoveriesCubit(),
child: BlocBuilder<DataDiscoveriesCubit, DataDiscoveriesState>(
builder: (BuildContext context, DataDiscoveriesState state) {
final TextTheme textTheme = Theme.of(context).primaryTextTheme;
return CardContent(
color: Theme.of(context).colorScheme.surface,
title: 'discoveries_title'.tr(
namedArgs: {
'daysCount': daysCount.toString(),
},
),
content: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'discoveries_artists_title',
style: textTheme.titleMedium!.apply(fontWeightDelta: 2),
).tr(),
const SizedBox(height: 8),
ChartDiscoveriesArtists(
chartData:
DiscoveriesData.fromJson(jsonDecode(state.discoveries.toString())),
isLoading: false,
),
const SizedBox(height: 8),
Text(
'discoveries_tracks_title',
style: textTheme.titleMedium!.apply(fontWeightDelta: 2),
).tr(),
const SizedBox(height: 8),
ChartDiscoveriesTracks(
chartData:
DiscoveriesData.fromJson(jsonDecode(state.discoveries.toString())),
isLoading: false,
),
],
),
);
},
),
);
}
}
import 'dart:convert';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:scrobbles/cubit/data_statistics_global_cubit.dart';
import 'package:scrobbles/models/statistics_global.dart';
import 'package:scrobbles/ui/widgets/card_content.dart';
import 'package:scrobbles/ui/widgets/content/statistics_global.dart';
class CardStatisticsGlobal extends StatelessWidget {
const CardStatisticsGlobal({super.key});
@override
Widget build(BuildContext context) {
return BlocProvider<DataStatisticsGlobalCubit>(
create: (BuildContext context) => DataStatisticsGlobalCubit(),
child: BlocBuilder<DataStatisticsGlobalCubit, DataStatisticsGlobalState>(
builder: (BuildContext context, DataStatisticsGlobalState state) {
return CardContent(
color: Theme.of(context).colorScheme.primary,
title: 'global_statistics'.tr(),
content: ContentStatisticsGlobal(
statistics:
StatisticsGlobalData.fromJson(jsonDecode(state.statisticsGlobal.toString())),
isLoading: false,
),
);
},
),
);
}
}
import 'dart:convert';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:scrobbles/config/settings.dart';
import 'package:scrobbles/cubit/data_statistics_recent_cubit.dart';
import 'package:scrobbles/models/statistics_recent.dart';
import 'package:scrobbles/ui/widgets/card_content.dart';
import 'package:scrobbles/ui/widgets/content/statistics_recent.dart';
class CardStatisticsRecent extends StatelessWidget {
const CardStatisticsRecent({super.key});
@override
Widget build(BuildContext context) {
final int daysCount = Settings.statisticsRecentDaysCount;
// data context
return BlocProvider<DataStatisticsRecentCubit>(
create: (BuildContext context) => DataStatisticsRecentCubit(),
child: BlocBuilder<DataStatisticsRecentCubit, DataStatisticsRecentState>(
builder: (BuildContext context, DataStatisticsRecentState dataState) {
return CardContent(
color: Theme.of(context).colorScheme.primary,
title: 'recent_statistics'.tr(
namedArgs: {
'daysCount': daysCount.toString(),
},
),
content: ContentStatisticsRecent(
statistics: StatisticsRecentData.fromJson(
jsonDecode(dataState.statisticsRecent.toString())),
isLoading: false,
),
);
},
),
);
}
}
import 'dart:convert';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:scrobbles/config/settings.dart';
import 'package:scrobbles/cubit/data_timeline_cubit.dart';
import 'package:scrobbles/models/timeline.dart';
import 'package:scrobbles/ui/widgets/card_content.dart';
import 'package:scrobbles/ui/widgets/charts/timeline_counts.dart';
import 'package:scrobbles/ui/widgets/charts/timeline_eclecticism.dart';
class CardTimeline extends StatelessWidget {
const CardTimeline({super.key});
@override
Widget build(BuildContext context) {
final int daysCount = Settings.timelineDaysCount;
return BlocProvider<DataTimelineCubit>(
create: (BuildContext context) => DataTimelineCubit(),
child: BlocBuilder<DataTimelineCubit, DataTimelineState>(
builder: (BuildContext context, DataTimelineState state) {
return CardContent(
color: Theme.of(context).colorScheme.surface,
title: 'timeline_title'.tr(
namedArgs: {
'daysCount': daysCount.toString(),
},
),
content: Stack(
children: [
ChartTimelineCounts(
chartData: TimelineData.fromJson(jsonDecode(state.timeline.toString())),
isLoading: false,
),
ChartTimelineEclecticism(
chartData: TimelineData.fromJson(jsonDecode(state.timeline.toString())),
isLoading: false,
),
],
),
);
},
),
);
}
}