Compare commits

...

2 Commits

Author SHA1 Message Date
1e5af07691 improve UX. (#110) 2023-01-25 21:47:05 -08:00
ecf8c902dc bump flutter and linter version. (#108) 2023-01-25 12:33:06 -08:00
41 changed files with 671 additions and 468 deletions

View File

@ -12,12 +12,12 @@ jobs:
runs-on: ubuntu-latest
timeout-minutes: 30
env:
FLUTTER_VERSION: "3.3.10"
FLUTTER_VERSION: "3.7.0"
steps:
- uses: actions/checkout@v2
- uses: subosito/flutter-action@v2
with:
flutter-version: '3.3.10'
flutter-version: '3.7.0'
channel: 'stable'
- run: flutter pub get
- run: flutter format --set-exit-if-changed .

View File

@ -31,7 +31,7 @@ jobs:
uses: subosito/flutter-action@v2
with:
cache: true
flutter-version: 3.3.10
flutter-version: 3.7.0
- run: flutter pub get
- run: flutter format --set-exit-if-changed .
- run: flutter analyze

View File

@ -1,4 +1,4 @@
include: package:very_good_analysis/analysis_options.2.4.0.yaml
include: package:very_good_analysis/analysis_options.3.1.0.yaml
linter:
rules:
parameter_assignments: false

View File

@ -1,4 +1,4 @@
include: package:very_good_analysis/analysis_options.2.4.0.yaml
include: package:very_good_analysis/analysis_options.3.1.0.yaml
linter:
rules:
parameter_assignments: false

View File

@ -12,7 +12,7 @@ PODS:
- OrderedSet (~> 5.0)
- flutter_local_notifications (0.0.1):
- Flutter
- flutter_secure_storage (3.3.1):
- flutter_secure_storage (6.0.0):
- Flutter
- flutter_siri_suggestions (0.0.1):
- Flutter
@ -24,6 +24,9 @@ PODS:
- OrderedSet (5.0.0)
- package_info_plus (0.4.5):
- Flutter
- path_provider_foundation (0.0.1):
- Flutter
- FlutterMacOS
- path_provider_ios (0.0.1):
- Flutter
- ReachabilitySwift (5.0.0)
@ -31,6 +34,9 @@ PODS:
- Flutter
- share_plus (0.0.1):
- Flutter
- shared_preferences_foundation (0.0.1):
- Flutter
- FlutterMacOS
- shared_preferences_ios (0.0.1):
- Flutter
- sqflite (0.0.2):
@ -56,9 +62,11 @@ DEPENDENCIES:
- flutter_siri_suggestions (from `.symlinks/plugins/flutter_siri_suggestions/ios`)
- integration_test (from `.symlinks/plugins/integration_test/ios`)
- package_info_plus (from `.symlinks/plugins/package_info_plus/ios`)
- path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/ios`)
- path_provider_ios (from `.symlinks/plugins/path_provider_ios/ios`)
- receive_sharing_intent (from `.symlinks/plugins/receive_sharing_intent/ios`)
- share_plus (from `.symlinks/plugins/share_plus/ios`)
- shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/ios`)
- shared_preferences_ios (from `.symlinks/plugins/shared_preferences_ios/ios`)
- sqflite (from `.symlinks/plugins/sqflite/ios`)
- synced_shared_preferences (from `.symlinks/plugins/synced_shared_preferences/ios`)
@ -90,12 +98,16 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/integration_test/ios"
package_info_plus:
:path: ".symlinks/plugins/package_info_plus/ios"
path_provider_foundation:
:path: ".symlinks/plugins/path_provider_foundation/ios"
path_provider_ios:
:path: ".symlinks/plugins/path_provider_ios/ios"
receive_sharing_intent:
:path: ".symlinks/plugins/receive_sharing_intent/ios"
share_plus:
:path: ".symlinks/plugins/share_plus/ios"
shared_preferences_foundation:
:path: ".symlinks/plugins/shared_preferences_foundation/ios"
shared_preferences_ios:
:path: ".symlinks/plugins/shared_preferences_ios/ios"
sqflite:
@ -116,20 +128,22 @@ SPEC CHECKSUMS:
Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854
flutter_inappwebview: bfd58618f49dc62f2676de690fc6dcda1d6c3721
flutter_local_notifications: 0c0b1ae97e741e1521e4c1629a459d04b9aec743
flutter_secure_storage: 7953c38a04c3fdbb00571bcd87d8e3b5ceb9daec
flutter_secure_storage: 23fc622d89d073675f2eaa109381aefbcf5a49be
flutter_siri_suggestions: 226fb7ef33d25d3fe0d4aa2a8bcf4b72730c466f
FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a
integration_test: a1e7d09bd98eca2fc37aefd79d4f41ad37bdbbe5
OrderedSet: aaeb196f7fef5a9edf55d89760da9176ad40b93c
package_info_plus: 6c92f08e1f853dc01228d6f553146438dafcd14e
path_provider_foundation: 37748e03f12783f9de2cb2c4eadfaa25fe6d4852
path_provider_ios: 14f3d2fd28c4fdb42f44e0f751d12861c43cee02
ReachabilitySwift: 985039c6f7b23a1da463388634119492ff86c825
receive_sharing_intent: c0d87310754e74c0f9542947e7cbdf3a0335a3b1
share_plus: 056a1e8ac890df3e33cb503afffaf1e9b4fbae68
shared_preferences_foundation: 297b3ebca31b34ec92be11acd7fb0ba932c822ca
shared_preferences_ios: 548a61f8053b9b8a49ac19c1ffbc8b92c50d68ad
sqflite: 6d358c025f5b867b29ed92fc697fd34924e11904
synced_shared_preferences: f722742b06d65c7315b8e9f56b794c9fbd5597f7
url_launcher_ios: 839c58cdb4279282219f5e248c3321761ff3c4de
url_launcher_ios: ae1517e5e344f5544fb090b079e11f399dfbe4d2
wakelock: d0fc7c864128eac40eba1617cb5264d9c940b46f
webview_flutter_wkwebview: b7e70ef1ddded7e69c796c7390ee74180182971f
workmanager: 0afdcf5628bbde6924c21af7836fed07b42e30e6

View File

@ -3,7 +3,7 @@
archiveVersion = 1;
classes = {
};
objectVersion = 51;
objectVersion = 54;
objects = {
/* Begin PBXBuildFile section */
@ -360,6 +360,7 @@
/* Begin PBXShellScriptBuildPhase section */
3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
isa = PBXShellScriptBuildPhase;
alwaysOutOfDate = 1;
buildActionMask = 2147483647;
files = (
);
@ -413,6 +414,7 @@
};
9740EEB61CF901F6004384FC /* Run Script */ = {
isa = PBXShellScriptBuildPhase;
alwaysOutOfDate = 1;
buildActionMask = 2147483647;
files = (
);

View File

@ -74,5 +74,7 @@
</array>
<key>ITSAppUsesNonExemptEncryption</key>
<false/>
<key>UIApplicationSupportsIndirectInputEvents</key>
<true/>
</dict>
</plist>

View File

@ -84,6 +84,9 @@ class StoriesBloc extends Bloc<StoriesEvent, StoriesState> {
const StoriesState.init().copyWith(
offlineReading: hasCachedStories,
currentPageSize: pageSize,
downloadStatus: state.downloadStatus,
storiesDownloaded: state.storiesDownloaded,
storiesToBeDownloaded: state.storiesToBeDownloaded,
),
);
for (final StoryType type in types) {
@ -374,7 +377,6 @@ class StoriesBloc extends Bloc<StoriesEvent, StoriesState> {
StoriesPageSizeChanged event,
Emitter<StoriesState> emit,
) async {
emit(const StoriesState.init());
add(StoriesInitialize());
}

View File

@ -22,12 +22,12 @@ extension ContextExtension on BuildContext {
static double _screenWidth = 0;
static double _storyTileHeight = 0;
static int _storyTileMaxLines = 4;
static const double _screenWidthLowerBound = 430,
_screenWidthUpperBound = 850,
_picHeightLowerBound = 110,
_picHeightUpperBound = 128,
_smallPicHeight = 100,
_picHeightFactor = 0.3;
static const double _screenWidthLowerBound = 430;
static const double _screenWidthUpperBound = 850;
static const double _picHeightLowerBound = 110;
static const double _picHeightUpperBound = 128;
static const double _smallPicHeight = 100;
static const double _picHeightFactor = 0.3;
double get storyTileHeight {
final double screenWidth =

View File

@ -19,7 +19,7 @@ extension StateExtension on State {
? SnackBarAction(
label: label,
onPressed: action,
textColor: Theme.of(context).textTheme.bodyText1?.color,
textColor: Theme.of(context).textTheme.bodyLarge?.color,
)
: null,
behavior: SnackBarBehavior.floating,

View File

@ -1,6 +1,5 @@
import 'dart:async';
import 'package:dio/dio.dart';
import 'package:hacki/config/locator.dart';
import 'package:hacki/models/models.dart';
import 'package:hacki/repositories/postable_repository.dart';
@ -9,13 +8,12 @@ import 'package:logger/logger.dart';
class AuthRepository extends PostableRepository {
AuthRepository({
Dio? dio,
super.dio,
PreferenceRepository? preferenceRepository,
Logger? logger,
}) : _preferenceRepository =
preferenceRepository ?? locator.get<PreferenceRepository>(),
_logger = logger ?? locator.get<Logger>(),
super(dio: dio);
_logger = logger ?? locator.get<Logger>();
final PreferenceRepository _preferenceRepository;
final Logger _logger;

View File

@ -8,10 +8,9 @@ import 'package:hacki/repositories/preference_repository.dart';
import 'package:hacki/utils/utils.dart';
class PostRepository extends PostableRepository {
PostRepository({Dio? dio, PreferenceRepository? storageRepository})
PostRepository({super.dio, PreferenceRepository? storageRepository})
: _preferenceRepository =
storageRepository ?? locator.get<PreferenceRepository>(),
super(dio: dio);
storageRepository ?? locator.get<PreferenceRepository>();
final PreferenceRepository _preferenceRepository;

View File

@ -4,7 +4,7 @@ import 'dart:io';
import 'package:badges/badges.dart';
import 'package:feature_discovery/feature_discovery.dart';
import 'package:flutter/material.dart';
import 'package:flutter/material.dart' hide Badge;
import 'package:flutter/scheduler.dart';
import 'package:flutter/services.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
@ -182,7 +182,7 @@ class _HomeScreenState extends State<HomeScreen>
),
],
),
child: Container(
child: ColoredBox(
color: Palette.orangeAccent.withOpacity(0.2),
child: StoryTile(
key: ValueKey<String>('${story.id}-PinnedStoryTile'),
@ -508,9 +508,8 @@ class _HomeScreenState extends State<HomeScreen>
class _MobileHomeScreen extends StatelessWidget {
const _MobileHomeScreen({
Key? key,
required this.homeScreen,
}) : super(key: key);
});
final Widget homeScreen;
@ -534,9 +533,8 @@ class _MobileHomeScreen extends StatelessWidget {
class _TabletHomeScreen extends StatelessWidget {
const _TabletHomeScreen({
Key? key,
required this.homeScreen,
}) : super(key: key);
});
final Widget homeScreen;
@ -561,7 +559,7 @@ class _TabletHomeScreen extends StatelessWidget {
left: Dimens.zero,
top: Dimens.zero,
bottom: Dimens.zero,
width: state.expanded ? Dimens.zero : homeScreenWidth,
width: homeScreenWidth,
duration: const Duration(milliseconds: 300),
curve: Curves.elasticOut,
child: homeScreen,
@ -592,7 +590,7 @@ class _TabletHomeScreen extends StatelessWidget {
}
class _TabletStoryView extends StatelessWidget {
const _TabletStoryView({Key? key}) : super(key: key);
const _TabletStoryView();
@override
Widget build(BuildContext context) {
@ -605,7 +603,7 @@ class _TabletStoryView extends StatelessWidget {
}
return Material(
child: Container(
child: ColoredBox(
color: Theme.of(context).canvasColor,
child: const Center(
child: Text('Tap on story tile to view comments.'),

View File

@ -7,10 +7,10 @@ import 'package:hacki/styles/styles.dart';
class CustomAppBar extends AppBar {
CustomAppBar({
Key? key,
super.key,
required ScrollController scrollController,
required Item item,
required Color backgroundColor,
required Color super.backgroundColor,
required Future<bool> Function() onBackgroundTap,
required Future<bool> Function() onDismiss,
required VoidCallback onFontSizeTap,
@ -19,8 +19,6 @@ class CustomAppBar extends AppBar {
VoidCallback? onZoomTap,
bool? expanded,
}) : super(
key: key,
backgroundColor: backgroundColor,
elevation: Dimens.zero,
actions: <Widget>[
if (splitViewEnabled) ...<Widget>[

View File

@ -9,15 +9,15 @@ import 'package:hacki/utils/utils.dart';
class LoginDialog extends StatelessWidget {
const LoginDialog({
Key? key,
super.key,
required this.usernameController,
required this.passwordController,
required this.showSnackBar,
}) : super(key: key);
});
final TextEditingController usernameController;
final TextEditingController passwordController;
final Function({
final void Function({
required String content,
VoidCallback? action,
String? label,

View File

@ -17,7 +17,7 @@ import 'package:pull_to_refresh/pull_to_refresh.dart';
class MainView extends StatelessWidget {
const MainView({
Key? key,
super.key,
required this.scrollController,
required this.refreshController,
required this.commentEditingController,
@ -29,7 +29,7 @@ class MainView extends StatelessWidget {
required this.onStoryLinkTapped,
required this.onLoginTapped,
required this.onRightMoreTapped,
}) : super(key: key);
});
final ScrollController scrollController;
final RefreshController refreshController;
@ -38,11 +38,14 @@ class MainView extends StatelessWidget {
final FocusNode focusNode;
final double topPadding;
final bool splitViewEnabled;
final Function(Item item, Rect? rect) onMoreTapped;
final void Function(Item item, Rect? rect) onMoreTapped;
final ValueChanged<String> onStoryLinkTapped;
final VoidCallback onLoginTapped;
final ValueChanged<Comment> onRightMoreTapped;
static const int _loadingIndicatorOpacityAnimationDuration = 300;
static const double _trailingBoxHeight = 240;
@override
Widget build(BuildContext context) {
return Stack(
@ -130,7 +133,7 @@ class MainView extends StatelessWidget {
state.comments.isNotEmpty) ||
state.onlyShowTargetComment) {
return SizedBox(
height: 240,
height: _trailingBoxHeight,
child: Center(
child: Text(Constants.happyFaces.pickRandomly()!),
),
@ -194,8 +197,13 @@ class MainView extends StatelessWidget {
buildWhen: (CommentsState prev, CommentsState current) =>
prev.status != current.status,
builder: (BuildContext context, CommentsState state) {
return Visibility(
visible: state.status == CommentsStatus.loading,
return AnimatedOpacity(
opacity: state.status == CommentsStatus.loading
? NumSwitch.on
: NumSwitch.off,
duration: const Duration(
milliseconds: _loadingIndicatorOpacityAnimationDuration,
),
child: const LinearProgressIndicator(),
);
},
@ -208,7 +216,6 @@ class MainView extends StatelessWidget {
class _ParentItemSection extends StatelessWidget {
const _ParentItemSection({
Key? key,
required this.scrollController,
required this.refreshController,
required this.commentEditingController,
@ -221,7 +228,7 @@ class _ParentItemSection extends StatelessWidget {
required this.onStoryLinkTapped,
required this.onLoginTapped,
required this.onRightMoreTapped,
}) : super(key: key);
});
final ScrollController scrollController;
final RefreshController refreshController;
@ -231,7 +238,7 @@ class _ParentItemSection extends StatelessWidget {
final FocusNode focusNode;
final double topPadding;
final bool splitViewEnabled;
final Function(Item item, Rect? rect) onMoreTapped;
final void Function(Item item, Rect? rect) onMoreTapped;
final ValueChanged<String> onStoryLinkTapped;
final VoidCallback onLoginTapped;
final ValueChanged<Comment> onRightMoreTapped;
@ -342,7 +349,7 @@ class _ParentItemSection extends StatelessWidget {
prefState.fontSize.fontSize,
color: Theme.of(context)
.textTheme
.bodyText1
.bodyLarge
?.color,
),
children: <TextSpan>[

View File

@ -12,17 +12,17 @@ import 'package:hacki/utils/utils.dart';
class MorePopupMenu extends StatelessWidget {
const MorePopupMenu({
Key? key,
super.key,
required this.item,
required this.isBlocked,
required this.showSnackBar,
required this.onStoryLinkTapped,
required this.onLoginTapped,
}) : super(key: key);
});
final Item item;
final bool isBlocked;
final Function({
final void Function({
required String content,
VoidCallback? action,
String? label,

View File

@ -168,7 +168,7 @@ class PollView extends StatelessWidget {
? SnackBarAction(
label: label,
onPressed: action,
textColor: Theme.of(context).textTheme.bodyText1?.color,
textColor: Theme.of(context).textTheme.bodyLarge?.color,
)
: null,
behavior: SnackBarBehavior.floating,

View File

@ -111,7 +111,8 @@ class _ReplyBoxState extends State<ReplyBox> {
...<Widget>[
if (replyingTo != null)
AnimatedOpacity(
opacity: expanded ? 1 : 0,
opacity:
expanded ? NumSwitch.on : NumSwitch.off,
duration: const Duration(milliseconds: 300),
child: IconButton(
key: const Key('quote'),

View File

@ -9,19 +9,19 @@ import 'package:responsive_builder/responsive_builder.dart';
class TimeMachineDialog extends StatelessWidget {
const TimeMachineDialog({
Key? key,
super.key,
required this.comment,
required this.size,
required this.deviceType,
required this.widthFactor,
required this.onStoryLinkTapped,
}) : super(key: key);
});
final Comment comment;
final Size size;
final DeviceScreenType deviceType;
final double widthFactor;
final Function(String) onStoryLinkTapped;
final void Function(String) onStoryLinkTapped;
@override
Widget build(BuildContext context) {

View File

@ -650,89 +650,93 @@ class _ProfileScreenState extends State<ProfileScreen>
final PackageInfo packageInfo = await PackageInfo.fromPlatform();
final String version = packageInfo.version;
showAboutDialog(
context: context,
applicationName: 'Hacki',
applicationVersion: 'v$version',
applicationIcon: ClipRRect(
borderRadius: const BorderRadius.all(
Radius.circular(
Dimens.pt12,
if (mounted) {
showAboutDialog(
context: context,
applicationName: 'Hacki',
applicationVersion: 'v$version',
applicationIcon: ClipRRect(
borderRadius: const BorderRadius.all(
Radius.circular(
Dimens.pt12,
),
),
child: Image.asset(
Constants.hackiIconPath,
height: Dimens.pt50,
width: Dimens.pt50,
),
),
child: Image.asset(
Constants.hackiIconPath,
height: Dimens.pt50,
width: Dimens.pt50,
),
),
children: <Widget>[
ElevatedButton(
onPressed: () => LinkUtil.launch(
Constants.portfolioLink,
children: <Widget>[
ElevatedButton(
onPressed: () => LinkUtil.launch(
Constants.portfolioLink,
),
child: Row(
children: const <Widget>[
Icon(
FontAwesomeIcons.addressCard,
),
SizedBox(
width: Dimens.pt12,
),
Text('Developer'),
],
),
),
child: Row(
children: const <Widget>[
Icon(
FontAwesomeIcons.addressCard,
),
SizedBox(
width: Dimens.pt12,
),
Text('Developer'),
],
ElevatedButton(
onPressed: () => LinkUtil.launch(
Constants.githubLink,
),
child: Row(
children: const <Widget>[
Icon(
FontAwesomeIcons.github,
),
SizedBox(
width: Dimens.pt12,
),
Text('Source code'),
],
),
),
),
ElevatedButton(
onPressed: () => LinkUtil.launch(
Constants.githubLink,
ElevatedButton(
onPressed: () => LinkUtil.launch(
Platform.isIOS
? Constants.appStoreLink
: Constants.googlePlayLink,
),
child: Row(
children: const <Widget>[
Icon(
Icons.thumb_up,
),
SizedBox(
width: Dimens.pt12,
),
Text('Like the app?'),
],
),
),
child: Row(
children: const <Widget>[
Icon(
FontAwesomeIcons.github,
),
SizedBox(
width: Dimens.pt12,
),
Text('Source code'),
],
ElevatedButton(
onPressed: () => LinkUtil.launch(
Constants.sponsorLink,
),
child: Row(
children: const <Widget>[
Icon(
FeatherIcons.coffee,
),
SizedBox(
width: Dimens.pt12,
),
Text('Buy me a coffee'),
],
),
),
),
ElevatedButton(
onPressed: () => LinkUtil.launch(
Platform.isIOS ? Constants.appStoreLink : Constants.googlePlayLink,
),
child: Row(
children: const <Widget>[
Icon(
Icons.thumb_up,
),
SizedBox(
width: Dimens.pt12,
),
Text('Like the app?'),
],
),
),
ElevatedButton(
onPressed: () => LinkUtil.launch(
Constants.sponsorLink,
),
child: Row(
children: const <Widget>[
Icon(
FeatherIcons.coffee,
),
SizedBox(
width: Dimens.pt12,
),
Text('Buy me a coffee'),
],
),
),
],
);
],
);
}
}
void onCommentTapped(Comment comment, {VoidCallback? then}) {

View File

@ -22,7 +22,7 @@ class InboxView extends StatelessWidget {
final RefreshController refreshController;
final List<Comment> comments;
final List<int> unreadCommentsIds;
final Function(Comment) onCommentTapped;
final void Function(Comment) onCommentTapped;
final VoidCallback onMarkAllAsReadTapped;
final VoidCallback onLoadMore;
final VoidCallback onRefresh;

View File

@ -179,8 +179,7 @@ class _SearchScreenState extends State<SearchScreen> {
),
],
)
.expand((List<Widget> e) => e)
.toList(),
.expand((List<Widget> e) => e),
const SizedBox(
height: Dimens.pt40,
),

View File

@ -1,7 +1,7 @@
import 'package:flutter/material.dart';
import 'package:hacki/screens/widgets/widgets.dart';
typedef DateRangeCallback = Function(DateTime, DateTime);
typedef DateRangeCallback = void Function(DateTime, DateTime);
enum CustomDateTimeRange {
pastDay(Duration(days: 1), label: 'past day'),
@ -17,10 +17,10 @@ enum CustomDateTimeRange {
class CustomRangeFilterChip extends StatelessWidget {
const CustomRangeFilterChip({
Key? key,
super.key,
required this.range,
required this.onTap,
}) : super(key: key);
});
final CustomDateTimeRange range;
final DateRangeCallback onTap;

View File

@ -5,14 +5,14 @@ import 'package:intl/intl.dart';
class DateTimeRangeFilterChip extends StatelessWidget {
const DateTimeRangeFilterChip({
Key? key,
super.key,
required this.filter,
required this.onDateTimeRangeUpdated,
required this.onDateTimeRangeRemoved,
}) : super(key: key);
});
final DateTimeRangeFilter? filter;
final Function(DateTime, DateTime) onDateTimeRangeUpdated;
final void Function(DateTime, DateTime) onDateTimeRangeUpdated;
final VoidCallback onDateTimeRangeRemoved;
static final DateFormat _dateTimeFormatter = DateFormat.yMMMd();

View File

@ -4,9 +4,9 @@ import 'package:hacki/screens/widgets/widgets.dart';
class PostedByFilterChip extends StatelessWidget {
const PostedByFilterChip({
Key? key,
super.key,
required this.filter,
}) : super(key: key);
});
final PostedByFilter? filter;

View File

@ -17,7 +17,7 @@ class BlocBuilder3<
BlocC extends StateStreamable<BlocCState>,
BlocCState> extends StatelessWidget {
const BlocBuilder3({
Key? key,
super.key,
required this.builder,
this.blocA,
this.blocB,
@ -25,7 +25,7 @@ class BlocBuilder3<
this.buildWhenA,
this.buildWhenB,
this.buildWhenC,
}) : super(key: key);
});
final BlocWidgetBuilder3<BlocAState, BlocBState, BlocCState> builder;

View File

@ -33,11 +33,11 @@ class CommentTile extends StatelessWidget {
final Comment comment;
final int level;
final bool actionable;
final Function(Comment)? onReplyTapped;
final Function(Comment, Rect?)? onMoreTapped;
final Function(Comment)? onEditTapped;
final Function(Comment)? onRightMoreTapped;
final Function(String) onStoryLinkTapped;
final void Function(Comment)? onReplyTapped;
final void Function(Comment, Rect?)? onMoreTapped;
final void Function(Comment)? onEditTapped;
final void Function(Comment)? onRightMoreTapped;
final void Function(String) onStoryLinkTapped;
final FetchMode fetchMode;
@override

View File

@ -57,7 +57,7 @@ class ItemsListView<T extends Item> extends StatelessWidget {
final VoidCallback? onRefresh;
final VoidCallback? onLoadMore;
final ValueChanged<Story>? onPinned;
final Function(T) onTap;
final void Function(T) onTap;
@override
Widget build(BuildContext context) {
@ -249,11 +249,10 @@ class ItemsListView<T extends Item> extends StatelessWidget {
class _CommentTile extends StatelessWidget {
const _CommentTile({
Key? key,
required this.comment,
required this.onTap,
this.fontSize = 16,
}) : super(key: key);
});
final Comment comment;
final VoidCallback onTap;

View File

@ -113,7 +113,8 @@ class LinkPreview extends StatefulWidget {
class _LinkPreviewState extends State<LinkPreview> {
InfoBase? _info;
String? _errorTitle, _errorBody;
String? _errorTitle;
String? _errorBody;
bool _loading = false;
@override
@ -158,7 +159,7 @@ class _LinkPreviewState extends State<LinkPreview> {
}
Widget _buildLinkContainer(
double _height, {
double height, {
String? title = '',
String? desc = '',
String? imageUri = '',
@ -177,7 +178,7 @@ class _LinkPreviewState extends State<LinkPreview> {
const BoxShadow(blurRadius: 3, color: Palette.grey),
],
),
height: _height,
height: height,
child: LinkView(
key: widget.key ?? Key(widget.link),
metadata: widget.story.simpleMetadata,

View File

@ -37,7 +37,7 @@ class LinkView extends StatelessWidget {
final String description;
final String? imageUri;
final String? imagePath;
final Function(String) onTap;
final void Function(String) onTap;
final TextStyle? titleTextStyle;
final TextStyle? bodyTextStyle;
final bool showMultiMedia;
@ -76,13 +76,13 @@ class LinkView extends StatelessWidget {
final double layoutWidth = constraints.biggest.width;
final double layoutHeight = constraints.biggest.height;
final TextStyle _titleFontSize = titleTextStyle ??
final TextStyle titleFontSize = titleTextStyle ??
TextStyle(
fontSize: computeTitleFontSize(layoutWidth),
color: Palette.black,
fontWeight: FontWeight.bold,
);
final TextStyle _bodyFontSize = bodyTextStyle ??
final TextStyle bodyFontSize = bodyTextStyle ??
TextStyle(
fontSize: computeTitleFontSize(layoutWidth) - 1,
color: Palette.grey,
@ -131,11 +131,11 @@ class LinkView extends StatelessWidget {
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
_buildTitleContainer(
_titleFontSize,
titleFontSize,
computeTitleLines(layoutHeight),
),
_buildBodyContainer(
_bodyFontSize,
bodyFontSize,
computeBodyLines(layoutHeight),
)
],
@ -149,7 +149,7 @@ class LinkView extends StatelessWidget {
);
}
Widget _buildTitleContainer(TextStyle _titleTS, int _maxLines) {
Widget _buildTitleContainer(TextStyle titleTS, int maxLines) {
final bool showUrl = this.showUrl && url.isNotEmpty;
return Padding(
padding: const EdgeInsets.fromLTRB(4, 2, 3, 0),
@ -159,9 +159,9 @@ class LinkView extends StatelessWidget {
alignment: Alignment.topLeft,
child: Text(
title,
style: _titleTS,
style: titleTS,
overflow: TextOverflow.ellipsis,
maxLines: _maxLines,
maxLines: maxLines,
),
),
if (showUrl)
@ -170,10 +170,10 @@ class LinkView extends StatelessWidget {
child: Text(
'($readableUrl)',
textAlign: TextAlign.left,
style: _titleTS.copyWith(
style: titleTS.copyWith(
color: Palette.grey,
fontSize:
_titleTS.fontSize == null ? 12 : _titleTS.fontSize! - 4,
titleTS.fontSize == null ? 12 : titleTS.fontSize! - 4,
fontWeight: FontWeight.w400,
),
overflow: bodyTextOverflow ?? TextOverflow.ellipsis,
@ -185,7 +185,7 @@ class LinkView extends StatelessWidget {
);
}
Widget _buildBodyContainer(TextStyle _bodyTS, int _maxLines) {
Widget _buildBodyContainer(TextStyle bodyTS, int maxLines) {
return Expanded(
flex: 2,
child: Padding(
@ -198,9 +198,9 @@ class LinkView extends StatelessWidget {
child: Text(
metadata,
textAlign: TextAlign.left,
style: _bodyTS.copyWith(
style: bodyTS.copyWith(
fontSize:
_bodyTS.fontSize == null ? 12 : _bodyTS.fontSize! - 2,
bodyTS.fontSize == null ? 12 : bodyTS.fontSize! - 2,
),
overflow: bodyTextOverflow ?? TextOverflow.ellipsis,
maxLines: 1,
@ -212,9 +212,9 @@ class LinkView extends StatelessWidget {
child: Text(
description,
textAlign: TextAlign.left,
style: _bodyTS,
style: bodyTS,
overflow: bodyTextOverflow ?? TextOverflow.ellipsis,
maxLines: (bodyMaxLines ?? _maxLines) -
maxLines: (bodyMaxLines ?? maxLines) -
(showMetadata ? 1 : 0) -
(showUrl && url.isNotEmpty ? 1 : 0),
),

View File

@ -63,7 +63,7 @@ class WebImageInfo extends InfoBase {
/// Video Information
class WebVideoInfo extends WebImageInfo {
WebVideoInfo({String? image}) : super(image: image);
WebVideoInfo({super.image});
}
/// Web analyzer

View File

@ -6,7 +6,7 @@ import 'package:hacki/styles/styles.dart';
import 'package:hacki/utils/utils.dart';
class OnboardingView extends StatefulWidget {
const OnboardingView({Key? key}) : super(key: key);
const OnboardingView({super.key});
@override
State<OnboardingView> createState() => _OnboardingViewState();
@ -106,10 +106,9 @@ class _OnboardingViewState extends State<OnboardingView> {
class _PageViewChild extends StatelessWidget {
const _PageViewChild({
Key? key,
required this.path,
required this.description,
}) : super(key: key);
});
final String path;
final String description;

View File

@ -56,7 +56,7 @@ class StoryTile extends StatelessWidget {
titleStyle: TextStyle(
color: hasRead
? Palette.grey[500]
: Theme.of(context).textTheme.subtitle1?.color,
: Theme.of(context).textTheme.bodyLarge?.color,
fontWeight: FontWeight.bold,
),
showMetadata: showMetadata,
@ -90,7 +90,7 @@ class StoryTile extends StatelessWidget {
? Palette.grey[500]
: Theme.of(context)
.textTheme
.bodyText1
.bodyLarge
?.color,
fontSize: simpleTileFontSize,
),
@ -137,9 +137,8 @@ class StoryTile extends StatelessWidget {
class _LinkPreviewPlaceholder extends StatelessWidget {
const _LinkPreviewPlaceholder({
Key? key,
required this.height,
}) : super(key: key);
});
final double height;

View File

@ -6,7 +6,6 @@ export 'custom_chip.dart';
export 'custom_circular_progress_indicator.dart';
export 'items_list_view.dart';
export 'link_preview/link_preview.dart';
export 'link_preview/link_preview.dart';
export 'offline_banner.dart';
export 'onboarding_view.dart';
export 'spring_curve.dart';

View File

@ -38,3 +38,8 @@ abstract class TextDimens {
static const double pt26 = 26;
static const double pt36 = 36;
}
abstract class NumSwitch {
static const double on = 1;
static const double off = 0;
}

File diff suppressed because it is too large Load Diff

View File

@ -1,11 +1,11 @@
name: hacki
description: A Hacker News reader.
version: 1.0.2+80
version: 1.0.3+81
publish_to: none
environment:
sdk: ">=2.17.0 <3.0.0"
flutter: "3.3.10"
flutter: "3.7.0"
dependencies:
adaptive_theme: ^3.0.0
@ -73,12 +73,14 @@ dependencies:
dev_dependencies:
bloc_test: ^9.1.0
flutter_driver:
sdk: flutter
flutter_test:
sdk: flutter
integration_test:
sdk: flutter
mocktail: ^0.3.0
very_good_analysis: ^2.4.0
very_good_analysis: ^3.1.0
flutter:
uses-material-design: true

View File

@ -20,8 +20,11 @@ void main() {
final MockStoriesRepository mockStoriesRepository = MockStoriesRepository();
final MockSembastRepository mockSembastRepository = MockSembastRepository();
const int created = 0, delay = 1, karma = 2;
const String about = 'about', id = 'id';
const int created = 0;
const int delay = 1;
const int karma = 2;
const String about = 'about';
const String id = 'id';
const User tUser = User(
about: about,
@ -57,7 +60,8 @@ void main() {
);
group('AuthAppStarted', () {
const String username = 'username', password = 'password';
const String username = 'username';
const String password = 'password';
setUp(() {
when(() => mockAuthRepository.username)
.thenAnswer((_) => Future<String?>.value(username));