mirror of
https://github.com/Livinglist/Hacki.git
synced 2025-08-06 18:24:42 +08:00
Compare commits
1 Commits
Author | SHA1 | Date | |
---|---|---|---|
d1c8eed3de |
@ -6,6 +6,8 @@ import 'package:hacki/config/constants.dart';
|
|||||||
import 'package:hacki/styles/styles.dart';
|
import 'package:hacki/styles/styles.dart';
|
||||||
|
|
||||||
extension ContextExtension on BuildContext {
|
extension ContextExtension on BuildContext {
|
||||||
|
bool get isScreenReaderEnabled => MediaQuery.of(this).accessibleNavigation;
|
||||||
|
|
||||||
T? tryRead<T>() {
|
T? tryRead<T>() {
|
||||||
try {
|
try {
|
||||||
return read<T>();
|
return read<T>();
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
extension DateTimeExtension on DateTime {
|
extension DateTimeExtension on DateTime {
|
||||||
String toReadableString() {
|
String toTimeAgoString() {
|
||||||
final DateTime now = DateTime.now();
|
final DateTime now = DateTime.now();
|
||||||
final Duration diff = now.difference(this);
|
final Duration diff = now.difference(this);
|
||||||
if (diff.inDays > 365) {
|
if (diff.inDays > 365) {
|
||||||
|
@ -24,7 +24,7 @@ class Comment extends Item {
|
|||||||
|
|
||||||
final int level;
|
final int level;
|
||||||
|
|
||||||
String get metadata => '''by $by $postedDate''';
|
String get metadata => '''by $by $timeAgo''';
|
||||||
|
|
||||||
Comment copyWith({int? level}) {
|
Comment copyWith({int? level}) {
|
||||||
return Comment(
|
return Comment(
|
||||||
|
@ -82,8 +82,8 @@ class Item extends Equatable {
|
|||||||
final List<int> kids;
|
final List<int> kids;
|
||||||
final List<int> parts;
|
final List<int> parts;
|
||||||
|
|
||||||
String get postedDate =>
|
String get timeAgo =>
|
||||||
DateTime.fromMillisecondsSinceEpoch(time * 1000).toReadableString();
|
DateTime.fromMillisecondsSinceEpoch(time * 1000).toTimeAgoString();
|
||||||
|
|
||||||
bool get isPoll => type == 'poll';
|
bool get isPoll => type == 'poll';
|
||||||
|
|
||||||
|
@ -43,10 +43,13 @@ class Story extends Item {
|
|||||||
Story.fromJson(super.json) : super.fromJson();
|
Story.fromJson(super.json) : super.fromJson();
|
||||||
|
|
||||||
String get metadata =>
|
String get metadata =>
|
||||||
'''$score point${score > 1 ? 's' : ''} by $by $postedDate | $descendants comment${descendants > 1 ? 's' : ''}''';
|
'''$score point${score > 1 ? 's' : ''} by $by $timeAgo | $descendants comment${descendants > 1 ? 's' : ''}''';
|
||||||
|
|
||||||
|
String get screenReaderLabel =>
|
||||||
|
'''$title at $readableUrl by $by $timeAgo. This story has $score point${score > 1 ? 's' : ''} and $descendants comment${descendants > 1 ? 's' : ''}''';
|
||||||
|
|
||||||
String get simpleMetadata =>
|
String get simpleMetadata =>
|
||||||
'''$score point${score > 1 ? 's' : ''} $descendants comment${descendants > 1 ? 's' : ''} $postedDate''';
|
'''$score point${score > 1 ? 's' : ''} $descendants comment${descendants > 1 ? 's' : ''} $timeAgo''';
|
||||||
|
|
||||||
String get readableUrl {
|
String get readableUrl {
|
||||||
final Uri url = Uri.parse(this.url);
|
final Uri url = Uri.parse(this.url);
|
||||||
@ -55,10 +58,5 @@ class Story extends Item {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() {
|
String toString() => 'Story $id';
|
||||||
// final String prettyString =
|
|
||||||
// const JsonEncoder.withIndent(' ').convert(this);
|
|
||||||
// return 'Story $prettyString';
|
|
||||||
return 'Story $id';
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -24,9 +24,7 @@ class LinkIconButton extends StatelessWidget {
|
|||||||
featureId: Constants.featureOpenStoryInWebView,
|
featureId: Constants.featureOpenStoryInWebView,
|
||||||
title: Text('Open in Browser'),
|
title: Text('Open in Browser'),
|
||||||
description: Text(
|
description: Text(
|
||||||
'Want more than just reading and replying? '
|
'''You can tap here to open this story in browser.''',
|
||||||
'You can tap here to open this story in a '
|
|
||||||
'browser.',
|
|
||||||
style: TextStyle(fontSize: TextDimens.pt16),
|
style: TextStyle(fontSize: TextDimens.pt16),
|
||||||
),
|
),
|
||||||
child: Icon(
|
child: Icon(
|
||||||
|
@ -286,7 +286,7 @@ class _ParentItemSection extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
const Spacer(),
|
const Spacer(),
|
||||||
Text(
|
Text(
|
||||||
state.item.postedDate,
|
state.item.timeAgo,
|
||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
color: Palette.grey,
|
color: Palette.grey,
|
||||||
),
|
),
|
||||||
|
@ -118,7 +118,7 @@ class InboxView extends StatelessWidget {
|
|||||||
Row(
|
Row(
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
Text(
|
Text(
|
||||||
e.postedDate,
|
e.timeAgo,
|
||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
color: Palette.grey,
|
color: Palette.grey,
|
||||||
),
|
),
|
||||||
|
@ -152,7 +152,7 @@ class CommentTile extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
const Spacer(),
|
const Spacer(),
|
||||||
Text(
|
Text(
|
||||||
comment.postedDate,
|
comment.timeAgo,
|
||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
color: Palette.grey,
|
color: Palette.grey,
|
||||||
),
|
),
|
||||||
|
@ -317,6 +317,7 @@ class SelectableLinkify extends StatelessWidget {
|
|||||||
selectionControls: selectionControls,
|
selectionControls: selectionControls,
|
||||||
onSelectionChanged: onSelectionChanged,
|
onSelectionChanged: onSelectionChanged,
|
||||||
contextMenuBuilder: contextMenuBuilder,
|
contextMenuBuilder: contextMenuBuilder,
|
||||||
|
semanticsLabel: text,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -47,6 +47,7 @@ class ItemText extends StatelessWidget {
|
|||||||
editableTextState,
|
editableTextState,
|
||||||
item: item,
|
item: item,
|
||||||
),
|
),
|
||||||
|
semanticsLabel: item.text,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
return SelectableLinkify(
|
return SelectableLinkify(
|
||||||
|
@ -200,7 +200,7 @@ class ItemsListView<T extends Item> extends StatelessWidget {
|
|||||||
Row(
|
Row(
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
Text(
|
Text(
|
||||||
e.postedDate,
|
e.timeAgo,
|
||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
color: Palette.grey,
|
color: Palette.grey,
|
||||||
),
|
),
|
||||||
|
@ -52,15 +52,18 @@ class _OnboardingViewState extends State<OnboardingView> {
|
|||||||
children: const <Widget>[
|
children: const <Widget>[
|
||||||
_PageViewChild(
|
_PageViewChild(
|
||||||
path: Constants.commentTileRightSlidePath,
|
path: Constants.commentTileRightSlidePath,
|
||||||
description: 'Swipe right to leave a comment or vote.',
|
description:
|
||||||
|
'''Swipe right to leave a comment, vote, and more.''',
|
||||||
),
|
),
|
||||||
_PageViewChild(
|
_PageViewChild(
|
||||||
path: Constants.commentTileLeftSlidePath,
|
path: Constants.commentTileLeftSlidePath,
|
||||||
description: 'Swipe left to view all the parent comments.',
|
description:
|
||||||
|
'''Swipe left to view all the ancestor comments.''',
|
||||||
),
|
),
|
||||||
_PageViewChild(
|
_PageViewChild(
|
||||||
path: Constants.commentTileTopTapPath,
|
path: Constants.commentTileTopTapPath,
|
||||||
description: 'Tap on the top of comment tile to collapse.',
|
description:
|
||||||
|
'''Tap on anywhere inside a comment tile to collapse.''',
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
@ -33,7 +33,9 @@ class StoryTile extends StatelessWidget {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
if (showWebPreview) {
|
if (showWebPreview) {
|
||||||
final double height = context.storyTileHeight;
|
final double height = context.storyTileHeight;
|
||||||
return TapDownWrapper(
|
return Semantics(
|
||||||
|
label: story.screenReaderLabel,
|
||||||
|
child: TapDownWrapper(
|
||||||
onTap: onTap,
|
onTap: onTap,
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.symmetric(
|
padding: const EdgeInsets.symmetric(
|
||||||
@ -43,7 +45,8 @@ class StoryTile extends StatelessWidget {
|
|||||||
child: LinkPreview(
|
child: LinkPreview(
|
||||||
story: story,
|
story: story,
|
||||||
link: story.url,
|
link: story.url,
|
||||||
offlineReading: context.read<StoriesBloc>().state.offlineReading,
|
offlineReading:
|
||||||
|
context.read<StoriesBloc>().state.offlineReading,
|
||||||
placeholderWidget: _LinkPreviewPlaceholder(
|
placeholderWidget: _LinkPreviewPlaceholder(
|
||||||
height: height,
|
height: height,
|
||||||
),
|
),
|
||||||
@ -64,9 +67,12 @@ class StoryTile extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
return InkWell(
|
return Semantics(
|
||||||
|
label: story.screenReaderLabel,
|
||||||
|
child: InkWell(
|
||||||
onTap: onTap,
|
onTap: onTap,
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.only(left: Dimens.pt12),
|
padding: const EdgeInsets.only(left: Dimens.pt12),
|
||||||
@ -130,6 +136,7 @@ class StoryTile extends StatelessWidget {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1359,4 +1359,4 @@ packages:
|
|||||||
version: "3.1.1"
|
version: "3.1.1"
|
||||||
sdks:
|
sdks:
|
||||||
dart: ">=2.19.0 <3.0.0"
|
dart: ">=2.19.0 <3.0.0"
|
||||||
flutter: ">=3.7.5"
|
flutter: ">=3.7.6"
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
name: hacki
|
name: hacki
|
||||||
description: A Hacker News reader.
|
description: A Hacker News reader.
|
||||||
version: 1.3.1+100
|
version: 1.3.2+101
|
||||||
publish_to: none
|
publish_to: none
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
sdk: ">=2.17.0 <3.0.0"
|
sdk: ">=2.17.0 <3.0.0"
|
||||||
flutter: "3.7.5"
|
flutter: "3.7.6"
|
||||||
|
|
||||||
dependencies:
|
dependencies:
|
||||||
adaptive_theme: ^3.0.0
|
adaptive_theme: ^3.0.0
|
||||||
|
Submodule submodules/flutter updated: c07f788888...12cb4eb7a0
Reference in New Issue
Block a user