diff --git a/.fvm/fvm_config.json b/.fvm/fvm_config.json index a54bfce7..c15c2874 100644 --- a/.fvm/fvm_config.json +++ b/.fvm/fvm_config.json @@ -1,4 +1,4 @@ { "flutterSdkVersion": "3.14.0-0.2.pre@beta", "flavors": {} -} +} \ No newline at end of file diff --git a/assets/Illustration-Conference.svg b/assets/Illustration-Conference.svg new file mode 100644 index 00000000..d409864c --- /dev/null +++ b/assets/Illustration-Conference.svg @@ -0,0 +1,54 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/app/config.g.dart b/lib/app/config.g.dart index 3f2bd24a..62eee081 100644 --- a/lib/app/config.g.dart +++ b/lib/app/config.g.dart @@ -1,6 +1,6 @@ // GENERATED CODE - DO NOT MODIFY BY HAND -// ignore_for_file: type=lint +// ignore_for_file: type=lint, duplicate_ignore part of 'config.dart'; @@ -22,4 +22,5 @@ final configProvider = AutoDisposeProvider.internal( ); typedef ConfigRef = AutoDisposeProviderRef; -// ignore_for_file: unnecessary_raw_strings, subtype_of_sealed_class, invalid_use_of_internal_member, do_not_use_environment, prefer_const_constructors, public_member_api_docs, avoid_private_typedef_functions +// ignore_for_file: type=lint +// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member diff --git a/lib/app/home_page.dart b/lib/app/home_page.dart index 27b5f8b4..a17d4c37 100644 --- a/lib/app/home_page.dart +++ b/lib/app/home_page.dart @@ -5,6 +5,7 @@ import 'package:confwebsite2023/core/theme.dart'; import 'package:confwebsite2023/features/access/ui/access_widget.dart'; import 'package:confwebsite2023/features/count_down/model/count_down_timer.dart'; import 'package:confwebsite2023/features/count_down/ui/count_down_section.dart'; +import 'package:confwebsite2023/features/event/hands-on/ui/hands_on_event.dart'; import 'package:confwebsite2023/features/footer/ui/footer.dart'; import 'package:confwebsite2023/features/header/data/header_item_button_data.dart'; import 'package:confwebsite2023/features/header/ui/header_widget.dart'; @@ -28,6 +29,7 @@ class MainPage extends HookWidget { const sectionKeys = ( access: GlobalObjectKey('accessSectionKey'), event: GlobalObjectKey('eventSectionKey'), + ticket: GlobalObjectKey('ticketSectionKey'), session: GlobalObjectKey('sessionSectionKey'), sponsor: GlobalObjectKey('sponsorSectionKey'), staff: GlobalObjectKey('staffSectionKey'), @@ -42,6 +44,22 @@ class MainPage extends HookWidget { duration: const Duration(milliseconds: 750), ), ), + HeaderItemButtonData( + title: 'Event', + onPressed: () async => Scrollable.ensureVisible( + sectionKeys.event.currentContext!, + curve: Curves.easeOutCirc, + duration: const Duration(milliseconds: 750), + ), + ), + HeaderItemButtonData( + title: 'Ticket', + onPressed: () async => Scrollable.ensureVisible( + sectionKeys.ticket.currentContext!, + curve: Curves.easeOutCirc, + duration: const Duration(milliseconds: 750), + ), + ), HeaderItemButtonData( title: 'Staff', onPressed: () async => Scrollable.ensureVisible( @@ -74,6 +92,7 @@ class _MainPageBody extends StatelessWidget { final ({ GlobalObjectKey access, GlobalObjectKey event, + GlobalObjectKey ticket, GlobalObjectKey session, GlobalObjectKey sponsor, GlobalObjectKey staff @@ -155,17 +174,31 @@ class _MainPageBody extends StatelessWidget { padding: padding, child: const NewsSection(), ), + const SliverToBoxAdapter( + child: Spaces.vertical_200, + ), _Sliver( padding: padding, - child: const TicketSection(), + child: AccessWidget( + key: sectionKeys.access, + ), ), const SliverToBoxAdapter( child: Spaces.vertical_200, ), _Sliver( padding: padding, - child: AccessWidget( - key: sectionKeys.access, + child: TicketSection( + key: sectionKeys.ticket, + ), + ), + const SliverToBoxAdapter( + child: Spaces.vertical_200, + ), + _Sliver( + padding: padding, + child: HandsOnEvent( + key: sectionKeys.event, ), ), const SliverToBoxAdapter( diff --git a/lib/core/components/left_filled_icon_button.dart b/lib/core/components/left_filled_icon_button.dart new file mode 100644 index 00000000..a4797c6f --- /dev/null +++ b/lib/core/components/left_filled_icon_button.dart @@ -0,0 +1,54 @@ +import 'package:confwebsite2023/core/theme.dart'; +import 'package:flutter/material.dart'; + +class LeftFilledIconButton extends StatelessWidget { + const LeftFilledIconButton({ + required this.onPressed, + required this.buttonTitle, + required this.icon, + super.key, + }); + + final void Function() onPressed; + final String buttonTitle; + final IconData icon; + + @override + Widget build(BuildContext context) { + final theme = Theme.of(context); + final textTheme = theme.textTheme; + final colorScheme = theme.colorScheme; + return SizedBox( + height: 40, + child: ElevatedButton( + style: ElevatedButton.styleFrom( + backgroundColor: colorScheme.primary, + padding: const EdgeInsets.symmetric( + horizontal: 16, + vertical: 8, + ), + ), + onPressed: onPressed, + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + mainAxisSize: MainAxisSize.min, + children: [ + Spaces.horizontal_8, + Text( + buttonTitle, + style: textTheme.labelLarge?.copyWith( + color: colorScheme.onPrimary, + ), + ), + Spaces.horizontal_8, + Icon( + icon, + size: 18, + color: colorScheme.onPrimary, + ), + ], + ), + ), + ); + } +} diff --git a/lib/core/components/profile_image.dart b/lib/core/components/profile_image.dart new file mode 100644 index 00000000..e38f2a94 --- /dev/null +++ b/lib/core/components/profile_image.dart @@ -0,0 +1,34 @@ +import 'package:flutter/material.dart'; +import 'package:transparent_image/transparent_image.dart'; + +class ProfileImage extends StatelessWidget { + const ProfileImage({ + required this.imageUrl, + required this.size, + super.key, + }); + final String imageUrl; + final double size; + + @override + Widget build(BuildContext context) { + return SizedBox( + height: size, + width: size, + child: FittedBox( + child: ClipOval( + child: FadeInImage( + fit: BoxFit.cover, + image: NetworkImage(imageUrl), + placeholder: MemoryImage(kTransparentImage), + imageErrorBuilder: (_, __, ___) => const FittedBox( + child: Icon( + Icons.error, + ), + ), + ), + ), + ), + ); + } +} diff --git a/lib/core/components/wanted.dart b/lib/core/components/wanted.dart index 96b4f81d..2c43f227 100644 --- a/lib/core/components/wanted.dart +++ b/lib/core/components/wanted.dart @@ -1,3 +1,4 @@ +import 'package:confwebsite2023/core/components/left_filled_icon_button.dart'; import 'package:confwebsite2023/core/components/responsive_widget.dart'; import 'package:confwebsite2023/core/components/section_header.dart'; import 'package:confwebsite2023/core/theme.dart'; @@ -11,6 +12,7 @@ class WantedWidget extends StatelessWidget { required this.content, required this.buttonTitle, required this.onPressed, + this.child, this.image, this.subContent, super.key, @@ -19,6 +21,7 @@ class WantedWidget extends StatelessWidget { final String title; final String content; final String? subContent; + final Widget? child; final String buttonTitle; final String? image; final VoidCallback onPressed; @@ -26,41 +29,44 @@ class WantedWidget extends StatelessWidget { @override Widget build(BuildContext context) { return ResponsiveWidget( - largeWidget: WantedDesktop( + largeWidget: _WantedDesktop( title: title, content: content, subContent: subContent, buttonTitle: buttonTitle, image: image, onPressed: onPressed, + child: child, ), - smallWidget: WantedMobile( + smallWidget: _WantedMobile( title: title, content: content, subContent: subContent, buttonTitle: buttonTitle, image: image, onPressed: onPressed, + child: child, ), ); } } -class WantedDesktop extends StatelessWidget { - const WantedDesktop({ +class _WantedDesktop extends StatelessWidget { + const _WantedDesktop({ required this.title, required this.content, required this.subContent, required this.buttonTitle, required this.image, required this.onPressed, - super.key, + this.child, }); final String title; final String content; final String? subContent; final String buttonTitle; + final Widget? child; final String? image; final VoidCallback onPressed; @@ -98,45 +104,23 @@ class WantedDesktop extends StatelessWidget { ), ), Spaces.vertical_24, - ...switch (subContent) { - final String body => [ - Text( - body, - style: textTheme.bodyMedium!.copyWith( - color: colorScheme.secondary, - ), - ), - Spaces.vertical_24, - ], - null => [], - }, - SizedBox( - height: 40, - child: ElevatedButton( - style: ElevatedButton.styleFrom( - backgroundColor: colorScheme.primary, - ), - onPressed: onPressed, - child: Row( - mainAxisSize: MainAxisSize.min, - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Spaces.horizontal_8, - Text( - buttonTitle, - style: textTheme.labelLarge?.copyWith( - color: colorScheme.onPrimary, - ), - ), - Spaces.horizontal_8, - Icon( - Icons.arrow_forward_ios, - size: 9, - color: colorScheme.onPrimary, - ), - ], + if (subContent != null) ...[ + Text( + subContent!, + style: textTheme.bodyMedium!.copyWith( + color: colorScheme.secondary, ), ), + Spaces.vertical_24, + ], + if (child != null) ...[ + child!, + Spaces.vertical_24, + ], + LeftFilledIconButton( + onPressed: onPressed, + buttonTitle: buttonTitle, + icon: Icons.arrow_forward_ios, ), ], ), @@ -158,15 +142,15 @@ class WantedDesktop extends StatelessWidget { } } -class WantedMobile extends StatelessWidget { - const WantedMobile({ +class _WantedMobile extends StatelessWidget { + const _WantedMobile({ required this.title, required this.content, required this.subContent, required this.buttonTitle, required this.image, required this.onPressed, - super.key, + this.child, }); final String title; @@ -174,6 +158,7 @@ class WantedMobile extends StatelessWidget { final String? subContent; final String buttonTitle; final String? image; + final Widget? child; final VoidCallback onPressed; @override @@ -205,42 +190,23 @@ class WantedMobile extends StatelessWidget { ), ), Spaces.vertical_24, - ...switch (subContent) { - final String body => [ - Text( - body, - style: textTheme.bodyMedium!.copyWith( - color: colorScheme.secondary, - ), - ), - Spaces.vertical_24, - ], - null => [], - }, - SizedBox( - height: 40, - child: ElevatedButton( - style: ElevatedButton.styleFrom( - backgroundColor: colorScheme.primary, - ), - onPressed: onPressed, - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text( - buttonTitle, - style: textTheme.labelLarge?.copyWith( - color: colorScheme.onPrimary, - ), - ), - Icon( - Icons.arrow_forward_ios, - size: 9, - color: colorScheme.onPrimary, - ), - ], + if (subContent != null) ...[ + Text( + subContent!, + style: textTheme.bodyMedium!.copyWith( + color: colorScheme.secondary, ), ), + Spaces.vertical_24, + ], + if (child != null) ...[ + child!, + Spaces.vertical_24, + ], + LeftFilledIconButton( + onPressed: onPressed, + buttonTitle: buttonTitle, + icon: Icons.arrow_forward_ios, ), ], ), diff --git a/lib/core/gen/assets.gen.dart b/lib/core/gen/assets.gen.dart index a18236bc..d7701065 100644 --- a/lib/core/gen/assets.gen.dart +++ b/lib/core/gen/assets.gen.dart @@ -47,6 +47,8 @@ class $AssetsIconsGen { class Assets { Assets._(); + static const String illustrationConference = + 'assets/Illustration-Conference.svg'; static const String flutterkaigiLogoShadowed = 'assets/flutterkaigi_logo_shadowed.svg'; static const String flutterkaigiLogoUnion = @@ -54,7 +56,8 @@ class Assets { static const $AssetsIconsGen icons = $AssetsIconsGen(); /// List of all assets - List get values => [flutterkaigiLogoShadowed, flutterkaigiLogoUnion]; + List get values => + [illustrationConference, flutterkaigiLogoShadowed, flutterkaigiLogoUnion]; } class AssetGenImage { diff --git a/lib/features/count_down/model/count_down_timer.g.dart b/lib/features/count_down/model/count_down_timer.g.dart index 59286c97..0be9a29f 100644 --- a/lib/features/count_down/model/count_down_timer.g.dart +++ b/lib/features/count_down/model/count_down_timer.g.dart @@ -1,6 +1,6 @@ // GENERATED CODE - DO NOT MODIFY BY HAND -// ignore_for_file: type=lint +// ignore_for_file: type=lint, duplicate_ignore part of 'count_down_timer.dart'; @@ -22,4 +22,5 @@ final nowProvider = AutoDisposeProvider.internal( ); typedef NowRef = AutoDisposeProviderRef; -// ignore_for_file: unnecessary_raw_strings, subtype_of_sealed_class, invalid_use_of_internal_member, do_not_use_environment, prefer_const_constructors, public_member_api_docs, avoid_private_typedef_functions +// ignore_for_file: type=lint +// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member diff --git a/lib/features/event/hands-on/data/hands_on_staffs_provider.dart b/lib/features/event/hands-on/data/hands_on_staffs_provider.dart new file mode 100644 index 00000000..1c98f85c --- /dev/null +++ b/lib/features/event/hands-on/data/hands_on_staffs_provider.dart @@ -0,0 +1,14 @@ +import 'package:confwebsite2023/features/staff/data/staff.dart'; +import 'package:confwebsite2023/features/staff/data/staff_provider.dart'; +import 'package:riverpod_annotation/riverpod_annotation.dart'; + +part 'hands_on_staffs_provider.g.dart'; + +@riverpod +Future> handsOnStaff(HandsOnStaffRef ref) async { + final staffs = await ref.watch(staffsProvider.future); + const handsOnTeamDisplayNames = ['okaryo', 'ちっぴー', '兼高理恵 (robo)', 'jiyuujin']; + return staffs + .where((staff) => handsOnTeamDisplayNames.contains(staff.displayName)) + .toList(); +} diff --git a/lib/features/event/hands-on/data/hands_on_staffs_provider.g.dart b/lib/features/event/hands-on/data/hands_on_staffs_provider.g.dart new file mode 100644 index 00000000..e08e2f9a --- /dev/null +++ b/lib/features/event/hands-on/data/hands_on_staffs_provider.g.dart @@ -0,0 +1,26 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +// ignore_for_file: type=lint, duplicate_ignore + +part of 'hands_on_staffs_provider.dart'; + +// ************************************************************************** +// RiverpodGenerator +// ************************************************************************** + +String _$handsOnStaffHash() => r'6c45dd0845d6b7d0ecfdc1e859c323a8c06fd3f7'; + +/// See also [handsOnStaff]. +@ProviderFor(handsOnStaff) +final handsOnStaffProvider = AutoDisposeFutureProvider>.internal( + handsOnStaff, + name: r'handsOnStaffProvider', + debugGetCreateSourceHash: + const bool.fromEnvironment('dart.vm.product') ? null : _$handsOnStaffHash, + dependencies: null, + allTransitiveDependencies: null, +); + +typedef HandsOnStaffRef = AutoDisposeFutureProviderRef>; +// ignore_for_file: type=lint +// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member diff --git a/lib/features/event/hands-on/ui/hands_on_event.dart b/lib/features/event/hands-on/ui/hands_on_event.dart new file mode 100644 index 00000000..44b9d49d --- /dev/null +++ b/lib/features/event/hands-on/ui/hands_on_event.dart @@ -0,0 +1,59 @@ +import 'package:confwebsite2023/core/components/profile_image.dart'; +import 'package:confwebsite2023/core/components/wanted.dart'; +import 'package:confwebsite2023/core/gen/assets.gen.dart'; +import 'package:confwebsite2023/features/event/hands-on/data/hands_on_staffs_provider.dart'; +import 'package:confwebsite2023/features/staff/data/staff.dart'; +import 'package:flutter/material.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:url_launcher/url_launcher_string.dart'; + +class HandsOnEvent extends StatelessWidget { + const HandsOnEvent({super.key}); + + @override + Widget build(BuildContext context) { + const text = + // ignore: lines_longer_than_80_chars + '今年のハンズオンでは、三目並べの制作を通してriverpodを学べることを目指します。また、そのチャレンジ企画として Firebase を利用したリアルタイム対戦機能も計画しています。現在、スタッフ一丸となってその準備に励んでおりますので、開催当日まで暫しお待ちいただければと思います。\n' + 'なお、開催日は昨年と違い本編とは別日の10/26に開催予定ですので、こちらも合わせてご留意ください。'; + return WantedWidget( + title: 'Join the hands-on event!', + buttonTitle: 'イベント詳細', + content: text, + onPressed: () async => launchUrlString( + 'https://flutterkaigi.connpass.com/event/293847/', + mode: LaunchMode.externalApplication, + ), + image: Assets.illustrationConference, + child: const _HandsOnStaffsIcon(), + ); + } +} + +class _HandsOnStaffsIcon extends ConsumerWidget { + const _HandsOnStaffsIcon(); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final staffs = ref.watch(handsOnStaffProvider); + + return switch ((staffs.valueOrNull, staffs.error)) { + (final List data, _) => Wrap( + alignment: WrapAlignment.center, + runAlignment: WrapAlignment.center, + crossAxisAlignment: WrapCrossAlignment.center, + spacing: 24, + children: data + .map( + (e) => ProfileImage( + imageUrl: e.image.src, + size: 120, + ), + ) + .toList(), + ), + (_, final Object error) => Text('例外が発生しました: $error'), + (_, _) => const CircularProgressIndicator(), + }; + } +} diff --git a/lib/features/news/data/news.freezed.dart b/lib/features/news/data/news.freezed.dart index ab98573e..9d2b7b0d 100644 --- a/lib/features/news/data/news.freezed.dart +++ b/lib/features/news/data/news.freezed.dart @@ -41,7 +41,7 @@ abstract class $NewsCopyWith<$Res> { String? url, DateTime startedAt, @JsonKey(fromJson: _dateTimeFromJson, toJson: _dateTimeToJson) - DateTime? endedAt}); + DateTime? endedAt}); } /// @nodoc @@ -94,7 +94,7 @@ abstract class _$$_NewsCopyWith<$Res> implements $NewsCopyWith<$Res> { String? url, DateTime startedAt, @JsonKey(fromJson: _dateTimeFromJson, toJson: _dateTimeToJson) - DateTime? endedAt}); + DateTime? endedAt}); } /// @nodoc @@ -140,7 +140,7 @@ class _$_News implements _News { required this.url, required this.startedAt, @JsonKey(fromJson: _dateTimeFromJson, toJson: _dateTimeToJson) - required this.endedAt}); + required this.endedAt}); factory _$_News.fromJson(Map json) => _$$_NewsFromJson(json); @@ -195,7 +195,7 @@ abstract class _News implements News { required final String? url, required final DateTime startedAt, @JsonKey(fromJson: _dateTimeFromJson, toJson: _dateTimeToJson) - required final DateTime? endedAt}) = _$_News; + required final DateTime? endedAt}) = _$_News; factory _News.fromJson(Map json) = _$_News.fromJson; diff --git a/lib/features/news/data/news.g.dart b/lib/features/news/data/news.g.dart index f4423a13..0532a4e6 100644 --- a/lib/features/news/data/news.g.dart +++ b/lib/features/news/data/news.g.dart @@ -1,6 +1,6 @@ // GENERATED CODE - DO NOT MODIFY BY HAND -// ignore_for_file: type=lint +// ignore_for_file: type=lint, duplicate_ignore part of 'news.dart'; diff --git a/lib/features/news/data/news_data_source.g.dart b/lib/features/news/data/news_data_source.g.dart index 3d2a12c7..11587dc2 100644 --- a/lib/features/news/data/news_data_source.g.dart +++ b/lib/features/news/data/news_data_source.g.dart @@ -1,6 +1,6 @@ // GENERATED CODE - DO NOT MODIFY BY HAND -// ignore_for_file: type=lint +// ignore_for_file: type=lint, duplicate_ignore part of 'news_data_source.dart'; @@ -23,4 +23,5 @@ final newsDataSourceProvider = Provider.internal( ); typedef NewsDataSourceRef = ProviderRef; -// ignore_for_file: unnecessary_raw_strings, subtype_of_sealed_class, invalid_use_of_internal_member, do_not_use_environment, prefer_const_constructors, public_member_api_docs, avoid_private_typedef_functions +// ignore_for_file: type=lint +// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member diff --git a/lib/features/news/data/news_provider.g.dart b/lib/features/news/data/news_provider.g.dart index f890fa7c..acf8e484 100644 --- a/lib/features/news/data/news_provider.g.dart +++ b/lib/features/news/data/news_provider.g.dart @@ -1,6 +1,6 @@ // GENERATED CODE - DO NOT MODIFY BY HAND -// ignore_for_file: type=lint +// ignore_for_file: type=lint, duplicate_ignore part of 'news_provider.dart'; @@ -38,4 +38,5 @@ final currentNewsProvider = AutoDisposeFutureProvider>.internal( ); typedef CurrentNewsRef = AutoDisposeFutureProviderRef>; -// ignore_for_file: unnecessary_raw_strings, subtype_of_sealed_class, invalid_use_of_internal_member, do_not_use_environment, prefer_const_constructors, public_member_api_docs, avoid_private_typedef_functions +// ignore_for_file: type=lint +// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member diff --git a/lib/features/staff/data/staff.g.dart b/lib/features/staff/data/staff.g.dart index 4f1bc9d5..90407d89 100644 --- a/lib/features/staff/data/staff.g.dart +++ b/lib/features/staff/data/staff.g.dart @@ -1,6 +1,6 @@ // GENERATED CODE - DO NOT MODIFY BY HAND -// ignore_for_file: type=lint +// ignore_for_file: type=lint, duplicate_ignore part of 'staff.dart'; diff --git a/lib/features/staff/data/staff_data_source.g.dart b/lib/features/staff/data/staff_data_source.g.dart index 3adf75fd..a2678cbe 100644 --- a/lib/features/staff/data/staff_data_source.g.dart +++ b/lib/features/staff/data/staff_data_source.g.dart @@ -1,6 +1,6 @@ // GENERATED CODE - DO NOT MODIFY BY HAND -// ignore_for_file: type=lint +// ignore_for_file: type=lint, duplicate_ignore part of 'staff_data_source.dart'; @@ -23,4 +23,5 @@ final staffDataSourceProvider = Provider.internal( ); typedef StaffDataSourceRef = ProviderRef; -// ignore_for_file: unnecessary_raw_strings, subtype_of_sealed_class, invalid_use_of_internal_member, do_not_use_environment, prefer_const_constructors, public_member_api_docs, avoid_private_typedef_functions +// ignore_for_file: type=lint +// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member diff --git a/lib/features/staff/data/staff_provider.g.dart b/lib/features/staff/data/staff_provider.g.dart index b5983ef6..255157fe 100644 --- a/lib/features/staff/data/staff_provider.g.dart +++ b/lib/features/staff/data/staff_provider.g.dart @@ -1,6 +1,6 @@ // GENERATED CODE - DO NOT MODIFY BY HAND -// ignore_for_file: type=lint +// ignore_for_file: type=lint, duplicate_ignore part of 'staff_provider.dart'; @@ -36,4 +36,5 @@ final sortedStaffsProvider = AutoDisposeFutureProvider>.internal( ); typedef SortedStaffsRef = AutoDisposeFutureProviderRef>; -// ignore_for_file: unnecessary_raw_strings, subtype_of_sealed_class, invalid_use_of_internal_member, do_not_use_environment, prefer_const_constructors, public_member_api_docs, avoid_private_typedef_functions +// ignore_for_file: type=lint +// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member diff --git a/lib/features/staff/ui/staff_item.dart b/lib/features/staff/ui/staff_item.dart index d508d2cc..4ede8d70 100644 --- a/lib/features/staff/ui/staff_item.dart +++ b/lib/features/staff/ui/staff_item.dart @@ -1,9 +1,9 @@ +import 'package:confwebsite2023/core/components/profile_image.dart'; import 'package:confwebsite2023/core/foundation/iterable_ex.dart'; import 'package:confwebsite2023/core/theme.dart'; import 'package:confwebsite2023/features/staff/data/staff.dart'; import 'package:confwebsite2023/features/staff/ui/sns_icon.dart'; import 'package:flutter/material.dart'; -import 'package:transparent_image/transparent_image.dart'; import 'package:url_launcher/link.dart'; /// ! StaffItemのレイアウト変更時は、`features/staff/ui/staff_table.dart`の @@ -19,23 +19,9 @@ class StaffItem extends StatelessWidget { @override Widget build(BuildContext context) { final theme = Theme.of(context); - final icon = SizedBox( - height: 120, - width: 120, - child: FittedBox( - child: ClipOval( - child: FadeInImage( - fit: BoxFit.cover, - image: NetworkImage(staff.image.src), - placeholder: MemoryImage(kTransparentImage), - imageErrorBuilder: (_, __, ___) => const FittedBox( - child: Icon( - Icons.error, - ), - ), - ), - ), - ), + final icon = ProfileImage( + imageUrl: staff.image.src, + size: 120, ); // IconButtonでは Material Designに基づいて 押しやすいサイズになっているが // ここでは ボタンの押しやすさより 1行に収めることを優先する diff --git a/pubspec.lock b/pubspec.lock index a1414eb8..c64fd2cf 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -85,10 +85,10 @@ packages: dependency: transitive description: name: build_resolvers - sha256: a7417cc44d9edb3f2c8760000270c99dba8c72ff66d0146772b8326565780745 + sha256: d912852cce27c9e80a93603db721c267716894462e7033165178b91138587972 url: "https://pub.dev" source: hosted - version: "2.3.1" + version: "2.3.2" build_runner: dependency: "direct dev" description: @@ -298,18 +298,18 @@ packages: dependency: transitive description: name: flutter_gen_core - sha256: e8637dd6a59860f89e5e71be0a27101ec32dad1a0ed7fd879fd23b6e91d5004d + sha256: "8b4ff1d45d125e576e26ea99d15e0419bb3c45b53696e022880866b78bb6b830" url: "https://pub.dev" source: hosted - version: "5.3.1" + version: "5.3.2" flutter_gen_runner: dependency: "direct dev" description: name: flutter_gen_runner - sha256: "7de1bf4fc0439be0fef3178b6423d5c7f1f9f3a38a7c6fafe75d7f70ff4856d7" + sha256: fd197f8c657e79313d53d3934de602ebe604ba722a84c88ae3a43cd90428c67a url: "https://pub.dev" source: hosted - version: "5.3.1" + version: "5.3.2" flutter_hooks: dependency: "direct main" description: @@ -327,10 +327,10 @@ packages: dependency: transitive description: name: flutter_riverpod - sha256: b04d4e9435a563673746ccb328d22018c6c9496bb547e11dd56c1b0cc9829fe5 + sha256: "1bd39b04f1bcd217a969589777ca6bd642d116e3e5de65c3e6a8e8bdd8b178ec" url: "https://pub.dev" source: hosted - version: "2.3.10" + version: "2.4.0" flutter_svg: dependency: "direct main" description: @@ -401,10 +401,10 @@ packages: dependency: "direct main" description: name: hooks_riverpod - sha256: "04a8a526db4c04139f6e5d318ef5079832daa1327a485ad391faf1b6bb203960" + sha256: ad7b877c3687e38764633d221a1f65491bc7a540e724101e9a404a84db2a4276 url: "https://pub.dev" source: hosted - version: "2.3.10" + version: "2.4.0" hotreloader: dependency: transitive description: @@ -641,10 +641,10 @@ packages: dependency: transitive description: name: riverpod - sha256: "6c0a2c30c04206ac05494bcccd8148b76866e1a9248a5a8c84ca7b16fbcb3f6a" + sha256: a600120d6f213a9922860eea1abc32597436edd5b2c4e73b91410f8c2af67d22 url: "https://pub.dev" source: hosted - version: "2.3.10" + version: "2.4.0" riverpod_analyzer_utils: dependency: transitive description: @@ -657,10 +657,10 @@ packages: dependency: "direct main" description: name: riverpod_annotation - sha256: fefc51f8888839a597abe3c813c764404c85c0100a0676d242f358cc92bf5e23 + sha256: "6294fe7e7d1875f32bdf04c8fce7620e718070273703097847df8f3bf16995ea" url: "https://pub.dev" source: hosted - version: "2.1.4" + version: "2.1.5" riverpod_generator: dependency: "direct dev" description: @@ -958,10 +958,10 @@ packages: dependency: transitive description: name: win32 - sha256: "9e82a402b7f3d518fb9c02d0e9ae45952df31b9bf34d77baf19da2de03fc2aaa" + sha256: c97defd418eef4ec88c0d1652cdce84b9f7b63dd7198e266d06ac1710d527067 url: "https://pub.dev" source: hosted - version: "5.0.7" + version: "5.0.8" xdg_directories: dependency: transitive description: