Compare commits

..

7 Commits

52 changed files with 675 additions and 376 deletions

View File

@ -9,13 +9,16 @@ on:
jobs: jobs:
releases: releases:
name: Check commit name: Check commit
runs-on: ubuntu-latest runs-on: macos-latest
timeout-minutes: 30 timeout-minutes: 30
steps: steps:
- name: checkout all the submodules - name: checkout all the submodules
uses: actions/checkout@v3 uses: actions/checkout@v3
with: with:
submodules: recursive submodules: recursive
fetch-depth: 0
- run: cd submodules/flutter
- run: git remote set-url origin https://github.com/flutter/flutter.git
- run: submodules/flutter/bin/flutter doctor - run: submodules/flutter/bin/flutter doctor
- run: submodules/flutter/bin/flutter pub get - run: submodules/flutter/bin/flutter pub get
- run: submodules/flutter/bin/dart format --set-exit-if-changed lib test integration_test - run: submodules/flutter/bin/dart format --set-exit-if-changed lib test integration_test

View File

@ -23,6 +23,9 @@ jobs:
uses: actions/checkout@v3 uses: actions/checkout@v3
with: with:
submodules: recursive submodules: recursive
fetch-depth: 0
- run: cd submodules/flutter
- run: git remote set-url origin https://github.com/flutter/flutter.git
- run: submodules/flutter/bin/flutter doctor - run: submodules/flutter/bin/flutter doctor
- run: submodules/flutter/bin/flutter pub get - run: submodules/flutter/bin/flutter pub get
- run: submodules/flutter/bin/dart format --set-exit-if-changed lib test integration_test - run: submodules/flutter/bin/dart format --set-exit-if-changed lib test integration_test

View File

@ -29,6 +29,7 @@ Features:
- Download stories and comments for offline reading. - Download stories and comments for offline reading.
- Pick up where you left off. - Pick up where you left off.
- Synced favorites and pins across devices. (iOS only) - Synced favorites and pins across devices. (iOS only)
- Export or import your favorites.
- Launch from system share sheet. - Launch from system share sheet.
- And more... - And more...

View File

@ -1,121 +0,0 @@
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:in_app_review_platform_interface/method_channel_in_app_review.dart';
import 'package:platform/platform.dart';
void main() {
TestWidgetsFlutterBinding.ensureInitialized();
late MethodChannelInAppReview methodChannelInAppReview;
late List<MethodCall> log = <MethodCall>[];
const MethodChannel channel = MethodChannel('dev.britannio.in_app_review');
setUp(() {
methodChannelInAppReview = MethodChannelInAppReview();
methodChannelInAppReview.channel = channel;
log = <MethodCall>[];
});
tearDown(() {
log.clear();
});
group('isAvailable', () {
test(
'should invoke the isAvailable method channel',
() async {
// ACT
final bool result = await methodChannelInAppReview.isAvailable();
// ASSERT
expect(log, <Matcher>[isMethodCall('isAvailable', arguments: null)]);
expect(result, isTrue);
},
);
});
group('requestReview', () {
test(
'should invoke the requestReview method channel',
() async {
// ACT
await methodChannelInAppReview.requestReview();
// ASSERT
expect(log, <Matcher>[isMethodCall('requestReview', arguments: null)]);
},
);
});
group('openStoreListing', () {
test(
'should invoke the openStoreListing method channel on Android',
() async {
// ARRANGE
methodChannelInAppReview.platform =
FakePlatform(operatingSystem: 'android');
// ACT
await methodChannelInAppReview.openStoreListing();
// ASSERT
expect(
log,
<Matcher>[isMethodCall('openStoreListing', arguments: null)],
);
},
);
test(
'should invoke the openStoreListing method channel on iOS',
() async {
// ARRANGE
methodChannelInAppReview.platform =
FakePlatform(operatingSystem: 'ios');
final String appStoreId = "store_id";
// ACT
await methodChannelInAppReview.openStoreListing(appStoreId: appStoreId);
// ASSERT
expect(log,
<Matcher>[isMethodCall('openStoreListing', arguments: appStoreId)]);
},
);
test(
'should invoke the openStoreListing method channel on MacOS',
() async {
// ARRANGE
methodChannelInAppReview.platform =
FakePlatform(operatingSystem: 'macos');
final String appStoreId = "store_id";
// ACT
await methodChannelInAppReview.openStoreListing(appStoreId: appStoreId);
// ASSERT
expect(log,
<Matcher>[isMethodCall('openStoreListing', arguments: appStoreId)]);
},
);
test(
'should invoke the openStoreListing method channel on Windows',
() async {
// ARRANGE
methodChannelInAppReview.platform =
FakePlatform(operatingSystem: 'windows');
final String microsoftStoreId = 'store_id';
// ACT
await methodChannelInAppReview.openStoreListing(
microsoftStoreId: microsoftStoreId,
);
// ASSERT
expect(log, <Matcher>[
isMethodCall('openStoreListing', arguments: microsoftStoreId)
]);
},
skip:
'The windows uwp implementation still uses the url_launcher package',
);
});
}

View File

@ -27,12 +27,16 @@ PODS:
- Flutter - Flutter
- integration_test (0.0.1): - integration_test (0.0.1):
- Flutter - Flutter
- MTBBarcodeScanner (5.0.11)
- OrderedSet (5.0.0) - OrderedSet (5.0.0)
- package_info_plus (0.4.5): - package_info_plus (0.4.5):
- Flutter - Flutter
- path_provider_foundation (0.0.1): - path_provider_foundation (0.0.1):
- Flutter - Flutter
- FlutterMacOS - FlutterMacOS
- qr_code_scanner (0.2.0):
- Flutter
- MTBBarcodeScanner
- ReachabilitySwift (5.0.0) - ReachabilitySwift (5.0.0)
- receive_sharing_intent (0.0.1): - receive_sharing_intent (0.0.1):
- Flutter - Flutter
@ -68,6 +72,7 @@ DEPENDENCIES:
- integration_test (from `.symlinks/plugins/integration_test/ios`) - integration_test (from `.symlinks/plugins/integration_test/ios`)
- package_info_plus (from `.symlinks/plugins/package_info_plus/ios`) - package_info_plus (from `.symlinks/plugins/package_info_plus/ios`)
- path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`) - path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`)
- qr_code_scanner (from `.symlinks/plugins/qr_code_scanner/ios`)
- receive_sharing_intent (from `.symlinks/plugins/receive_sharing_intent/ios`) - receive_sharing_intent (from `.symlinks/plugins/receive_sharing_intent/ios`)
- share_plus (from `.symlinks/plugins/share_plus/ios`) - share_plus (from `.symlinks/plugins/share_plus/ios`)
- shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`) - shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`)
@ -81,6 +86,7 @@ DEPENDENCIES:
SPEC REPOS: SPEC REPOS:
trunk: trunk:
- FMDB - FMDB
- MTBBarcodeScanner
- OrderedSet - OrderedSet
- ReachabilitySwift - ReachabilitySwift
@ -109,6 +115,8 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/package_info_plus/ios" :path: ".symlinks/plugins/package_info_plus/ios"
path_provider_foundation: path_provider_foundation:
:path: ".symlinks/plugins/path_provider_foundation/darwin" :path: ".symlinks/plugins/path_provider_foundation/darwin"
qr_code_scanner:
:path: ".symlinks/plugins/qr_code_scanner/ios"
receive_sharing_intent: receive_sharing_intent:
:path: ".symlinks/plugins/receive_sharing_intent/ios" :path: ".symlinks/plugins/receive_sharing_intent/ios"
share_plus: share_plus:
@ -140,9 +148,11 @@ SPEC CHECKSUMS:
FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a
in_app_review: 318597b3a06c22bb46dc454d56828c85f444f99d in_app_review: 318597b3a06c22bb46dc454d56828c85f444f99d
integration_test: 13825b8a9334a850581300559b8839134b124670 integration_test: 13825b8a9334a850581300559b8839134b124670
MTBBarcodeScanner: f453b33c4b7dfe545d8c6484ed744d55671788cb
OrderedSet: aaeb196f7fef5a9edf55d89760da9176ad40b93c OrderedSet: aaeb196f7fef5a9edf55d89760da9176ad40b93c
package_info_plus: fd030dabf36271f146f1f3beacd48f564b0f17f7 package_info_plus: fd030dabf36271f146f1f3beacd48f564b0f17f7
path_provider_foundation: eaf5b3e458fc0e5fbb9940fb09980e853fe058b8 path_provider_foundation: eaf5b3e458fc0e5fbb9940fb09980e853fe058b8
qr_code_scanner: bb67d64904c3b9658ada8c402e8b4d406d5d796e
ReachabilitySwift: 985039c6f7b23a1da463388634119492ff86c825 ReachabilitySwift: 985039c6f7b23a1da463388634119492ff86c825
receive_sharing_intent: c0d87310754e74c0f9542947e7cbdf3a0335a3b1 receive_sharing_intent: c0d87310754e74c0f9542947e7cbdf3a0335a3b1
share_plus: 599aa54e4ea31d4b4c0e9c911bcc26c55e791028 share_plus: 599aa54e4ea31d4b4c0e9c911bcc26c55e791028

View File

@ -291,7 +291,7 @@
isa = PBXProject; isa = PBXProject;
attributes = { attributes = {
LastSwiftUpdateCheck = 1330; LastSwiftUpdateCheck = 1330;
LastUpgradeCheck = 1300; LastUpgradeCheck = 1430;
ORGANIZATIONNAME = ""; ORGANIZATIONNAME = "";
TargetAttributes = { TargetAttributes = {
97C146ED1CF9000F007C117D = { 97C146ED1CF9000F007C117D = {

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<Scheme <Scheme
LastUpgradeVersion = "1300" LastUpgradeVersion = "1430"
version = "1.3"> version = "1.3">
<BuildAction <BuildAction
parallelizeBuildables = "YES" parallelizeBuildables = "YES"

View File

@ -76,5 +76,9 @@
<false/> <false/>
<key>UIApplicationSupportsIndirectInputEvents</key> <key>UIApplicationSupportsIndirectInputEvents</key>
<true/> <true/>
<key>NSCameraUsageDescription</key>
<string>This app needs camera access to scan QR codes</string>
<key>io.flutter.embedded_views_preview</key>
<true/>
</dict> </dict>
</plist> </plist>

View File

@ -133,6 +133,8 @@ class StoriesBloc extends Bloc<StoriesEvent, StoriesState> {
StoriesRefresh event, StoriesRefresh event,
Emitter<StoriesState> emit, Emitter<StoriesState> emit,
) async { ) async {
if (state.statusByType[event.type] == StoriesStatus.loading) return;
emit( emit(
state.copyWithStatusUpdated( state.copyWithStatusUpdated(
type: event.type, type: event.type,

View File

@ -39,8 +39,9 @@ abstract class Constants {
static const String featureOpenStoryInWebView = 'open_story_in_web_view'; static const String featureOpenStoryInWebView = 'open_story_in_web_view';
static const String featureLogIn = 'log_in'; static const String featureLogIn = 'log_in';
static const String featurePinToTop = 'pin_to_top'; static const String featurePinToTop = 'pin_to_top';
static const String featureJumpUpButton = 'jump_up_button'; static const String featureJumpUpButton = 'jump_up_button_with_long_press';
static const String featureJumpDownButton = 'jump_down_button'; static const String featureJumpDownButton =
'jump_down_button_with_long_press';
static final String happyFace = <String>[ static final String happyFace = <String>[
'(๑•̀ㅂ•́)و✧', '(๑•̀ㅂ•́)و✧',

View File

@ -2,7 +2,7 @@ import 'package:logger/logger.dart';
class CustomLogFilter extends LogFilter { class CustomLogFilter extends LogFilter {
@override @override
Level? get level => Level.verbose; Level? get level => Level.trace;
/// The minimal level allowed in production. /// The minimal level allowed in production.
static const Level _minimalLevel = Level.info; static const Level _minimalLevel = Level.info;

View File

@ -11,10 +11,14 @@ class CustomRouter {
switch (settings.name) { switch (settings.name) {
case HomeScreen.routeName: case HomeScreen.routeName:
return HomeScreen.route(); return HomeScreen.route();
case ItemScreen.routeName:
return ItemScreen.route(settings.arguments! as ItemScreenArgs);
case SubmitScreen.routeName: case SubmitScreen.routeName:
return SubmitScreen.route(); return SubmitScreen.route();
case QrCodeScannerScreen.routeName:
return QrCodeScannerScreen.route();
case ItemScreen.routeName:
return ItemScreen.route(settings.arguments! as ItemScreenArgs);
case QrCodeViewScreen.routeName:
return QrCodeViewScreen.route(data: settings.arguments! as String);
default: default:
return _errorRoute(); return _errorRoute();
} }

View File

@ -20,7 +20,7 @@ class CustomFileOutput extends LogOutput {
IOSink? _sink; IOSink? _sink;
@override @override
void init() { Future<void> init() async {
_sink = file.openWrite( _sink = file.openWrite(
mode: overrideExisting ? FileMode.writeOnly : FileMode.writeOnlyAppend, mode: overrideExisting ? FileMode.writeOnly : FileMode.writeOnlyAppend,
encoding: encoding, encoding: encoding,

View File

@ -349,8 +349,8 @@ class CommentsCubit extends Cubit<CommentsState> {
init(useCommentCache: true); init(useCommentCache: true);
} }
/// Jump to next root level comment. /// Scroll to next root level comment.
void jump( void scrollToNextRoot(
ItemScrollController itemScrollController, ItemScrollController itemScrollController,
ItemPositionsListener itemPositionsListener, ItemPositionsListener itemPositionsListener,
) { ) {
@ -387,8 +387,8 @@ class CommentsCubit extends Cubit<CommentsState> {
} }
} }
/// Jump to previous root level comment. /// Scroll to previous root level comment.
void jumpUp( void scrollToPreviousRoot(
ItemScrollController itemScrollController, ItemScrollController itemScrollController,
ItemPositionsListener itemPositionsListener, ItemPositionsListener itemPositionsListener,
) { ) {

View File

@ -27,7 +27,7 @@ class PinCubit extends Cubit<PinState> {
emit(state.copyWith(pinnedStoriesIds: ids)); emit(state.copyWith(pinnedStoriesIds: ids));
_storiesRepository.fetchStoriesStream(ids: ids).listen(_onStoryFetched); _storiesRepository.fetchStoriesStream(ids: ids).listen(_onStoryFetched);
}); }).whenComplete(() => emit(state.copyWith(status: Status.loaded)));
} }
void pinStory(Story story) { void pinStory(Story story) {
@ -52,7 +52,10 @@ class PinCubit extends Cubit<PinState> {
_preferenceRepository.updatePinnedStoriesIds(state.pinnedStoriesIds); _preferenceRepository.updatePinnedStoriesIds(state.pinnedStoriesIds);
} }
void refresh() => init(); void refresh() {
if (state.status == Status.loading) return;
init();
}
void _onStoryFetched(Story story) { void _onStoryFetched(Story story) {
emit(state.copyWith(pinnedStories: <Story>[...state.pinnedStories, story])); emit(state.copyWith(pinnedStories: <Story>[...state.pinnedStories, story]));

View File

@ -4,22 +4,27 @@ class PinState extends Equatable {
const PinState({ const PinState({
required this.pinnedStoriesIds, required this.pinnedStoriesIds,
required this.pinnedStories, required this.pinnedStories,
required this.status,
}); });
PinState.init() PinState.init()
: pinnedStoriesIds = <int>[], : pinnedStoriesIds = <int>[],
pinnedStories = <Story>[]; pinnedStories = <Story>[],
status = Status.idle;
final List<int> pinnedStoriesIds; final List<int> pinnedStoriesIds;
final List<Story> pinnedStories; final List<Story> pinnedStories;
final Status status;
PinState copyWith({ PinState copyWith({
List<int>? pinnedStoriesIds, List<int>? pinnedStoriesIds,
List<Story>? pinnedStories, List<Story>? pinnedStories,
Status? status,
}) { }) {
return PinState( return PinState(
pinnedStoriesIds: pinnedStoriesIds ?? this.pinnedStoriesIds, pinnedStoriesIds: pinnedStoriesIds ?? this.pinnedStoriesIds,
pinnedStories: pinnedStories ?? this.pinnedStories, pinnedStories: pinnedStories ?? this.pinnedStories,
status: status ?? this.status,
); );
} }
@ -27,5 +32,6 @@ class PinState extends Equatable {
List<Object?> get props => <Object?>[ List<Object?> get props => <Object?>[
pinnedStoriesIds, pinnedStoriesIds,
pinnedStories, pinnedStories,
status,
]; ];
} }

View File

@ -14,6 +14,10 @@ extension ObjectExtension on Object {
String identifier = '', String identifier = '',
StackTrace? stackTrace, StackTrace? stackTrace,
}) { }) {
locator.get<Logger>().e(identifier, this, stackTrace ?? StackTrace.current); locator.get<Logger>().e(
identifier,
error: this,
stackTrace: stackTrace ?? StackTrace.current,
);
} }
} }

View File

@ -58,8 +58,8 @@ Future<void> main({bool testing = false}) async {
FlutterError.onError = (FlutterErrorDetails details) { FlutterError.onError = (FlutterErrorDetails details) {
locator.get<Logger>().e( locator.get<Logger>().e(
details.summary, details.summary,
details.exceptionAsString(), error: details.exceptionAsString(),
details.stack, stackTrace: details.stack,
); );
}; };
@ -241,7 +241,7 @@ class HackiApp extends StatelessWidget {
create: (BuildContext context) => TabCubit( create: (BuildContext context) => TabCubit(
preferenceCubit: context.read<PreferenceCubit>(), preferenceCubit: context.read<PreferenceCubit>(),
)..init(), )..init(),
) ),
], ],
child: AdaptiveTheme( child: AdaptiveTheme(
light: ThemeData( light: ThemeData(
@ -289,7 +289,9 @@ class HackiApp extends StatelessWidget {
child: MaterialApp( child: MaterialApp(
title: 'Hacki', title: 'Hacki',
debugShowCheckedModeBanner: false, debugShowCheckedModeBanner: false,
theme: useTrueDark ? trueDarkTheme : theme, theme: (useTrueDark ? trueDarkTheme : theme).copyWith(
useMaterial3: false,
),
navigatorKey: navigatorKey, navigatorKey: navigatorKey,
navigatorObservers: <NavigatorObserver>[ navigatorObservers: <NavigatorObserver>[
locator.get<RouteObserver<ModalRoute<dynamic>>>(), locator.get<RouteObserver<ModalRoute<dynamic>>>(),

View File

@ -0,0 +1,14 @@
import 'package:flutter/material.dart' show IconData, Icons;
enum ExportDestination {
qrCode('QR code', icon: Icons.qr_code),
clipBoard('ClipBoard', icon: Icons.copy);
const ExportDestination(
this.label, {
required this.icon,
});
final String label;
final IconData icon;
}

View File

@ -4,7 +4,8 @@ enum FontSize {
small('Small', TextDimens.pt15), small('Small', TextDimens.pt15),
regular('Regular', TextDimens.pt16), regular('Regular', TextDimens.pt16),
large('Large', TextDimens.pt17), large('Large', TextDimens.pt17),
xlarge('XLarge', TextDimens.pt18); xlarge('XLarge', TextDimens.pt18),
xxlarge('XXLarge', TextDimens.pt19);
const FontSize(this.description, this.fontSize); const FontSize(this.description, this.fontSize);

View File

@ -1,4 +1,5 @@
export 'comments_order.dart'; export 'comments_order.dart';
export 'export_destination.dart';
export 'fetch_mode.dart'; export 'fetch_mode.dart';
export 'font.dart'; export 'font.dart';
export 'font_size.dart'; export 'font_size.dart';
@ -6,5 +7,6 @@ export 'item/item.dart';
export 'post_data.dart'; export 'post_data.dart';
export 'preference.dart'; export 'preference.dart';
export 'search_params.dart'; export 'search_params.dart';
export 'status.dart';
export 'story_type.dart'; export 'story_type.dart';
export 'user.dart'; export 'user.dart';

View File

@ -146,7 +146,7 @@ class AutoScrollModePreference extends BooleanPreference {
@override @override
String get subtitle => String get subtitle =>
'''Automatically scroll to next comment when you collapse a comment.'''; '''automatically scroll to next comment when you collapse a comment.''';
} }
/// The value deciding whether or not the story /// The value deciding whether or not the story

6
lib/models/status.dart Normal file
View File

@ -0,0 +1,6 @@
enum Status {
idle,
loading,
loaded,
error,
}

View File

@ -64,7 +64,7 @@ class PostableRepository {
validateStatus: validateStatus, validateStatus: validateStatus,
), ),
); );
} on DioError catch (e) { } on DioException catch (e) {
throw ServiceException(e.message); throw ServiceException(e.message);
} }
} }

View File

@ -370,7 +370,7 @@ class _ItemScreenState extends State<ItemScreen> with RouteAware {
), ),
SizedBox( SizedBox(
height: MediaQuery.of(context).viewInsets.bottom, height: MediaQuery.of(context).viewInsets.bottom,
) ),
], ],
); );
}, },

View File

@ -43,6 +43,7 @@ class CustomAppBar extends AppBar {
fontFamily: FeatherIcons.type.fontFamily, fontFamily: FeatherIcons.type.fontFamily,
package: FeatherIcons.type.fontPackage, package: FeatherIcons.type.fontPackage,
), ),
textScaleFactor: 1,
), ),
onPressed: onFontSizeTap, onPressed: onFontSizeTap,
), ),

View File

@ -32,30 +32,32 @@ class CustomFloatingActionButton extends StatelessWidget {
Icons.keyboard_arrow_up, Icons.keyboard_arrow_up,
color: Palette.white, color: Palette.white,
), ),
title: const Text('Jump to previous root level comment.'), title: const Text('Shortcut'),
description: const Text( description: const Text(
'''Tapping on this button will take you to the previous off-screen root level comment.''', '''Tapping on this button will take you to the previous off-screen root level comment.\n\nLong press on it to jump to the very beginning of this thread.''',
), ),
child: FloatingActionButton.small( child: InkWell(
backgroundColor: Theme.of(context).scaffoldBackgroundColor, onLongPress: () => itemScrollController.scrollTo(
index: 0,
duration: Durations.ms400,
),
child: FloatingActionButton.small(
backgroundColor: Theme.of(context).scaffoldBackgroundColor,
/// Randomly generated string as heroTag to prevent /// Randomly generated string as heroTag to prevent
/// default [FloatingActionButton] animation. /// default [FloatingActionButton] animation.
heroTag: UniqueKey().hashCode, heroTag: UniqueKey().hashCode,
onPressed: () { onPressed: () {
if (state.status == CommentsStatus.loading) return; HapticFeedbackUtil.selection();
context.read<CommentsCubit>().scrollToPreviousRoot(
HapticFeedbackUtil.selection(); itemScrollController,
context.read<CommentsCubit>().jumpUp( itemPositionsListener,
itemScrollController, );
itemPositionsListener, },
); child: Icon(
}, Icons.keyboard_arrow_up,
child: Icon( color: Theme.of(context).colorScheme.primary,
Icons.keyboard_arrow_up, ),
color: state.status == CommentsStatus.loading
? Palette.grey
: Theme.of(context).colorScheme.primary,
), ),
), ),
), ),
@ -65,29 +67,31 @@ class CustomFloatingActionButton extends StatelessWidget {
Icons.keyboard_arrow_down, Icons.keyboard_arrow_down,
color: Palette.white, color: Palette.white,
), ),
title: const Text('Jump to next root level comment.'), title: const Text('Shortcut'),
description: const Text( description: const Text(
'''Tapping on this button will take you to the next off-screen root level comment.''', '''Tapping on this button will take you to the next off-screen root level comment.\n\nLong press on it to jump to the end of this thread.''',
), ),
child: FloatingActionButton.small( child: InkWell(
backgroundColor: Theme.of(context).scaffoldBackgroundColor, onLongPress: () => itemScrollController.scrollTo(
index: state.comments.length,
duration: Durations.ms400,
),
child: FloatingActionButton.small(
backgroundColor: Theme.of(context).scaffoldBackgroundColor,
/// Same as above. /// Same as above.
heroTag: UniqueKey().hashCode, heroTag: UniqueKey().hashCode,
onPressed: () { onPressed: () {
if (state.status == CommentsStatus.loading) return; HapticFeedbackUtil.selection();
context.read<CommentsCubit>().scrollToNextRoot(
HapticFeedbackUtil.selection(); itemScrollController,
context.read<CommentsCubit>().jump( itemPositionsListener,
itemScrollController, );
itemPositionsListener, },
); child: Icon(
}, Icons.keyboard_arrow_down,
child: Icon( color: Theme.of(context).colorScheme.primary,
Icons.keyboard_arrow_down, ),
color: state.status == CommentsStatus.loading
? Palette.grey
: Theme.of(context).colorScheme.primary,
), ),
), ),
), ),

View File

@ -141,7 +141,7 @@ class _LoginDialogState extends State<LoginDialog> {
), ),
], ],
), ),
) ),
], ],
), ),
Padding( Padding(

View File

@ -255,6 +255,8 @@ class _ParentItemSection extends StatelessWidget {
style: const TextStyle( style: const TextStyle(
color: Palette.orange, color: Palette.orange,
), ),
textScaleFactor:
MediaQuery.of(context).textScaleFactor,
), ),
const Spacer(), const Spacer(),
Text( Text(
@ -262,6 +264,8 @@ class _ParentItemSection extends StatelessWidget {
style: const TextStyle( style: const TextStyle(
color: Palette.grey, color: Palette.grey,
), ),
textScaleFactor:
MediaQuery.of(context).textScaleFactor,
), ),
], ],
), ),
@ -334,9 +338,8 @@ class _ParentItemSection extends StatelessWidget {
], ],
), ),
textAlign: TextAlign.center, textAlign: TextAlign.center,
textScaleFactor: MediaQuery.of( textScaleFactor:
context, MediaQuery.of(context).textScaleFactor,
).textScaleFactor,
), ),
), ),
) )
@ -354,6 +357,8 @@ class _ParentItemSection extends StatelessWidget {
), ),
child: ItemText( child: ItemText(
item: state.item, item: state.item,
textScaleFactor:
MediaQuery.of(context).textScaleFactor,
), ),
), ),
), ),
@ -402,6 +407,7 @@ class _ParentItemSection extends StatelessWidget {
style: const TextStyle( style: const TextStyle(
fontSize: TextDimens.pt13, fontSize: TextDimens.pt13,
), ),
textScaleFactor: 1,
), ),
] else ...<Widget>[ ] else ...<Widget>[
const SizedBox( const SizedBox(
@ -444,6 +450,7 @@ class _ParentItemSection extends StatelessWidget {
style: TextStyle( style: TextStyle(
fontSize: TextDimens.pt13, fontSize: TextDimens.pt13,
), ),
textScaleFactor: 1,
), ),
), ),
), ),
@ -462,6 +469,7 @@ class _ParentItemSection extends StatelessWidget {
style: const TextStyle( style: const TextStyle(
fontSize: TextDimens.pt13, fontSize: TextDimens.pt13,
), ),
textScaleFactor: 1,
), ),
), ),
) )
@ -483,6 +491,7 @@ class _ParentItemSection extends StatelessWidget {
style: const TextStyle( style: const TextStyle(
fontSize: TextDimens.pt13, fontSize: TextDimens.pt13,
), ),
textScaleFactor: 1,
), ),
), ),
) )

View File

@ -285,7 +285,7 @@ class MorePopupMenu extends StatelessWidget {
child: SearchScreen( child: SearchScreen(
fromUserDialog: true, fromUserDialog: true,
), ),
) ),
], ],
), ),
), ),

View File

@ -134,7 +134,7 @@ class _PollViewState extends State<PollView> {
), ),
], ],
), ),
) ),
], ],
), ),
); );

View File

@ -345,6 +345,8 @@ class _ReplyBoxState extends State<ReplyBox> {
child: SingleChildScrollView( child: SingleChildScrollView(
child: ItemText( child: ItemText(
item: replyingTo, item: replyingTo,
textScaleFactor:
MediaQuery.of(context).textScaleFactor,
), ),
), ),
), ),

View File

@ -363,7 +363,7 @@ class _ProfileScreenState extends State<ProfileScreen>
? <Comment>[comment] ? <Comment>[comment]
: <Comment>[ : <Comment>[
...children, ...children,
comment.copyWith(level: children.length) comment.copyWith(level: children.length),
], ],
onlyShowTargetComment: true, onlyShowTargetComment: true,
), ),

View File

@ -0,0 +1,78 @@
import 'package:flutter/material.dart';
import 'package:hacki/main.dart';
import 'package:hacki/styles/styles.dart';
import 'package:qr_code_scanner/qr_code_scanner.dart';
class QrCodeScannerScreen extends StatefulWidget {
const QrCodeScannerScreen({super.key});
static const String routeName = '/qr-code-scanner';
static Route<dynamic> route() {
return MaterialPageRoute<String?>(
settings: const RouteSettings(name: routeName),
builder: (_) => const QrCodeScannerScreen(),
);
}
@override
State<QrCodeScannerScreen> createState() => _QrCodeScannerScreenState();
}
class _QrCodeScannerScreenState extends State<QrCodeScannerScreen> {
final GlobalKey qrKey = GlobalKey(debugLabel: 'QR');
QRViewController? controller;
bool isFlashOn = false;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
elevation: 0,
backgroundColor: Palette.transparent,
actions: <Widget>[
IconButton(
icon: Icon(isFlashOn ? Icons.flash_off : Icons.flash_on),
onPressed: () {
controller?.toggleFlash();
setState(() {
isFlashOn = !isFlashOn;
});
},
),
IconButton(
icon: const Icon(Icons.cameraswitch_outlined),
onPressed: controller?.flipCamera,
),
],
),
extendBodyBehindAppBar: true,
body: Column(
children: <Widget>[
Expanded(
child: QRView(
key: qrKey,
onQRViewCreated: onQRViewCreated,
),
),
],
),
);
}
void onQRViewCreated(QRViewController controller) {
setState(() {
this.controller = controller;
});
controller.scannedDataStream.listen((Barcode scanData) {
controller.stopCamera();
HackiApp.navigatorKey.currentState?.pop(scanData.code);
});
}
@override
void dispose() {
controller?.dispose();
super.dispose();
}
}

View File

@ -0,0 +1,55 @@
import 'package:flutter/material.dart';
import 'package:hacki/styles/palette.dart';
import 'package:qr_flutter/qr_flutter.dart';
class QrCodeViewScreen extends StatelessWidget {
const QrCodeViewScreen({
required this.data,
super.key,
});
final String data;
static const String routeName = '/qr-code-view';
static Route<dynamic> route({required String data}) {
return MaterialPageRoute<QrCodeViewScreen>(
settings: const RouteSettings(name: routeName),
builder: (_) => QrCodeViewScreen(
data: data,
),
);
}
static const int qrCodeVersion = 4;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
elevation: 0,
backgroundColor: Palette.transparent,
),
body: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Center(
child: QrImageView(
data: data,
dataModuleStyle: QrDataModuleStyle(
dataModuleShape: QrDataModuleShape.square,
color: Theme.of(context).colorScheme.onSurface,
),
eyeStyle: QrEyeStyle(
eyeShape: QrEyeShape.square,
color: Theme.of(context).colorScheme.onSurface,
),
version: qrCodeVersion,
size: 300,
),
),
],
),
);
}
}

View File

@ -1,3 +1,4 @@
import 'dart:async';
import 'dart:io'; import 'dart:io';
import 'package:adaptive_theme/adaptive_theme.dart'; import 'package:adaptive_theme/adaptive_theme.dart';
@ -14,9 +15,12 @@ import 'package:hacki/config/constants.dart';
import 'package:hacki/config/locator.dart'; import 'package:hacki/config/locator.dart';
import 'package:hacki/cubits/cubits.dart'; import 'package:hacki/cubits/cubits.dart';
import 'package:hacki/extensions/extensions.dart'; import 'package:hacki/extensions/extensions.dart';
import 'package:hacki/main.dart';
import 'package:hacki/models/models.dart'; import 'package:hacki/models/models.dart';
import 'package:hacki/repositories/repositories.dart'; import 'package:hacki/repositories/repositories.dart';
import 'package:hacki/screens/profile/models/page_type.dart'; import 'package:hacki/screens/profile/models/page_type.dart';
import 'package:hacki/screens/profile/qr_code_scanner_screen.dart';
import 'package:hacki/screens/profile/qr_code_view_screen.dart';
import 'package:hacki/screens/profile/widgets/offline_list_tile.dart'; import 'package:hacki/screens/profile/widgets/offline_list_tile.dart';
import 'package:hacki/screens/profile/widgets/tab_bar_settings.dart'; import 'package:hacki/screens/profile/widgets/tab_bar_settings.dart';
import 'package:hacki/screens/widgets/widgets.dart'; import 'package:hacki/screens/widgets/widgets.dart';
@ -244,6 +248,13 @@ class _SettingsState extends State<Settings> {
), ),
onTap: onExportFavoritesTapped, onTap: onExportFavoritesTapped,
), ),
ListTile(
title: const Text(
'Import Favorites',
),
onTap: () =>
onImportFavoritesTapped(context.read<FavCubit>()),
),
ListTile( ListTile(
title: const Text( title: const Text(
'Clear Favorites', 'Clear Favorites',
@ -350,7 +361,7 @@ class _SettingsState extends State<Settings> {
), ),
Spacer(), Spacer(),
], ],
) ),
], ],
), ),
); );
@ -754,20 +765,68 @@ class _SettingsState extends State<Settings> {
} }
Future<void> onExportFavoritesTapped() async { Future<void> onExportFavoritesTapped() async {
final List<int> allFavorites = context.read<FavCubit>().state.favIds; return showModalBottomSheet<ExportDestination>(
context: context,
builder: (BuildContext context) {
return SafeArea(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
...ExportDestination.values.map(
(ExportDestination e) => ListTile(
leading: Icon(e.icon),
title: Text(e.label),
onTap: () => Navigator.pop<ExportDestination>(context, e),
),
),
],
),
);
},
).then(
(ExportDestination? destination) => exportFavorites(to: destination),
);
}
Future<void> onImportFavoritesTapped(FavCubit favCubit) async {
final String? res = await HackiApp.navigatorKey.currentState
?.pushNamed(QrCodeScannerScreen.routeName) as String?;
final List<int>? ids =
res?.split('\n').map(int.tryParse).whereType<int>().toList();
if (ids == null) return;
for (final int id in ids) {
await favCubit.addFav(id);
}
showSnackBar(content: 'Favorites imported successfully.');
}
Future<void> exportFavorites({required ExportDestination? to}) async {
final ExportDestination? destination = to;
if (destination == null) return;
final List<int> allFavorites = context.read<FavCubit>().state.favIds;
if (allFavorites.isEmpty) { if (allFavorites.isEmpty) {
showSnackBar(content: "You don't have any favorite item."); showSnackBar(content: "You don't have any favorite item.");
return; return;
} }
final String allFavoritesStr = allFavorites.join('\n');
try { switch (destination) {
await FlutterClipboard.copy( case ExportDestination.qrCode:
allFavorites.join('\n'), await HackiApp.navigatorKey.currentState?.pushNamed(
).whenComplete(HapticFeedbackUtil.selection); QrCodeViewScreen.routeName,
showSnackBar(content: 'Ids of favorites have been copied to clipboard.'); arguments: allFavoritesStr,
} catch (error, stackTrace) { );
error.logError(stackTrace: stackTrace); case ExportDestination.clipBoard:
try {
await FlutterClipboard.copy(allFavoritesStr)
.whenComplete(HapticFeedbackUtil.selection);
showSnackBar(
content: 'Ids of favorites have been copied to clipboard.',
);
} catch (error, stackTrace) {
error.logError(stackTrace: stackTrace);
}
} }
} }

View File

@ -1,6 +1,8 @@
export 'home/home_screen.dart'; export 'home/home_screen.dart';
export 'item/item_screen.dart'; export 'item/item_screen.dart';
export 'profile/profile_screen.dart'; export 'profile/profile_screen.dart';
export 'profile/qr_code_scanner_screen.dart';
export 'profile/qr_code_view_screen.dart';
export 'search/search_screen.dart'; export 'search/search_screen.dart';
export 'submit/submit_screen.dart'; export 'submit/submit_screen.dart';
export 'web_view/web_view_screen.dart'; export 'web_view/web_view_screen.dart';

View File

@ -143,6 +143,8 @@ class CommentTile extends StatelessWidget {
? orange ? orange
: color, : color,
), ),
textScaleFactor:
MediaQuery.of(context).textScaleFactor,
), ),
if (comment.by == opUsername) if (comment.by == opUsername)
const Text( const Text(
@ -157,6 +159,8 @@ class CommentTile extends StatelessWidget {
style: const TextStyle( style: const TextStyle(
color: Palette.grey, color: Palette.grey,
), ),
textScaleFactor:
MediaQuery.of(context).textScaleFactor,
), ),
], ],
), ),
@ -196,6 +200,8 @@ class CommentTile extends StatelessWidget {
child: ItemText( child: ItemText(
key: ValueKey<int>(comment.id), key: ValueKey<int>(comment.id),
item: comment, item: comment,
textScaleFactor: MediaQuery.of(context)
.textScaleFactor,
onTap: () { onTap: () {
if (onTap == null) { if (onTap == null) {
_onTextTapped(context); _onTextTapped(context);

View File

@ -3,7 +3,7 @@ import 'package:flutter/material.dart';
import 'package:hacki/screens/widgets/custom_linkify/linkifiers/linkifiers.dart'; import 'package:hacki/screens/widgets/custom_linkify/linkifiers/linkifiers.dart';
import 'package:hacki/styles/palette.dart'; import 'package:hacki/styles/palette.dart';
import 'package:hacki/utils/utils.dart'; import 'package:hacki/utils/utils.dart';
import 'package:linkify/linkify.dart'; import 'package:linkify/linkify.dart' hide UrlLinkifier;
export 'package:hacki/screens/widgets/custom_linkify/linkifiers/linkifiers.dart'; export 'package:hacki/screens/widgets/custom_linkify/linkifiers/linkifiers.dart';
export 'package:linkify/linkify.dart' export 'package:linkify/linkify.dart'
@ -14,9 +14,7 @@ export 'package:linkify/linkify.dart'
Linkifier, Linkifier,
LinkifyElement, LinkifyElement,
LinkifyOptions, LinkifyOptions,
TextElement, TextElement;
UrlElement,
UrlLinkifier;
/// Callback clicked link /// Callback clicked link
typedef LinkCallback = void Function(LinkableElement link); typedef LinkCallback = void Function(LinkableElement link);

View File

@ -1,2 +1,3 @@
export 'emphasis_linkifier.dart'; export 'emphasis_linkifier.dart';
export 'quote_linkifier.dart'; export 'quote_linkifier.dart';
export 'url_linkifier.dart';

View File

@ -0,0 +1,121 @@
import 'package:flutter/foundation.dart';
import 'package:linkify/linkify.dart';
final RegExp _urlRegex = RegExp(
r'^(.*?)((?:https?:\/\/|www\.)[^\s/$.?#].[\/\\\%:\?=&#@;A-Za-z0-9_.~-]*)',
caseSensitive: false,
dotAll: true,
);
final RegExp _looseUrlRegex = RegExp(
r'''^(.*?)((https?:\/\/)?(www\.)?[-a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,4}\b([-a-zA-Z0-9@:%_\+.~#?&//="'`]*))''',
caseSensitive: false,
dotAll: true,
);
final RegExp _protocolIdentifierRegex = RegExp(
r'^(https?:\/\/)',
caseSensitive: false,
);
class UrlLinkifier extends Linkifier {
const UrlLinkifier();
@override
List<LinkifyElement> parse(
List<LinkifyElement> elements,
LinkifyOptions options,
) {
final List<LinkifyElement> list = <LinkifyElement>[];
for (final LinkifyElement element in elements) {
if (element is TextElement) {
final RegExpMatch? match = options.looseUrl
? _looseUrlRegex.firstMatch(element.text)
: _urlRegex.firstMatch(element.text);
if (match == null) {
list.add(element);
} else {
final String text = element.text.replaceFirst(match.group(0)!, '');
if (match.group(1)?.isNotEmpty ?? false) {
list.add(TextElement(match.group(1)!));
}
if (match.group(2)?.isNotEmpty ?? false) {
String originalUrl = match.group(2)!;
String originText = originalUrl;
String? end;
if ((options.excludeLastPeriod) &&
originalUrl[originalUrl.length - 1] == '.') {
end = '.';
originText = originText.substring(0, originText.length - 1);
originalUrl = originalUrl.substring(0, originalUrl.length - 1);
}
String url = originalUrl;
if (!originalUrl.startsWith(_protocolIdentifierRegex)) {
originalUrl = (options.defaultToHttps ? 'https://' : 'http://') +
originalUrl;
}
if ((options.humanize) || (options.removeWww)) {
if (options.humanize) {
url = url.replaceFirst(RegExp('https?://'), '');
}
if (options.removeWww) {
url = url.replaceFirst(RegExp(r'www\.'), '');
}
list.add(
UrlElement(
originalUrl,
url,
originText,
),
);
} else {
list.add(UrlElement(originalUrl, null, originText));
}
if (end != null) {
list.add(TextElement(end));
}
}
if (text.isNotEmpty) {
list.addAll(parse(<LinkifyElement>[TextElement(text)], options));
}
}
} else {
list.add(element);
}
}
return list;
}
}
/// Represents an element containing a link
@immutable
class UrlElement extends LinkableElement {
UrlElement(String url, [String? text, String? originText])
: super(text, url, originText);
@override
String toString() {
return "LinkElement: '$url' ($text)";
}
@override
bool operator ==(Object other) => equals(other);
@override
int get hashCode => Object.hash(text, originText, url);
@override
bool equals(dynamic other) => other is UrlElement && super.equals(other);
}

View File

@ -17,7 +17,7 @@ class DeviceGestureWrapper extends StatelessWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return MediaQuery( return MediaQuery(
data: const MediaQueryData( data: const MediaQueryData(
gestureSettings: DeviceGestureSettings(touchSlop: 7.9), gestureSettings: DeviceGestureSettings(touchSlop: 12),
), ),
child: child, child: child,
); );

View File

@ -10,12 +10,14 @@ import 'package:hacki/utils/utils.dart';
class ItemText extends StatelessWidget { class ItemText extends StatelessWidget {
const ItemText({ const ItemText({
required this.item, required this.item,
required this.textScaleFactor,
super.key, super.key,
this.onTap, this.onTap,
}); });
final Item item; final Item item;
final VoidCallback? onTap; final VoidCallback? onTap;
final double textScaleFactor;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -37,7 +39,7 @@ class ItemText extends StatelessWidget {
onOpen: (LinkableElement link) => LinkUtil.launch(link.url), onOpen: (LinkableElement link) => LinkUtil.launch(link.url),
), ),
onTap: onTap, onTap: onTap,
textScaleFactor: MediaQuery.of(context).textScaleFactor, textScaleFactor: textScaleFactor,
contextMenuBuilder: ( contextMenuBuilder: (
BuildContext context, BuildContext context,
EditableTextState editableTextState, EditableTextState editableTextState,
@ -52,7 +54,7 @@ class ItemText extends StatelessWidget {
} else { } else {
return SelectableLinkify( return SelectableLinkify(
text: item.text, text: item.text,
textScaleFactor: MediaQuery.of(context).textScaleFactor, textScaleFactor: textScaleFactor,
style: style, style: style,
linkStyle: linkStyle, linkStyle: linkStyle,
onOpen: (LinkableElement link) => LinkUtil.launch(link.url), onOpen: (LinkableElement link) => LinkUtil.launch(link.url),

View File

@ -229,7 +229,7 @@ class _LinkPreviewPlaceholder extends StatelessWidget {
], ],
), ),
), ),
) ),
], ],
), ),
), ),

View File

@ -273,7 +273,7 @@ class WebAnalyzer {
info.title, info.title,
info.description, info.description,
info.icon, info.icon,
info.image info.image,
]; ];
} else if (info is WebVideoInfo) { } else if (info is WebVideoInfo) {
return <dynamic>['1', info.image]; return <dynamic>['1', info.image];

View File

@ -33,6 +33,7 @@ abstract class TextDimens {
static const double pt16 = 16; static const double pt16 = 16;
static const double pt17 = 17; static const double pt17 = 17;
static const double pt18 = 18; static const double pt18 = 18;
static const double pt19 = 19;
static const double pt20 = 20; static const double pt20 = 20;
static const double pt24 = 24; static const double pt24 = 24;
static const double pt26 = 26; static const double pt26 = 26;

View File

@ -26,8 +26,8 @@ abstract class HtmlUtil {
.querySelectorAll("input[type='hidden']"); .querySelectorAll("input[type='hidden']");
return <String, String>{ return <String, String>{
if (hiddenInputs != null) if (hiddenInputs != null)
for (dom.Element hiddenInput in hiddenInputs) for (final dom.Element hiddenInput in hiddenInputs)
hiddenInput.attributes['name']!: hiddenInput.attributes['value']! hiddenInput.attributes['name']!: hiddenInput.attributes['value']!,
}; };
} }

View File

@ -2,7 +2,6 @@ import 'dart:io';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_inappwebview/flutter_inappwebview.dart'; import 'package:flutter_inappwebview/flutter_inappwebview.dart';
import 'package:hacki/config/constants.dart';
import 'package:hacki/config/locator.dart'; import 'package:hacki/config/locator.dart';
import 'package:hacki/extensions/extensions.dart'; import 'package:hacki/extensions/extensions.dart';
import 'package:hacki/main.dart'; import 'package:hacki/main.dart';
@ -54,17 +53,7 @@ abstract class LinkUtil {
return; return;
} }
Uri rinseLink(String link) { final Uri uri = Uri.parse(link);
final RegExp regex = RegExp(RegExpConstants.linkSuffix);
if (!link.contains('en.wikipedia.org') && link.contains(regex)) {
final String match = regex.stringMatch(link) ?? '';
return Uri.parse(link.replaceAll(match, ''));
}
return Uri.parse(link);
}
final Uri uri = rinseLink(link);
canLaunchUrl(uri).then((bool val) { canLaunchUrl(uri).then((bool val) {
if (val) { if (val) {
if (link.contains('http')) { if (link.contains('http')) {

View File

@ -1,5 +1,5 @@
import 'package:hacki/screens/widgets/custom_linkify/linkifiers/linkifiers.dart'; import 'package:hacki/screens/widgets/custom_linkify/linkifiers/linkifiers.dart';
import 'package:linkify/linkify.dart'; import 'package:linkify/linkify.dart' hide UrlLinkifier;
abstract class LinkifierUtil { abstract class LinkifierUtil {
static const LinkifyOptions linkifyOptions = LinkifyOptions(humanize: false); static const LinkifyOptions linkifyOptions = LinkifyOptions(humanize: false);

View File

@ -5,34 +5,34 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: _fe_analyzer_shared name: _fe_analyzer_shared
sha256: "405666cd3cf0ee0a48d21ec67e65406aad2c726d9fa58840d3375e7bdcd32a07" sha256: ae92f5d747aee634b87f89d9946000c2de774be1d6ac3e58268224348cd0101a
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "60.0.0" version: "61.0.0"
adaptive_theme: adaptive_theme:
dependency: "direct main" dependency: "direct main"
description: description:
name: adaptive_theme name: adaptive_theme
sha256: "3568bb526d4823c7bb35f9ce3604af15e04cc0e9cc4f257da3604fe6b48d74ae" sha256: "2d9bfee4240cdfad1b169cb43ac38fb49487e7fe1cc845e2973d4cef1780c0f6"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.2.1" version: "3.3.0"
analyzer: analyzer:
dependency: transitive dependency: transitive
description: description:
name: analyzer name: analyzer
sha256: "1952250bd005bacb895a01bf1b4dc00e3ba1c526cf47dca54dfe24979c65f5b3" sha256: ea3d8652bda62982addfd92fdc2d0214e5f82e43325104990d4f4c4a2a313562
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "5.12.0" version: "5.13.0"
args: args:
dependency: transitive dependency: transitive
description: description:
name: args name: args
sha256: c372bb384f273f0c2a8aaaa226dad84dc27c8519a691b888725dec59518ad53a sha256: eef6c46b622e0494a36c5a12d10d77fb4e855501a91c1b9ef9339326e58f0596
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.4.1" version: "2.4.2"
async: async:
dependency: transitive dependency: transitive
description: description:
@ -53,18 +53,18 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: bloc name: bloc
sha256: "658a5ae59edcf1e58aac98b000a71c762ad8f46f1394c34a52050cafb3e11a80" sha256: "3820f15f502372d979121de1f6b97bfcf1630ebff8fe1d52fb2b0bfa49be5b49"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "8.1.1" version: "8.1.2"
bloc_test: bloc_test:
dependency: "direct dev" dependency: "direct dev"
description: description:
name: bloc_test name: bloc_test
sha256: ffbb60c17ee3d8e3784cb78071088e353199057233665541e8ac6cd438dca8ad sha256: af0de1a1e16a7536e95dcd7491e0a6d6078e11d2d691988e862280b74f5c7968
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "9.1.1" version: "9.1.4"
boolean_selector: boolean_selector:
dependency: transitive dependency: transitive
description: description:
@ -125,18 +125,18 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: collection name: collection
sha256: "4a07be6cb69c84d677a6c3096fcf960cc3285a8330b4603e0d463d15d9bd934c" sha256: f092b211a4319e98e5ff58223576de6c2803db36221657b46c82574721240687
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.17.1" version: "1.17.2"
connectivity_plus: connectivity_plus:
dependency: "direct main" dependency: "direct main"
description: description:
name: connectivity_plus name: connectivity_plus
sha256: "45262924896ff72a8cd92b722bb7e3d5020f9e0724531a3e10e22ddae2005991" sha256: "77a180d6938f78ca7d2382d2240eb626c0f6a735d0bfdce227d8ffb80f95c48b"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "4.0.0" version: "4.0.2"
connectivity_plus_platform_interface: connectivity_plus_platform_interface:
dependency: transitive dependency: transitive
description: description:
@ -181,10 +181,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: csslib name: csslib
sha256: b36c7f7e24c0bdf1bf9a3da461c837d1de64b9f8beb190c9011d8c72a3dfd745 sha256: "706b5707578e0c1b4b7550f64078f0a0f19dec3f50a178ffae7006b0a9ca58fb"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.17.2" version: "1.0.0"
dbus: dbus:
dependency: transitive dependency: transitive
description: description:
@ -197,10 +197,10 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: device_info_plus name: device_info_plus
sha256: "9b1a0c32b2a503f8fe9f8764fac7b5fcd4f6bd35d8f49de5350bccf9e2a33b8a" sha256: "86add5ef97215562d2e090535b0a16f197902b10c369c558a100e74ea06e8659"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "9.0.0" version: "9.0.3"
device_info_plus_platform_interface: device_info_plus_platform_interface:
dependency: transitive dependency: transitive
description: description:
@ -221,10 +221,10 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: dio name: dio
sha256: "347d56c26d63519552ef9a569f2a593dda99a81fdbdff13c584b7197cfe05059" sha256: ce75a1b40947fea0a0e16ce73337122a86762e38b982e1ccb909daa3b9bc4197
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "5.1.2" version: "5.3.2"
equatable: equatable:
dependency: "direct main" dependency: "direct main"
description: description:
@ -262,10 +262,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: ffi name: ffi
sha256: ed5337a5660c506388a9f012be0288fb38b49020ce2b45fe1f8b8323fe429f99 sha256: "7bf0adc28a23d395f19f3f1eb21dd7cfd1dd9f8e1c50051c069122e6853bc878"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.0.2" version: "2.1.0"
file: file:
dependency: transitive dependency: transitive
description: description:
@ -283,10 +283,10 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: flutter_bloc name: flutter_bloc
sha256: "434951eea948dbe87f737b674281465f610b8259c16c097b8163ce138749a775" sha256: e74efb89ee6945bcbce74a5b3a5a3376b088e5f21f55c263fc38cbdc6237faae
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "8.1.2" version: "8.1.3"
flutter_blurhash: flutter_blurhash:
dependency: transitive dependency: transitive
description: description:
@ -299,10 +299,10 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: flutter_cache_manager name: flutter_cache_manager
sha256: "32cd900555219333326a2d0653aaaf8671264c29befa65bbd9856d204a4c9fb3" sha256: "8207f27539deb83732fdda03e259349046a39a4c767269285f449ade355d54ba"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.3.0" version: "3.3.1"
flutter_driver: flutter_driver:
dependency: "direct dev" dependency: "direct dev"
description: flutter description: flutter
@ -312,10 +312,10 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: flutter_email_sender name: flutter_email_sender
sha256: "9e253c69617f43d4cb5de672e93a7a19c12a21fb6a75e66c6ce7626336c4c1bc" sha256: "52b713a67a966be4d9e6f68a323fc0a5bc2da71c567eb451af1aa90d30adbc3a"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "5.2.0" version: "6.0.1"
flutter_fadein: flutter_fadein:
dependency: "direct main" dependency: "direct main"
description: description:
@ -344,10 +344,10 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: flutter_local_notifications name: flutter_local_notifications
sha256: "20c92629902b125cb624efdbacbbe98806b3c0b01adb3d84d1c72198b3eafb1a" sha256: "3cc40fe8c50ab8383f3e053a499f00f975636622ecdc8e20a77418ece3b1e975"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "14.0.1" version: "15.1.0+1"
flutter_local_notifications_linux: flutter_local_notifications_linux:
dependency: transitive dependency: transitive
description: description:
@ -442,10 +442,10 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: font_awesome_flutter name: font_awesome_flutter
sha256: "959ef4add147753f990b4a7c6cccb746d5792dbdc81b1cde99e62e7edb31b206" sha256: "5fb789145cae1f4c3245c58b3f8fb287d055c26323879eab57a7bf0cfd1e45f3"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "10.4.0" version: "10.5.0"
frontend_server_client: frontend_server_client:
dependency: transitive dependency: transitive
description: description:
@ -479,10 +479,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: glob name: glob
sha256: "4515b5b6ddb505ebdd242a5f2cc5d22d3d6a80013789debfbda7777f47ea308c" sha256: "0e7014b3b7d4dac1ca4d6114f82bf1782ee86745b9b42a92c9289c23d8a0ab63"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.1.1" version: "2.1.2"
hive: hive:
dependency: "direct main" dependency: "direct main"
description: description:
@ -495,10 +495,10 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: html name: html
sha256: "58e3491f7bf0b6a4ea5110c0c688877460d1a6366731155c4a4580e7ded773e8" sha256: "3a7812d5bcd2894edf53dfaf8cd640876cf6cef50a8f238745c8b8120ea74d3a"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.15.3" version: "0.15.4"
html_unescape: html_unescape:
dependency: "direct main" dependency: "direct main"
description: description:
@ -511,10 +511,10 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: http name: http
sha256: "5895291c13fa8a3bd82e76d5627f69e0d85ca6a30dcac95c4ea19a5d555879c2" sha256: "759d1a329847dd0f39226c688d3e06a6b8679668e350e2891a6474f8b4bb8525"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.13.6" version: "1.1.0"
http_multi_server: http_multi_server:
dependency: transitive dependency: transitive
description: description:
@ -535,10 +535,10 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: hydrated_bloc name: hydrated_bloc
sha256: eb92d88061b6b911c48779b08a91c8a9f3a3aa8475f80d9380045375d9876536 sha256: "24994e61f64904d911683cce1a31dc4ef611619da5253f1de2b7b8fc6f79a118"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "9.1.0" version: "9.1.2"
in_app_review: in_app_review:
dependency: "direct main" dependency: "direct main"
description: description:
@ -595,34 +595,34 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: logger name: logger
sha256: db2ff852ed77090ba9f62d3611e4208a3d11dfa35991a81ae724c113fcb3e3f7 sha256: "66cb048220ca51cf9011da69fa581e4ee2bed4be6e82870d9e9baae75739da49"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.3.0" version: "2.0.1"
logging: logging:
dependency: transitive dependency: transitive
description: description:
name: logging name: logging
sha256: "04094f2eb032cbb06c6f6e8d3607edcfcb0455e2bb6cbc010cb01171dcb64e6d" sha256: "623a88c9594aa774443aa3eb2d41807a48486b5613e67599fb4c41c0ad47c340"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.1.1" version: "1.2.0"
matcher: matcher:
dependency: transitive dependency: transitive
description: description:
name: matcher name: matcher
sha256: "6501fbd55da300384b768785b83e5ce66991266cec21af89ab9ae7f5ce1c4cbb" sha256: "1803e76e6653768d64ed8ff2e1e67bea3ad4b923eb5c56a295c3e634bad5960e"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.12.15" version: "0.12.16"
material_color_utilities: material_color_utilities:
dependency: transitive dependency: transitive
description: description:
name: material_color_utilities name: material_color_utilities
sha256: d92141dc6fe1dad30722f9aa826c7fbc896d021d792f80678280601aff8cf724 sha256: "9528f2f296073ff54cb9fee677df673ace1218163c3bc7628093e7eed5203d41"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.2.0" version: "0.5.0"
memoize: memoize:
dependency: "direct main" dependency: "direct main"
description: description:
@ -651,10 +651,10 @@ packages:
dependency: "direct dev" dependency: "direct dev"
description: description:
name: mocktail name: mocktail
sha256: "80a996cd9a69284b3dc521ce185ffe9150cde69767c2d3a0720147d93c0cef53" sha256: "9503969a7c2c78c7292022c70c0289ed6241df7a9ba720010c0b215af29a5a58"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.3.0" version: "1.0.0"
nested: nested:
dependency: transitive dependency: transitive
description: description:
@ -699,10 +699,10 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: package_info_plus name: package_info_plus
sha256: d39e8fbff4c5aef4592737e25ad6ac500df006ce7a7a8e1f838ce1256e167542 sha256: "6ff267fcd9d48cb61c8df74a82680e8b82e940231bb5f68356672fde0397334a"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "4.0.0" version: "4.1.0"
package_info_plus_platform_interface: package_info_plus_platform_interface:
dependency: transitive dependency: transitive
description: description:
@ -723,58 +723,50 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: path_provider name: path_provider
sha256: "3087813781ab814e4157b172f1a11c46be20179fcc9bea043e0fba36bc0acaa2" sha256: "909b84830485dbcd0308edf6f7368bc8fd76afa26a270420f34cabea2a6467a0"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.0.15" version: "2.1.0"
path_provider_android: path_provider_android:
dependency: "direct main" dependency: "direct main"
description: description:
name: path_provider_android name: path_provider_android
sha256: "2cec049d282c7f13c594b4a73976b0b4f2d7a1838a6dd5aaf7bd9719196bee86" sha256: "5d44fc3314d969b84816b569070d7ace0f1dea04bd94a83f74c4829615d22ad8"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.0.27" version: "2.1.0"
path_provider_foundation: path_provider_foundation:
dependency: "direct main" dependency: "direct main"
description: description:
name: path_provider_foundation name: path_provider_foundation
sha256: "1995d88ec2948dac43edf8fe58eb434d35d22a2940ecee1a9fefcd62beee6eb3" sha256: "1b744d3d774e5a879bb76d6cd1ecee2ba2c6960c03b1020cd35212f6aa267ac5"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.2.3" version: "2.3.0"
path_provider_linux: path_provider_linux:
dependency: transitive dependency: transitive
description: description:
name: path_provider_linux name: path_provider_linux
sha256: "2ae08f2216225427e64ad224a24354221c2c7907e448e6e0e8b57b1eb9f10ad1" sha256: ba2b77f0c52a33db09fc8caf85b12df691bf28d983e84cf87ff6d693cfa007b3
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.1.10" version: "2.2.0"
path_provider_platform_interface: path_provider_platform_interface:
dependency: transitive dependency: transitive
description: description:
name: path_provider_platform_interface name: path_provider_platform_interface
sha256: "57585299a729335f1298b43245842678cb9f43a6310351b18fb577d6e33165ec" sha256: bced5679c7df11190e1ddc35f3222c858f328fff85c3942e46e7f5589bf9eb84
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.0.6" version: "2.1.0"
path_provider_windows: path_provider_windows:
dependency: transitive dependency: transitive
description: description:
name: path_provider_windows name: path_provider_windows
sha256: d3f80b32e83ec208ac95253e0cd4d298e104fbc63cb29c5c69edaed43b0c69d6 sha256: ee0e0d164516b90ae1f970bdf29f726f1aa730d7cfc449ecc74c495378b705da
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.1.6" version: "2.2.0"
pedantic:
dependency: transitive
description:
name: pedantic
sha256: "67fc27ed9639506c856c840ccce7594d0bdcd91bc8d53d6e52359449a1d50602"
url: "https://pub.dev"
source: hosted
version: "1.11.1"
petitparser: petitparser:
dependency: transitive dependency: transitive
description: description:
@ -795,10 +787,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: plugin_platform_interface name: plugin_platform_interface
sha256: "6a2128648c854906c53fa8e33986fc0247a1116122f9534dd20e3ab9e16a32bc" sha256: "43798d895c929056255600343db8f049921cbec94d31ec87f1dc5c16c01935dd"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.1.4" version: "2.1.5"
pool: pool:
dependency: transitive dependency: transitive
description: description:
@ -840,6 +832,30 @@ packages:
url: "https://github.com/livinglist/flutter_pulltorefresh" url: "https://github.com/livinglist/flutter_pulltorefresh"
source: git source: git
version: "2.0.0" version: "2.0.0"
qr:
dependency: transitive
description:
name: qr
sha256: "64957a3930367bf97cc211a5af99551d630f2f4625e38af10edd6b19131b64b3"
url: "https://pub.dev"
source: hosted
version: "3.0.1"
qr_code_scanner:
dependency: "direct main"
description:
name: qr_code_scanner
sha256: f23b68d893505a424f0bd2e324ebea71ed88465d572d26bb8d2e78a4749591fd
url: "https://pub.dev"
source: hosted
version: "1.0.1"
qr_flutter:
dependency: "direct main"
description:
name: qr_flutter
sha256: "5095f0fc6e3f71d08adef8feccc8cea4f12eec18a2e31c2e8d82cb6019f4b097"
url: "https://pub.dev"
source: hosted
version: "4.1.0"
receive_sharing_intent: receive_sharing_intent:
dependency: "direct main" dependency: "direct main"
description: description:
@ -876,82 +892,82 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: sembast name: sembast
sha256: a784dbcf313ff38a7f57249694c64a6bcf79f704dbec127958459a7737716830 sha256: "85ff944434f7b566fdc388be4f85b23e954736b7d6e51f965f4f419d966c15b1"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.4.4" version: "3.5.0+1"
share_plus: share_plus:
dependency: "direct main" dependency: "direct main"
description: description:
name: share_plus name: share_plus
sha256: "322a1ec9d9fe07e2e2252c098ce93d12dbd06133cc4c00ffe6a4ef505c295c17" sha256: "6cec740fa0943a826951223e76218df002804adb588235a8910dc3d6b0654e11"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "7.0.0" version: "7.1.0"
share_plus_platform_interface: share_plus_platform_interface:
dependency: transitive dependency: transitive
description: description:
name: share_plus_platform_interface name: share_plus_platform_interface
sha256: "0c6e61471bd71b04a138b8b588fa388e66d8b005e6f2deda63371c5c505a0981" sha256: "357412af4178d8e11d14f41723f80f12caea54cf0d5cd29af9dcdab85d58aea7"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.2.1" version: "3.3.0"
shared_preferences: shared_preferences:
dependency: "direct main" dependency: "direct main"
description: description:
name: shared_preferences name: shared_preferences
sha256: "16d3fb6b3692ad244a695c0183fca18cf81fd4b821664394a781de42386bf022" sha256: "0344316c947ffeb3a529eac929e1978fcd37c26be4e8468628bac399365a3ca1"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.1.1" version: "2.2.0"
shared_preferences_android: shared_preferences_android:
dependency: "direct main" dependency: "direct main"
description: description:
name: shared_preferences_android name: shared_preferences_android
sha256: "6478c6bbbecfe9aced34c483171e90d7c078f5883558b30ec3163cf18402c749" sha256: fe8401ec5b6dcd739a0fe9588802069e608c3fdbfd3c3c93e546cf2f90438076
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.1.4" version: "2.2.0"
shared_preferences_foundation: shared_preferences_foundation:
dependency: "direct main" dependency: "direct main"
description: description:
name: shared_preferences_foundation name: shared_preferences_foundation
sha256: e014107bb79d6d3297196f4f2d0db54b5d1f85b8ea8ff63b8e8b391a02700feb sha256: d29753996d8eb8f7619a1f13df6ce65e34bc107bef6330739ed76f18b22310ef
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.2.2" version: "2.3.3"
shared_preferences_linux: shared_preferences_linux:
dependency: transitive dependency: transitive
description: description:
name: shared_preferences_linux name: shared_preferences_linux
sha256: "9d387433ca65717bbf1be88f4d5bb18f10508917a8fa2fb02e0fd0d7479a9afa" sha256: "71d6806d1449b0a9d4e85e0c7a917771e672a3d5dc61149cc9fac871115018e1"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.2.0" version: "2.3.0"
shared_preferences_platform_interface: shared_preferences_platform_interface:
dependency: transitive dependency: transitive
description: description:
name: shared_preferences_platform_interface name: shared_preferences_platform_interface
sha256: fb5cf25c0235df2d0640ac1b1174f6466bd311f621574997ac59018a6664548d sha256: "23b052f17a25b90ff2b61aad4cc962154da76fb62848a9ce088efe30d7c50ab1"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.2.0" version: "2.3.0"
shared_preferences_web: shared_preferences_web:
dependency: transitive dependency: transitive
description: description:
name: shared_preferences_web name: shared_preferences_web
sha256: "74083203a8eae241e0de4a0d597dbedab3b8fef5563f33cf3c12d7e93c655ca5" sha256: "7347b194fb0bbeb4058e6a4e87ee70350b6b2b90f8ac5f8bd5b3a01548f6d33a"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.1.0" version: "2.2.0"
shared_preferences_windows: shared_preferences_windows:
dependency: transitive dependency: transitive
description: description:
name: shared_preferences_windows name: shared_preferences_windows
sha256: "5e588e2efef56916a3b229c3bfe81e6a525665a454519ca51dbcc4236a274173" sha256: f95e6a43162bce43c9c3405f3eb6f39e5b5d11f65fab19196cf8225e2777624d
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.2.0" version: "2.3.0"
shelf: shelf:
dependency: transitive dependency: transitive
description: description:
@ -988,10 +1004,10 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: shimmer name: shimmer
sha256: "1f1009b5845a1f88f1c5630212279540486f97409e9fc3f63883e71070d107bf" sha256: "5f88c883a22e9f9f299e5ba0e4f7e6054857224976a5d9f839d4ebdc94a14ac9"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.0.0" version: "3.0.0"
sky_engine: sky_engine:
dependency: transitive dependency: transitive
description: flutter description: flutter
@ -1017,26 +1033,26 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: source_span name: source_span
sha256: dd904f795d4b4f3b870833847c461801f6750a9fa8e61ea5ac53f9422b31f250 sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.9.1" version: "1.10.0"
sqflite: sqflite:
dependency: transitive dependency: transitive
description: description:
name: sqflite name: sqflite
sha256: b4d6710e1200e96845747e37338ea8a819a12b51689a3bcf31eff0003b37a0b9 sha256: "591f1602816e9c31377d5f008c2d9ef7b8aca8941c3f89cc5fd9d84da0c38a9a"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.2.8+4" version: "2.3.0"
sqflite_common: sqflite_common:
dependency: transitive dependency: transitive
description: description:
name: sqflite_common name: sqflite_common
sha256: e77abf6ff961d69dfef41daccbb66b51e9983cdd5cb35bf30733598057401555 sha256: "1b92f368f44b0dee2425bb861cfa17b6f6cf3961f762ff6f941d20b33355660a"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.4.5" version: "2.5.0"
stack_trace: stack_trace:
dependency: transitive dependency: transitive
description: description:
@ -1096,26 +1112,26 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: test name: test
sha256: "3dac9aecf2c3991d09b9cdde4f98ded7b30804a88a0d7e4e7e1678e78d6b97f4" sha256: "13b41f318e2a5751c3169137103b60c584297353d4b1761b66029bae6411fe46"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.24.1" version: "1.24.3"
test_api: test_api:
dependency: transitive dependency: transitive
description: description:
name: test_api name: test_api
sha256: eb6ac1540b26de412b3403a163d919ba86f6a973fe6cc50ae3541b80092fdcfb sha256: "75760ffd7786fffdfb9597c35c5b27eaeec82be8edfb6d71d32651128ed7aab8"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.5.1" version: "0.6.0"
test_core: test_core:
dependency: transitive dependency: transitive
description: description:
name: test_core name: test_core
sha256: "5138dbffb77b2289ecb12b81c11ba46036590b72a64a7a90d6ffb880f1a29e93" sha256: "99806e9e6d95c7b059b7a0fc08f07fc53fabe54a829497f0d9676299f1e8637e"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.5.1" version: "0.5.3"
timezone: timezone:
dependency: transitive dependency: transitive
description: description:
@ -1144,18 +1160,18 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: url_launcher name: url_launcher
sha256: eb1e00ab44303d50dd487aab67ebc575456c146c6af44422f9c13889984c00f3 sha256: "781bd58a1eb16069412365c98597726cd8810ae27435f04b3b4d3a470bacd61e"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "6.1.11" version: "6.1.12"
url_launcher_android: url_launcher_android:
dependency: transitive dependency: transitive
description: description:
name: url_launcher_android name: url_launcher_android
sha256: "1a5848f598acc5b7d8f7c18b8cb834ab667e59a13edc3c93e9d09cf38cc6bc87" sha256: "3dd2388cc0c42912eee04434531a26a82512b9cb1827e0214430c9bcbddfe025"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "6.0.34" version: "6.0.38"
url_launcher_ios: url_launcher_ios:
dependency: transitive dependency: transitive
description: description:
@ -1176,34 +1192,34 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: url_launcher_macos name: url_launcher_macos
sha256: "91ee3e75ea9dadf38036200c5d3743518f4a5eb77a8d13fda1ee5764373f185e" sha256: "1c4fdc0bfea61a70792ce97157e5cc17260f61abbe4f39354513f39ec6fd73b1"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.0.5" version: "3.0.6"
url_launcher_platform_interface: url_launcher_platform_interface:
dependency: transitive dependency: transitive
description: description:
name: url_launcher_platform_interface name: url_launcher_platform_interface
sha256: "6c9ca697a5ae218ce56cece69d46128169a58aa8653c1b01d26fcd4aad8c4370" sha256: bfdfa402f1f3298637d71ca8ecfe840b4696698213d5346e9d12d4ab647ee2ea
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.1.2" version: "2.1.3"
url_launcher_web: url_launcher_web:
dependency: transitive dependency: transitive
description: description:
name: url_launcher_web name: url_launcher_web
sha256: "81fe91b6c4f84f222d186a9d23c73157dc4c8e1c71489c4d08be1ad3b228f1aa" sha256: cc26720eefe98c1b71d85f9dc7ef0cada5132617046369d9dc296b3ecaa5cbb4
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.0.16" version: "2.0.18"
url_launcher_windows: url_launcher_windows:
dependency: transitive dependency: transitive
description: description:
name: url_launcher_windows name: url_launcher_windows
sha256: "254708f17f7c20a9c8c471f67d86d76d4a3f9c1591aad1e15292008aceb82771" sha256: "7967065dd2b5fccc18c653b97958fdf839c5478c28e767c61ee879f4e7882422"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.0.6" version: "3.0.7"
uuid: uuid:
dependency: transitive dependency: transitive
description: description:
@ -1224,18 +1240,18 @@ packages:
dependency: "direct dev" dependency: "direct dev"
description: description:
name: very_good_analysis name: very_good_analysis
sha256: "5f77d7c00d6010d8ad93ac5d91ecc851c216bcc1e7a51e56c3c01b27152453bb" sha256: "5e4ea72d2a9188630f0dd8f120a541de730090ef8863243fedca8267a84508b8"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "5.0.0" version: "5.0.0+1"
vm_service: vm_service:
dependency: transitive dependency: transitive
description: description:
name: vm_service name: vm_service
sha256: f6deed8ed625c52864792459709183da231ebf66ff0cf09e69b573227c377efe sha256: c620a6f783fa22436da68e42db7ebbf18b8c44b9a46ab911f666ff09ffd9153f
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "11.3.0" version: "11.7.1"
wakelock: wakelock:
dependency: "direct main" dependency: "direct main"
description: description:
@ -1284,6 +1300,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.1.0" version: "1.1.0"
web:
dependency: transitive
description:
name: web
sha256: dc8ccd225a2005c1be616fe02951e2e342092edf968cf0844220383757ef8f10
url: "https://pub.dev"
source: hosted
version: "0.1.4-beta"
web_socket_channel: web_socket_channel:
dependency: transitive dependency: transitive
description: description:
@ -1312,42 +1336,42 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: webview_flutter name: webview_flutter
sha256: "1a37bdbaaf5fbe09ad8579ab09ecfd473284ce482f900b5aea27cf834386a567" sha256: "789d52bd789373cc1e100fb634af2127e86c99cf9abde09499743270c5de8d00"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "4.2.0" version: "4.2.2"
webview_flutter_android: webview_flutter_android:
dependency: transitive dependency: transitive
description: description:
name: webview_flutter_android name: webview_flutter_android
sha256: "1acea8def62592123e2fbbca164ed8681a98a890bdcbb88f916d5b4a22687759" sha256: bca797abba472868655b5f1a6029c1132385685ee9db4713cb0e7f33076210c6
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.7.0" version: "3.9.3"
webview_flutter_platform_interface: webview_flutter_platform_interface:
dependency: transitive dependency: transitive
description: description:
name: webview_flutter_platform_interface name: webview_flutter_platform_interface
sha256: "78715dc442b7849dbde74e92bb67de1cecf5addf95531c5fb474e72f5fe9a507" sha256: "0ca3cfcc6781a7de701d580917af4a9efc4e3e129f8ead95a80587f0a749480a"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.3.0" version: "2.5.0"
webview_flutter_wkwebview: webview_flutter_wkwebview:
dependency: transitive dependency: transitive
description: description:
name: webview_flutter_wkwebview name: webview_flutter_wkwebview
sha256: "4646bb68297803bdbb96d46853e8fcb560d6cb5e04153fa64581535767875dfe" sha256: ed749f94ac9e814d04a258a9255cf69cfa4cc6006ff59542aea7fb4590144972
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.4.3" version: "3.7.3"
win32: win32:
dependency: "direct overridden" dependency: "direct overridden"
description: description:
name: win32 name: win32
sha256: "6ca3aaab1790eeb1f5cad232e33d9c53ba66e884dd3e7686c4e730bffc45f1a3" sha256: f2add6fa510d3ae152903412227bda57d0d5a8da61d2c39c1fb022c9429a41c0
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "5.0.2" version: "5.0.6"
win32_registry: win32_registry:
dependency: transitive dependency: transitive
description: description:
@ -1368,10 +1392,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: xdg_directories name: xdg_directories
sha256: bd512f03919aac5f1313eb8249f223bacf4927031bf60b02601f81f687689e86 sha256: f0c26453a2d47aa4c2570c6a033246a3fc62da2fe23c7ffdd0a7495086dc0247
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.2.0+3" version: "1.0.2"
xml: xml:
dependency: transitive dependency: transitive
description: description:
@ -1389,5 +1413,5 @@ packages:
source: hosted source: hosted
version: "3.1.2" version: "3.1.2"
sdks: sdks:
dart: ">=3.0.0 <4.0.0" dart: ">=3.1.0-185.0.dev <4.0.0"
flutter: ">=3.10.3" flutter: ">=3.13.0"

View File

@ -1,11 +1,11 @@
name: hacki name: hacki
description: A Hacker News reader. description: A Hacker News reader.
version: 1.7.2+113 version: 1.8.3+119
publish_to: none publish_to: none
environment: environment:
sdk: ">=3.0.0 <4.0.0" sdk: ">=3.0.0 <4.0.0"
flutter: "3.10.3" flutter: "3.13.0"
dependencies: dependencies:
adaptive_theme: ^3.2.0 adaptive_theme: ^3.2.0
@ -27,11 +27,11 @@ dependencies:
sdk: flutter sdk: flutter
flutter_bloc: ^8.1.2 flutter_bloc: ^8.1.2
flutter_cache_manager: ^3.3.0 flutter_cache_manager: ^3.3.0
flutter_email_sender: ^5.2.0 flutter_email_sender: ^6.0.1
flutter_fadein: ^2.0.0 flutter_fadein: ^2.0.0
flutter_feather_icons: 2.0.0+1 flutter_feather_icons: 2.0.0+1
flutter_inappwebview: ^5.7.2+3 flutter_inappwebview: ^5.7.2+3
flutter_local_notifications: ^14.0.1 flutter_local_notifications: ^15.1.0+1
flutter_secure_storage: ^8.0.0 flutter_secure_storage: ^8.0.0
flutter_siri_suggestions: ^2.1.0 flutter_siri_suggestions: ^2.1.0
flutter_slidable: ^3.0.0 flutter_slidable: ^3.0.0
@ -41,13 +41,13 @@ dependencies:
hive: ^2.2.3 hive: ^2.2.3
html: ^0.15.1 html: ^0.15.1
html_unescape: ^2.0.0 html_unescape: ^2.0.0
http: ^0.13.5 http: ^1.1.0
hydrated_bloc: ^9.1.0 hydrated_bloc: ^9.1.0
in_app_review: in_app_review:
path: components/in_app_review path: components/in_app_review
intl: ^0.18.0 intl: ^0.18.0
linkify: ^5.0.0 linkify: ^5.0.0
logger: ^1.3.0 logger: ^2.0.1
memoize: ^3.0.0 memoize: ^3.0.0
package_info_plus: ^4.0.0 package_info_plus: ^4.0.0
path: ^1.8.2 path: ^1.8.2
@ -58,6 +58,8 @@ dependencies:
git: git:
url: https://github.com/livinglist/flutter_pulltorefresh url: https://github.com/livinglist/flutter_pulltorefresh
ref: master ref: master
qr_code_scanner: ^1.0.1
qr_flutter: ^4.1.0
receive_sharing_intent: ^1.4.5 receive_sharing_intent: ^1.4.5
responsive_builder: ^0.7.0 responsive_builder: ^0.7.0
rxdart: ^0.27.7 rxdart: ^0.27.7
@ -67,7 +69,7 @@ dependencies:
shared_preferences: ^2.0.17 shared_preferences: ^2.0.17
shared_preferences_android: ^2.0.15 shared_preferences_android: ^2.0.15
shared_preferences_foundation: ^2.1.3 shared_preferences_foundation: ^2.1.3
shimmer: ^2.0.0 shimmer: ^3.0.0
synced_shared_preferences: synced_shared_preferences:
path: components/synced_shared_preferences path: components/synced_shared_preferences
universal_platform: ^1.0.0+1 universal_platform: ^1.0.0+1
@ -87,7 +89,7 @@ dev_dependencies:
sdk: flutter sdk: flutter
integration_test: integration_test:
sdk: flutter sdk: flutter
mocktail: ^0.3.0 mocktail: ^1.0.0
very_good_analysis: ^5.0.0 very_good_analysis: ^5.0.0
flutter: flutter: