mirror of
https://github.com/Livinglist/Hacki.git
synced 2025-08-06 18:24:42 +08:00
Compare commits
2 Commits
Author | SHA1 | Date | |
---|---|---|---|
1e5af07691 | |||
ecf8c902dc |
4
.github/workflows/commit_check.yml
vendored
4
.github/workflows/commit_check.yml
vendored
@ -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 .
|
||||
|
2
.github/workflows/publish_ios.yml
vendored
2
.github/workflows/publish_ios.yml
vendored
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
0
fastlane/metadata/android/en-US/changelogs/81.txt
Normal file
0
fastlane/metadata/android/en-US/changelogs/81.txt
Normal 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
|
||||
|
@ -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 = (
|
||||
);
|
||||
|
@ -74,5 +74,7 @@
|
||||
</array>
|
||||
<key>ITSAppUsesNonExemptEncryption</key>
|
||||
<false/>
|
||||
<key>UIApplicationSupportsIndirectInputEvents</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
|
@ -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());
|
||||
}
|
||||
|
||||
|
@ -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 =
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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.'),
|
||||
|
@ -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>[
|
||||
|
@ -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,
|
||||
|
@ -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>[
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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'),
|
||||
|
@ -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) {
|
||||
|
@ -650,6 +650,7 @@ class _ProfileScreenState extends State<ProfileScreen>
|
||||
final PackageInfo packageInfo = await PackageInfo.fromPlatform();
|
||||
final String version = packageInfo.version;
|
||||
|
||||
if (mounted) {
|
||||
showAboutDialog(
|
||||
context: context,
|
||||
applicationName: 'Hacki',
|
||||
@ -701,7 +702,9 @@ class _ProfileScreenState extends State<ProfileScreen>
|
||||
),
|
||||
ElevatedButton(
|
||||
onPressed: () => LinkUtil.launch(
|
||||
Platform.isIOS ? Constants.appStoreLink : Constants.googlePlayLink,
|
||||
Platform.isIOS
|
||||
? Constants.appStoreLink
|
||||
: Constants.googlePlayLink,
|
||||
),
|
||||
child: Row(
|
||||
children: const <Widget>[
|
||||
@ -734,6 +737,7 @@ class _ProfileScreenState extends State<ProfileScreen>
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void onCommentTapped(Comment comment, {VoidCallback? then}) {
|
||||
throttle.run(() {
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
),
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
|
@ -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),
|
||||
),
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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';
|
||||
|
@ -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;
|
||||
}
|
||||
|
727
pubspec.lock
727
pubspec.lock
File diff suppressed because it is too large
Load Diff
@ -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
|
||||
|
Submodule submodules/flutter updated: 135454af32...b06b8b2710
@ -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));
|
||||
|
Reference in New Issue
Block a user