From f44c0f60a53bb1370e00b75b39a87257ad16f17b Mon Sep 17 00:00:00 2001 From: krawieck Date: Tue, 1 Sep 2020 14:17:56 +0200 Subject: [PATCH 01/22] change some expressions to IIFEs --- lib/widgets/comment.dart | 49 +++++++++++++++++++++------------------- 1 file changed, 26 insertions(+), 23 deletions(-) diff --git a/lib/widgets/comment.dart b/lib/widgets/comment.dart index be479bc..7a3ea1e 100644 --- a/lib/widgets/comment.dart +++ b/lib/widgets/comment.dart @@ -25,30 +25,33 @@ class Comment extends StatelessWidget { var comment = commentTree.comment; // decide which username to use - var username; - if (comment.creatorPreferredUsername != null && - comment.creatorPreferredUsername != '') { - username = comment.creatorPreferredUsername; - } else { - username = '@${comment.creatorName}'; - } + final username = () { + if (comment.creatorPreferredUsername != null && + comment.creatorPreferredUsername != '') { + return comment.creatorPreferredUsername; + } else { + return '@${comment.creatorName}'; + } + }(); + + final body = () { + if (comment.deleted) { + return Flexible( + child: Text( + 'comment deleted by creator', + style: TextStyle(fontStyle: FontStyle.italic), + )); + } else if (comment.removed) { + return Flexible( + child: Text( + 'comment deleted by moderator', + style: TextStyle(fontStyle: FontStyle.italic), + )); + } else { + return Flexible(child: MarkdownText(commentTree.comment.content)); + } + }(); - var body; - if (comment.deleted) { - body = Flexible( - child: Text( - 'comment deleted by creator', - style: TextStyle(fontStyle: FontStyle.italic), - )); - } else if (comment.removed) { - body = Flexible( - child: Text( - 'comment deleted by moderator', - style: TextStyle(fontStyle: FontStyle.italic), - )); - } else { - body = Flexible(child: MarkdownText(commentTree.comment.content)); - } return Column( children: [ Container( From f5a2d3a4e1aa7738372731958cefd874b9dcd8b3 Mon Sep 17 00:00:00 2001 From: krawieck Date: Tue, 1 Sep 2020 19:35:06 +0200 Subject: [PATCH 02/22] add some ios junk --- ios/Flutter/.last_build_id | 1 + ios/Flutter/Debug.xcconfig | 1 + ios/Flutter/Release.xcconfig | 1 + ios/Podfile | 41 ++++++++ ios/Podfile.lock | 55 +++++++++++ ios/Runner.xcodeproj/project.pbxproj | 93 +++++++++++++++++-- .../xcshareddata/xcschemes/Runner.xcscheme | 8 +- .../contents.xcworkspacedata | 3 + 8 files changed, 189 insertions(+), 14 deletions(-) create mode 100644 ios/Flutter/.last_build_id create mode 100644 ios/Podfile create mode 100644 ios/Podfile.lock diff --git a/ios/Flutter/.last_build_id b/ios/Flutter/.last_build_id new file mode 100644 index 0000000..2e00983 --- /dev/null +++ b/ios/Flutter/.last_build_id @@ -0,0 +1 @@ +20ad19f2b9a812ac7774ca58ddf04b2e \ No newline at end of file diff --git a/ios/Flutter/Debug.xcconfig b/ios/Flutter/Debug.xcconfig index 592ceee..e8efba1 100644 --- a/ios/Flutter/Debug.xcconfig +++ b/ios/Flutter/Debug.xcconfig @@ -1 +1,2 @@ +#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" #include "Generated.xcconfig" diff --git a/ios/Flutter/Release.xcconfig b/ios/Flutter/Release.xcconfig index 592ceee..399e934 100644 --- a/ios/Flutter/Release.xcconfig +++ b/ios/Flutter/Release.xcconfig @@ -1 +1,2 @@ +#include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" #include "Generated.xcconfig" diff --git a/ios/Podfile b/ios/Podfile new file mode 100644 index 0000000..1e8c3c9 --- /dev/null +++ b/ios/Podfile @@ -0,0 +1,41 @@ +# Uncomment this line to define a global platform for your project +# platform :ios, '9.0' + +# CocoaPods analytics sends network stats synchronously affecting flutter build latency. +ENV['COCOAPODS_DISABLE_STATS'] = 'true' + +project 'Runner', { + 'Debug' => :debug, + 'Profile' => :release, + 'Release' => :release, +} + +def flutter_root + generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) + unless File.exist?(generated_xcode_build_settings_path) + raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" + end + + File.foreach(generated_xcode_build_settings_path) do |line| + matches = line.match(/FLUTTER_ROOT\=(.*)/) + return matches[1].strip if matches + end + raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" +end + +require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) + +flutter_ios_podfile_setup + +target 'Runner' do + use_frameworks! + use_modular_headers! + + flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) +end + +post_install do |installer| + installer.pods_project.targets.each do |target| + flutter_additional_ios_build_settings(target) + end +end diff --git a/ios/Podfile.lock b/ios/Podfile.lock new file mode 100644 index 0000000..ac80ad7 --- /dev/null +++ b/ios/Podfile.lock @@ -0,0 +1,55 @@ +PODS: + - esys_flutter_share (0.0.1): + - Flutter + - Flutter (1.0.0) + - FMDB (2.7.5): + - FMDB/standard (= 2.7.5) + - FMDB/standard (2.7.5) + - path_provider (0.0.1): + - Flutter + - shared_preferences (0.0.1): + - Flutter + - sqflite (0.0.1): + - Flutter + - FMDB (~> 2.7.2) + - url_launcher (0.0.1): + - Flutter + +DEPENDENCIES: + - esys_flutter_share (from `.symlinks/plugins/esys_flutter_share/ios`) + - Flutter (from `Flutter`) + - path_provider (from `.symlinks/plugins/path_provider/ios`) + - shared_preferences (from `.symlinks/plugins/shared_preferences/ios`) + - sqflite (from `.symlinks/plugins/sqflite/ios`) + - url_launcher (from `.symlinks/plugins/url_launcher/ios`) + +SPEC REPOS: + trunk: + - FMDB + +EXTERNAL SOURCES: + esys_flutter_share: + :path: ".symlinks/plugins/esys_flutter_share/ios" + Flutter: + :path: Flutter + path_provider: + :path: ".symlinks/plugins/path_provider/ios" + shared_preferences: + :path: ".symlinks/plugins/shared_preferences/ios" + sqflite: + :path: ".symlinks/plugins/sqflite/ios" + url_launcher: + :path: ".symlinks/plugins/url_launcher/ios" + +SPEC CHECKSUMS: + esys_flutter_share: 403498dab005b36ce1f8d7aff377e81f0621b0b4 + Flutter: 0e3d915762c693b495b44d77113d4970485de6ec + FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a + path_provider: abfe2b5c733d04e238b0d8691db0cfd63a27a93c + shared_preferences: af6bfa751691cdc24be3045c43ec037377ada40d + sqflite: 4001a31ff81d210346b500c55b17f4d6c7589dd0 + url_launcher: 6fef411d543ceb26efce54b05a0a40bfd74cbbef + +PODFILE CHECKSUM: aafe91acc616949ddb318b77800a7f51bffa2a4c + +COCOAPODS: 1.9.3 diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index 7ab9911..eb5416f 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -3,7 +3,7 @@ archiveVersion = 1; classes = { }; - objectVersion = 46; + objectVersion = 50; objects = { /* Begin PBXBuildFile section */ @@ -13,6 +13,7 @@ 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; + F627D0FEEE0CC42B20D97D4D /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4E5591CE3BD9F89AE791097F /* Pods_Runner.framework */; }; /* End PBXBuildFile section */ /* Begin PBXCopyFilesBuildPhase section */ @@ -31,7 +32,11 @@ /* Begin PBXFileReference section */ 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; + 20AF123CE6B282DF5FCC0E08 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; + 4E5591CE3BD9F89AE791097F /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 5D359FC3B8BF643CBF087D7C /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; + 5DC9EF56CF79F18EC6F8E97B /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; @@ -49,12 +54,31 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + F627D0FEEE0CC42B20D97D4D /* Pods_Runner.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 721C96BBF01C118C12E658F5 /* Pods */ = { + isa = PBXGroup; + children = ( + 20AF123CE6B282DF5FCC0E08 /* Pods-Runner.debug.xcconfig */, + 5D359FC3B8BF643CBF087D7C /* Pods-Runner.release.xcconfig */, + 5DC9EF56CF79F18EC6F8E97B /* Pods-Runner.profile.xcconfig */, + ); + path = Pods; + sourceTree = ""; + }; + 78D8D0D60D5196915B006F06 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 4E5591CE3BD9F89AE791097F /* Pods_Runner.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; 9740EEB11CF90186004384FC /* Flutter */ = { isa = PBXGroup; children = ( @@ -72,6 +96,8 @@ 9740EEB11CF90186004384FC /* Flutter */, 97C146F01CF9000F007C117D /* Runner */, 97C146EF1CF9000F007C117D /* Products */, + 721C96BBF01C118C12E658F5 /* Pods */, + 78D8D0D60D5196915B006F06 /* Frameworks */, ); sourceTree = ""; }; @@ -113,12 +139,14 @@ isa = PBXNativeTarget; buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; buildPhases = ( + 2C32CA1979B0B9EA89AB49DE /* [CP] Check Pods Manifest.lock */, 9740EEB61CF901F6004384FC /* Run Script */, 97C146EA1CF9000F007C117D /* Sources */, 97C146EB1CF9000F007C117D /* Frameworks */, 97C146EC1CF9000F007C117D /* Resources */, 9705A1C41CF9048500538489 /* Embed Frameworks */, 3B06AD1E1E4923F5004D2608 /* Thin Binary */, + ADBCA6764A9EF0DC6AA5E56E /* [CP] Embed Pods Frameworks */, ); buildRules = ( ); @@ -177,6 +205,28 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ + 2C32CA1979B0B9EA89AB49DE /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; @@ -205,6 +255,23 @@ shellPath = /bin/sh; shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; }; + ADBCA6764A9EF0DC6AA5E56E /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Embed Pods Frameworks"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ @@ -241,7 +308,6 @@ /* Begin XCBuildConfiguration section */ 249021D3217E4FDB00AE95B9 /* Profile */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_NONNULL = YES; @@ -297,13 +363,17 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = NMDSW6KGG7; ENABLE_BITCODE = NO; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", "$(PROJECT_DIR)/Flutter", ); INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); LIBRARY_SEARCH_PATHS = ( "$(inherited)", "$(PROJECT_DIR)/Flutter", @@ -318,7 +388,6 @@ }; 97C147031CF9000F007C117D /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_NONNULL = YES; @@ -374,7 +443,6 @@ }; 97C147041CF9000F007C117D /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_NONNULL = YES; @@ -418,7 +486,8 @@ MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = iphoneos; - SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; TARGETED_DEVICE_FAMILY = "1,2"; VALIDATE_PRODUCT = YES; }; @@ -431,13 +500,17 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = NMDSW6KGG7; ENABLE_BITCODE = NO; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", "$(PROJECT_DIR)/Flutter", ); INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); LIBRARY_SEARCH_PATHS = ( "$(inherited)", "$(PROJECT_DIR)/Flutter", @@ -458,13 +531,17 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = NMDSW6KGG7; ENABLE_BITCODE = NO; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", "$(PROJECT_DIR)/Flutter", ); INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); LIBRARY_SEARCH_PATHS = ( "$(inherited)", "$(PROJECT_DIR)/Flutter", diff --git a/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index a28140c..fb2dffc 100644 --- a/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -27,8 +27,6 @@ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" shouldUseLaunchSchemeArgsEnv = "YES"> - - - - + + - - + + From 82f2084b60b6c2ea450d3e78d3b06ee053e8bcf6 Mon Sep 17 00:00:00 2001 From: krawieck Date: Wed, 2 Sep 2020 00:05:42 +0200 Subject: [PATCH 03/22] Add FullPost and implement a fair bit of it --- lib/pages/full_post.dart | 99 ++++++++++++++++++++++++++++++++++++++++ lib/widgets/post.dart | 48 +++++++++++-------- 2 files changed, 127 insertions(+), 20 deletions(-) create mode 100644 lib/pages/full_post.dart diff --git a/lib/pages/full_post.dart b/lib/pages/full_post.dart new file mode 100644 index 0000000..cc27a13 --- /dev/null +++ b/lib/pages/full_post.dart @@ -0,0 +1,99 @@ +import 'package:esys_flutter_share/esys_flutter_share.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:lemmy_api_client/src/models/post.dart'; + +import '../widgets/comment_section.dart'; +import '../widgets/post.dart'; + +class FullPostPage extends HookWidget { + final Future fullPost; + final PostView post; + + FullPostPage(FullPost fullPost, {this.post}) + : fullPost = Future(() => fullPost); + FullPostPage.fromFuture(this.fullPost, {this.post}); + + void sharePost() => Share.text('Share post', post.apId, 'text/plain'); + + void savePost() { + // + } + + @override + Widget build(BuildContext context) { + // final post + var fullPostFuture = useFuture(this.fullPost); + + var fullPost = fullPostFuture.data; + + final savedIcon = () { + if (fullPost != null) { + if (fullPost.post.saved == null || !fullPost.post.saved) { + return Icons.bookmark_border; + } else { + return Icons.bookmark; + } + } + + if (post != null) { + if (post.saved == null || !post.saved) { + return Icons.bookmark_border; + } else { + return Icons.bookmark; + } + } + + return Icons.bookmark_border; + }(); + + return Scaffold( + appBar: AppBar( + leading: BackButton(), + actions: [ + IconButton(icon: Icon(Icons.share), onPressed: sharePost), + IconButton(icon: Icon(savedIcon), onPressed: savePost), + IconButton( + icon: Icon(Icons.more_vert), onPressed: () {}), // TODO: more menu + ], + ), + body: fullPost != null || post != null + // FUTURE SUCCESS + ? ListView( + physics: const AlwaysScrollableScrollPhysics(), + children: [ + if (fullPost != null) + Post(fullPost.post, fullPost: true) + else if (post != null) + Post(post, fullPost: true) + else + CircularProgressIndicator(), + if (fullPost != null) + CommentSection(fullPost.comments, + postCreatorId: fullPost.post.creatorId) + else + Container( + child: Center(child: CircularProgressIndicator()), + padding: EdgeInsets.only(top: 40), + ), + ], + ) + : fullPostFuture.error != null + // FUTURE FAILURE + ? Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon(Icons.error, size: 30), + Padding(padding: EdgeInsets.all(5)), + Text('ERROR: ${fullPostFuture.error.toString()}'), + ], + ), + ) + // FUTURE IN PROGRESS + : Container( + child: Center(child: CircularProgressIndicator()), + color: Theme.of(context).canvasColor), + ); + } +} diff --git a/lib/widgets/post.dart b/lib/widgets/post.dart index 8609e9d..5fb6b5a 100644 --- a/lib/widgets/post.dart +++ b/lib/widgets/post.dart @@ -6,6 +6,7 @@ import 'package:intl/intl.dart'; import 'package:lemmy_api_client/lemmy_api_client.dart'; import 'package:timeago/timeago.dart' as timeago; +import '../pages/full_post.dart'; import 'markdown_text.dart'; enum MediaType { @@ -28,11 +29,12 @@ MediaType whatType(String url) { class Post extends StatelessWidget { final PostView post; final String instanceUrl; + final bool fullPost; /// nullable final String postUrlDomain; - Post(this.post) + Post(this.post, {this.fullPost = false}) : instanceUrl = post.communityActorId.split('/')[2], postUrlDomain = post.url != null ? post.url.split('/')[2] : null; @@ -47,7 +49,10 @@ class Post extends StatelessWidget { } void _goToPost(BuildContext context) { - print('GO TO POST'); + final api = LemmyApi(instanceUrl).v1; + final p = api.getPost(id: post.id); + Navigator.of(context).push(MaterialPageRoute( + builder: (context) => FullPostPage.fromFuture(p, post: post))); } void _goToCommunity() { @@ -183,14 +188,15 @@ class Post extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.start, ), Spacer(), - Column( - children: [ - IconButton( - onPressed: _showMoreMenu, - icon: Icon(Icons.more_vert), - ) - ], - ) + if (!fullPost) + Column( + children: [ + IconButton( + onPressed: _showMoreMenu, + icon: Icon(Icons.more_vert), + ) + ], + ) ]), ), ]); @@ -314,15 +320,17 @@ class Post extends StatelessWidget { ), ), Spacer(), - IconButton( - icon: Icon(Icons.share), - onPressed: () => Share.text('Share post url', post.apId, - 'text/plain')), // TODO: find a way to mark it as url - IconButton( - icon: post.saved == true - ? Icon(Icons.bookmark) - : Icon(Icons.bookmark_border), - onPressed: _savePost), + if (!fullPost) + IconButton( + icon: Icon(Icons.share), + onPressed: () => Share.text('Share post url', post.apId, + 'text/plain')), // TODO: find a way to mark it as url + if (!fullPost) + IconButton( + icon: post.saved == true + ? Icon(Icons.bookmark) + : Icon(Icons.bookmark_border), + onPressed: _savePost), IconButton( icon: Icon(Icons.arrow_upward), onPressed: _upvotePost), Text(NumberFormat.compact().format(post.score)), @@ -339,7 +347,7 @@ class Post extends StatelessWidget { borderRadius: BorderRadius.all(Radius.circular(20)), ), child: InkWell( - onTap: () => _goToPost(context), + onTap: fullPost ? null : () => _goToPost(context), child: Column( children: [ info(), From 9e85fd5a2d93a7d1c1cf0f3cc77b2fe16b965f00 Mon Sep 17 00:00:00 2001 From: krawieck Date: Wed, 2 Sep 2020 13:47:45 +0200 Subject: [PATCH 04/22] Add util extension for calculating hot rank of comments --- lib/util/hot_rank.dart | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 lib/util/hot_rank.dart diff --git a/lib/util/hot_rank.dart b/lib/util/hot_rank.dart new file mode 100644 index 0000000..975e664 --- /dev/null +++ b/lib/util/hot_rank.dart @@ -0,0 +1,15 @@ +// import 'dart:core' show ab; +import 'dart:math' show log, max, pow; + +import 'package:lemmy_api_client/lemmy_api_client.dart'; + +double _calculateHotRank(int score, DateTime time) { + final elapsed = (time.difference(DateTime.now()).inMilliseconds).abs() / 36e5; + + // log instead of log10 in web version. does log == log10? + return (10000 * log(max(1, 3 + score))) / pow(elapsed + 2, 1.8); +} + +extension CommentHotRank on CommentView { + double get computedHotRank => _calculateHotRank(score, published); +} From fcf622dcfe120587a9aa93181c45ebfe829be4e9 Mon Sep 17 00:00:00 2001 From: krawieck Date: Wed, 2 Sep 2020 13:49:07 +0200 Subject: [PATCH 05/22] Add comment sorting with temporary dropdown --- lib/comment_tree.dart | 70 +++++++++++++++++++++++++++++ lib/widgets/comment.dart | 8 +++- lib/widgets/comment_section.dart | 76 +++++++++++++++++++++++++++----- 3 files changed, 142 insertions(+), 12 deletions(-) diff --git a/lib/comment_tree.dart b/lib/comment_tree.dart index d0da0da..4b61749 100644 --- a/lib/comment_tree.dart +++ b/lib/comment_tree.dart @@ -1,5 +1,16 @@ import 'package:lemmy_api_client/lemmy_api_client.dart'; +import 'util/hot_rank.dart'; + +enum CommentSortType { + hot, + top, + // ignore: constant_identifier_names + new_, + old, + chat, +} + class CommentTree { CommentView comment; List children; @@ -30,4 +41,63 @@ class CommentTree { var result = parents.map(gatherChildren).toList(); return result; } + + void sort(CommentSortType sortType) { + switch (sortType) { + case CommentSortType.chat: + throw Exception('i dont do this kinda stuff kido'); + case CommentSortType.hot: + return _sort((b, a) => + a.comment.computedHotRank.compareTo(b.comment.computedHotRank)); + case CommentSortType.new_: + return _sort( + (b, a) => a.comment.published.compareTo(b.comment.published)); + case CommentSortType.old: + return _sort( + (b, a) => b.comment.published.compareTo(a.comment.published)); + case CommentSortType.top: + return _sort((b, a) => a.comment.score.compareTo(b.comment.score)); + } + } + + void _sort(int compare(CommentTree a, CommentTree b)) { + children.sort(compare); + for (var el in children) { + el._sort(compare); + } + } + + static void sortList(CommentSortType sortType, List comms) { + switch (sortType) { + case CommentSortType.chat: + throw Exception('i dont do this kinda stuff kido'); + case CommentSortType.hot: + comms.sort((b, a) => + a.comment.computedHotRank.compareTo(b.comment.computedHotRank)); + for (var i = 0; i < comms.length; i++) { + comms[i].sort(sortType); + } + break; + case CommentSortType.new_: + comms + .sort((b, a) => a.comment.published.compareTo(b.comment.published)); + for (var i = 0; i < comms.length; i++) { + comms[i].sort(sortType); + } + break; + case CommentSortType.old: + comms + .sort((b, a) => b.comment.published.compareTo(a.comment.published)); + for (var i = 0; i < comms.length; i++) { + comms[i].sort(sortType); + } + break; + case CommentSortType.top: + comms.sort((b, a) => a.comment.score.compareTo(b.comment.score)); + for (var i = 0; i < comms.length; i++) { + comms[i].sort(sortType); + } + break; + } + } } diff --git a/lib/widgets/comment.dart b/lib/widgets/comment.dart index 7a3ea1e..627f317 100644 --- a/lib/widgets/comment.dart +++ b/lib/widgets/comment.dart @@ -1,7 +1,9 @@ import 'package:cached_network_image/cached_network_image.dart'; import 'package:flutter/material.dart'; +import 'package:timeago/timeago.dart' as timeago; import '../comment_tree.dart'; +import '../util/text_color.dart'; import 'markdown_text.dart'; class Comment extends StatelessWidget { @@ -22,7 +24,7 @@ class Comment extends StatelessWidget { @override Widget build(BuildContext context) { - var comment = commentTree.comment; + final comment = commentTree.comment; // decide which username to use final username = () { @@ -91,6 +93,8 @@ class Comment extends StatelessWidget { if (comment.bannedFromCommunity) CommentTag('BANNED FROM COMMUNITY', Colors.red), Spacer(), + Text(timeago.format(comment.published, locale: 'en_short')), + Text(' · '), Text(comment.score.toString()), ]), Row(children: [body]), @@ -137,7 +141,7 @@ class CommentTag extends StatelessWidget { padding: EdgeInsets.symmetric(horizontal: 3, vertical: 2), child: Text(text, style: TextStyle( - color: Colors.white, + color: textColorBasedOnBackground(bgColor), fontSize: Theme.of(context).textTheme.bodyText1.fontSize - 5, fontWeight: FontWeight.w800, )), diff --git a/lib/widgets/comment_section.dart b/lib/widgets/comment_section.dart index 3b73205..6b9bbad 100644 --- a/lib/widgets/comment_section.dart +++ b/lib/widgets/comment_section.dart @@ -16,16 +16,72 @@ class CommentSection extends HookWidget { assert(postCreatorId != null); @override - Widget build(BuildContext context) => Column(children: [ - // sorting menu goes here - if (comments.isEmpty) - Padding( - padding: EdgeInsets.symmetric(vertical: 50), - child: Text( - 'no comments yet', - style: TextStyle(fontStyle: FontStyle.italic), + Widget build(BuildContext context) { + var rawComms = useState(rawComments); + var comms = useState(comments); + var sorting = useState(CommentSortType.hot); + + return Column(children: [ + Padding( + padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 15), + child: Row( + children: [ + Container( + padding: const EdgeInsets.symmetric(vertical: 5, horizontal: 10), + decoration: BoxDecoration( + border: Border.all(color: Colors.black45), + borderRadius: BorderRadius.all(Radius.circular(10)), + ), + child: DropdownButton( + // TODO: change it to universal BottomModal + underline: Container(), + isDense: true, + // ignore: avoid_types_on_closure_parameters + onChanged: (CommentSortType val) { + if (val != sorting.value && val != CommentSortType.chat) { + CommentTree.sortList(val, comms.value); + } else { + rawComms.value + .sort((a, b) => a.published.compareTo(b.published)); + } + sorting.value = val; + }, + value: sorting.value, + items: [ + DropdownMenuItem( + child: Text('Hot'), value: CommentSortType.hot), + DropdownMenuItem( + child: Text('Top'), value: CommentSortType.top), + DropdownMenuItem( + child: Text('New'), value: CommentSortType.new_), + DropdownMenuItem( + child: Text('Old'), value: CommentSortType.old), + DropdownMenuItem( + child: Text('Chat'), value: CommentSortType.chat), + ], + ), ), + Spacer(), + ], + ), + ), + // sorting menu goes here + if (comments.isEmpty) + Padding( + padding: EdgeInsets.symmetric(vertical: 50), + child: Text( + 'no comments yet', + style: TextStyle(fontStyle: FontStyle.italic), ), - for (var com in comments) Comment(com, postCreatorId: postCreatorId), - ]); + ) + else if (sorting.value == CommentSortType.chat) + for (final com in rawComms.value) + Comment( + CommentTree(com), + postCreatorId: postCreatorId, + ) + else + for (var com in comms.value) Comment(com, postCreatorId: postCreatorId), + ]); + } } From 47116b1cb172b46daf9e2f329e89cc01f8453ed3 Mon Sep 17 00:00:00 2001 From: krawieck Date: Wed, 2 Sep 2020 23:05:34 +0200 Subject: [PATCH 06/22] Add link opening to post --- lib/widgets/post.dart | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/widgets/post.dart b/lib/widgets/post.dart index 5fb6b5a..7b1e1ca 100644 --- a/lib/widgets/post.dart +++ b/lib/widgets/post.dart @@ -7,6 +7,7 @@ import 'package:lemmy_api_client/lemmy_api_client.dart'; import 'package:timeago/timeago.dart' as timeago; import '../pages/full_post.dart'; +import '../url_launcher.dart'; import 'markdown_text.dart'; enum MediaType { @@ -42,6 +43,7 @@ class Post extends StatelessWidget { void _openLink() { print('OPEN LINK'); + urlLauncher(post.url); } void _goToUser() { From 4bc6164b644082ace927e3e7170d24b7ac31fdf2 Mon Sep 17 00:00:00 2001 From: krawieck Date: Wed, 2 Sep 2020 23:09:00 +0200 Subject: [PATCH 07/22] Restructure logic, comments are now sorted upon opening --- lib/comment_tree.dart | 18 ++++++++++++------ lib/widgets/comment_section.dart | 30 +++++++++++++++++------------- 2 files changed, 29 insertions(+), 19 deletions(-) diff --git a/lib/comment_tree.dart b/lib/comment_tree.dart index 4b61749..f8d6630 100644 --- a/lib/comment_tree.dart +++ b/lib/comment_tree.dart @@ -45,7 +45,8 @@ class CommentTree { void sort(CommentSortType sortType) { switch (sortType) { case CommentSortType.chat: - throw Exception('i dont do this kinda stuff kido'); + // throw Exception('i dont do this kinda stuff kido'); + return; case CommentSortType.hot: return _sort((b, a) => a.comment.computedHotRank.compareTo(b.comment.computedHotRank)); @@ -67,7 +68,8 @@ class CommentTree { } } - static void sortList(CommentSortType sortType, List comms) { + static List sortList( + CommentSortType sortType, List comms) { switch (sortType) { case CommentSortType.chat: throw Exception('i dont do this kinda stuff kido'); @@ -77,27 +79,31 @@ class CommentTree { for (var i = 0; i < comms.length; i++) { comms[i].sort(sortType); } - break; + return comms; + case CommentSortType.new_: comms .sort((b, a) => a.comment.published.compareTo(b.comment.published)); for (var i = 0; i < comms.length; i++) { comms[i].sort(sortType); } - break; + return comms; + case CommentSortType.old: comms .sort((b, a) => b.comment.published.compareTo(a.comment.published)); for (var i = 0; i < comms.length; i++) { comms[i].sort(sortType); } - break; + return comms; + case CommentSortType.top: comms.sort((b, a) => a.comment.score.compareTo(b.comment.score)); for (var i = 0; i < comms.length; i++) { comms[i].sort(sortType); } - break; + return comms; } + throw Exception('unreachable'); } } diff --git a/lib/widgets/comment_section.dart b/lib/widgets/comment_section.dart index 6b9bbad..8b7179b 100644 --- a/lib/widgets/comment_section.dart +++ b/lib/widgets/comment_section.dart @@ -10,16 +10,29 @@ class CommentSection extends HookWidget { final List rawComments; final List comments; final int postCreatorId; + final CommentSortType sortType; - CommentSection(this.rawComments, {@required this.postCreatorId}) - : comments = CommentTree.fromList(rawComments), + CommentSection( + List rawComments, { + @required this.postCreatorId, + this.sortType = CommentSortType.hot, + }) : comments = + CommentTree.sortList(sortType, CommentTree.fromList(rawComments)), + rawComments = rawComments + ..sort((b, a) => a.published.compareTo(b.published)), assert(postCreatorId != null); @override Widget build(BuildContext context) { + var sorting = useState(sortType); var rawComms = useState(rawComments); var comms = useState(comments); - var sorting = useState(CommentSortType.hot); + + void sortComments(CommentSortType sort) { + if (sort == sorting.value || sort == CommentSortType.chat) return; + + CommentTree.sortList(sort, comms.value); + } return Column(children: [ Padding( @@ -36,16 +49,7 @@ class CommentSection extends HookWidget { // TODO: change it to universal BottomModal underline: Container(), isDense: true, - // ignore: avoid_types_on_closure_parameters - onChanged: (CommentSortType val) { - if (val != sorting.value && val != CommentSortType.chat) { - CommentTree.sortList(val, comms.value); - } else { - rawComms.value - .sort((a, b) => a.published.compareTo(b.published)); - } - sorting.value = val; - }, + onChanged: sortComments, value: sorting.value, items: [ DropdownMenuItem( From b13508c0118afde656983d6ecfac175d509ffd69 Mon Sep 17 00:00:00 2001 From: krawieck Date: Wed, 2 Sep 2020 23:09:33 +0200 Subject: [PATCH 08/22] Add util for getting text color based on background --- lib/util/text_color.dart | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 lib/util/text_color.dart diff --git a/lib/util/text_color.dart b/lib/util/text_color.dart new file mode 100644 index 0000000..0a2f4de --- /dev/null +++ b/lib/util/text_color.dart @@ -0,0 +1,9 @@ +import 'package:flutter/material.dart'; + +Color textColorBasedOnBackground(Color color) { + if (color.computeLuminance() > 0.5) { + return Colors.black; + } else { + return Colors.white; + } +} From e44b6cf10f5bb3e430a46f0494342ff956f8ecb3 Mon Sep 17 00:00:00 2001 From: krawieck Date: Thu, 3 Sep 2020 00:01:04 +0200 Subject: [PATCH 09/22] Add comment actions --- lib/widgets/comment.dart | 72 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 71 insertions(+), 1 deletion(-) diff --git a/lib/widgets/comment.dart b/lib/widgets/comment.dart index 627f317..48e1d23 100644 --- a/lib/widgets/comment.dart +++ b/lib/widgets/comment.dart @@ -1,5 +1,6 @@ import 'package:cached_network_image/cached_network_image.dart'; import 'package:flutter/material.dart'; +import 'package:lemmy_api_client/lemmy_api_client.dart'; import 'package:timeago/timeago.dart' as timeago; import '../comment_tree.dart'; @@ -16,16 +17,34 @@ class Comment extends StatelessWidget { @required this.postCreatorId, }); + void _openMoreMenu() { + print('OPEN MORE MENU'); + } + void _goToUser() { print('GO TO USER'); } + void _save(bool save) { + print('SAVE COMMENT, $save'); + } + + void _reply() { + print('OPEN REPLY BOX'); + } + + void _vote(VoteType vote) { + print('COMMENT VOTE: ${vote.toString()}'); + } + bool get isOP => commentTree.comment.creatorId == postCreatorId; @override Widget build(BuildContext context) { final comment = commentTree.comment; + final saved = comment.saved ?? false; + // decide which username to use final username = () { if (comment.creatorPreferredUsername != null && @@ -100,7 +119,31 @@ class Comment extends StatelessWidget { Row(children: [body]), Row(children: [ Spacer(), - // actions go here + _CommentAction( + icon: Icons.more_horiz, + onPressed: _openMoreMenu, + tooltip: 'more', + ), + _CommentAction( + icon: saved ? Icons.bookmark : Icons.bookmark_border, + onPressed: () => _save(!saved), + tooltip: '${saved ? 'unsave' : 'save'} comment', + ), + _CommentAction( + icon: Icons.reply, + onPressed: _reply, + tooltip: 'reply', + ), + _CommentAction( + icon: Icons.arrow_upward, + onPressed: () => _vote(VoteType.up), + tooltip: 'upvote', + ), + _CommentAction( + icon: Icons.arrow_downward, + onPressed: () => _vote(VoteType.down), + tooltip: 'downvote', + ), ]) ], ), @@ -148,3 +191,30 @@ class CommentTag extends StatelessWidget { ), ); } + +class _CommentAction extends StatelessWidget { + final IconData icon; + final void Function() onPressed; + final String tooltip; + + const _CommentAction({ + Key key, + @required this.icon, + @required this.onPressed, + @required this.tooltip, + }) : super(key: key); + + @override + Widget build(BuildContext context) => IconButton( + constraints: BoxConstraints.tight(Size(32, 26)), + icon: Icon( + icon, + color: Theme.of(context).iconTheme.color.withAlpha(190), + ), + splashRadius: 25, + onPressed: onPressed, + iconSize: 22, + tooltip: tooltip, + padding: EdgeInsets.all(0), + ); +} From 3381e0c37514ee3ef403707ec58b3d7311e849e6 Mon Sep 17 00:00:00 2001 From: krawieck Date: Thu, 3 Sep 2020 00:07:07 +0200 Subject: [PATCH 10/22] Adjust color of link preview border to be more universal --- lib/widgets/post.dart | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/widgets/post.dart b/lib/widgets/post.dart index 7b1e1ca..201cf87 100644 --- a/lib/widgets/post.dart +++ b/lib/widgets/post.dart @@ -265,7 +265,9 @@ class Post extends StatelessWidget { onTap: _openLink, child: Container( decoration: BoxDecoration( - border: Border.all(width: 1), + border: Border.all( + width: 1, + color: Theme.of(context).iconTheme.color.withAlpha(170)), borderRadius: BorderRadius.circular(5)), child: Padding( padding: const EdgeInsets.all(10), From dec88a1d882ac861f9421b90ef1cd46fbad9d956 Mon Sep 17 00:00:00 2001 From: krawieck Date: Thu, 3 Sep 2020 00:10:36 +0200 Subject: [PATCH 11/22] make `CommentTag` private --- lib/widgets/comment.dart | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/widgets/comment.dart b/lib/widgets/comment.dart index 48e1d23..b44bd16 100644 --- a/lib/widgets/comment.dart +++ b/lib/widgets/comment.dart @@ -107,10 +107,10 @@ class Comment extends StatelessWidget { )), onLongPress: _goToUser, ), - if (isOP) CommentTag('OP', Theme.of(context).accentColor), - if (comment.banned) CommentTag('BANNED', Colors.red), + if (isOP) _CommentTag('OP', Theme.of(context).accentColor), + if (comment.banned) _CommentTag('BANNED', Colors.red), if (comment.bannedFromCommunity) - CommentTag('BANNED FROM COMMUNITY', Colors.red), + _CommentTag('BANNED FROM COMMUNITY', Colors.red), Spacer(), Text(timeago.format(comment.published, locale: 'en_short')), Text(' · '), @@ -167,11 +167,11 @@ class Comment extends StatelessWidget { } } -class CommentTag extends StatelessWidget { +class _CommentTag extends StatelessWidget { final String text; final Color bgColor; - const CommentTag(this.text, this.bgColor); + const _CommentTag(this.text, this.bgColor); @override Widget build(BuildContext context) => Padding( From 8e23e418bad473bff00ac736dab203d103bef122 Mon Sep 17 00:00:00 2001 From: krawieck Date: Thu, 3 Sep 2020 00:17:42 +0200 Subject: [PATCH 12/22] Fix bug with not updating --- lib/widgets/comment_section.dart | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/widgets/comment_section.dart b/lib/widgets/comment_section.dart index 8b7179b..1b1b262 100644 --- a/lib/widgets/comment_section.dart +++ b/lib/widgets/comment_section.dart @@ -29,9 +29,11 @@ class CommentSection extends HookWidget { var comms = useState(comments); void sortComments(CommentSortType sort) { - if (sort == sorting.value || sort == CommentSortType.chat) return; + if (sort != sorting.value && sort != CommentSortType.chat) { + CommentTree.sortList(sort, comms.value); + } - CommentTree.sortList(sort, comms.value); + sorting.value = sort; } return Column(children: [ From 7f0f0c11f13f4c9018c6fb1bfa966066c0a017f5 Mon Sep 17 00:00:00 2001 From: krawieck Date: Thu, 3 Sep 2020 00:18:29 +0200 Subject: [PATCH 13/22] Move InkWell one widget down --- lib/widgets/comment.dart | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/widgets/comment.dart b/lib/widgets/comment.dart index b44bd16..641e04d 100644 --- a/lib/widgets/comment.dart +++ b/lib/widgets/comment.dart @@ -80,10 +80,10 @@ class Comment extends StatelessWidget { children: [ Row(children: [ if (comment.creatorAvatar != null) - InkWell( - onTap: _goToUser, - child: Padding( - padding: const EdgeInsets.only(right: 5), + Padding( + padding: const EdgeInsets.only(right: 5), + child: InkWell( + onTap: _goToUser, child: CachedNetworkImage( imageUrl: comment.creatorAvatar, height: 20, @@ -112,9 +112,9 @@ class Comment extends StatelessWidget { if (comment.bannedFromCommunity) _CommentTag('BANNED FROM COMMUNITY', Colors.red), Spacer(), - Text(timeago.format(comment.published, locale: 'en_short')), - Text(' · '), Text(comment.score.toString()), + Text(' · '), + Text(timeago.format(comment.published, locale: 'en_short')), ]), Row(children: [body]), Row(children: [ From 54a4716febe57eb8d6d5cca8310a3416891d52e5 Mon Sep 17 00:00:00 2001 From: krawieck Date: Thu, 3 Sep 2020 00:35:08 +0200 Subject: [PATCH 14/22] Add ways to mark post Now post can be marked as: * stickied * nsfw * removed * deleted --- lib/widgets/post.dart | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/lib/widgets/post.dart b/lib/widgets/post.dart index 201cf87..60546a4 100644 --- a/lib/widgets/post.dart +++ b/lib/widgets/post.dart @@ -180,9 +180,17 @@ class Post extends StatelessWidget { TextSpan( text: ''' · ${timeago.format(post.published, locale: 'en_short')}'''), + if (post.locked) TextSpan(text: ' · 🔒'), + if (post.stickied) TextSpan(text: ' · 📌'), + if (post.nsfw) TextSpan(text: ' · '), + if (post.nsfw) + TextSpan( + text: 'NSFW', + style: TextStyle(color: Colors.red)), if (postUrlDomain != null) TextSpan(text: ' · $postUrlDomain'), - if (post.locked) TextSpan(text: ' · 🔒'), + if (post.removed) TextSpan(text: ' · REMOVED'), + if (post.deleted) TextSpan(text: ' · DELETED'), ], )) ]), From 11a2e40dfd65f8224d260fec9c4ec20cc25dff12 Mon Sep 17 00:00:00 2001 From: krawieck Date: Thu, 3 Sep 2020 12:23:46 +0200 Subject: [PATCH 15/22] Change `log` to `log10` and remove useless code --- lib/util/hot_rank.dart | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/lib/util/hot_rank.dart b/lib/util/hot_rank.dart index 975e664..309a9e5 100644 --- a/lib/util/hot_rank.dart +++ b/lib/util/hot_rank.dart @@ -1,13 +1,15 @@ -// import 'dart:core' show ab; -import 'dart:math' show log, max, pow; +import 'dart:math' show log, max, pow, ln10; import 'package:lemmy_api_client/lemmy_api_client.dart'; double _calculateHotRank(int score, DateTime time) { + log10(num x) => log(x) / ln10; + final elapsed = (time.difference(DateTime.now()).inMilliseconds).abs() / 36e5; // log instead of log10 in web version. does log == log10? - return (10000 * log(max(1, 3 + score))) / pow(elapsed + 2, 1.8); + + return (10000 * log10(max(1, 3 + score))) / pow(elapsed + 2, 1.8); } extension CommentHotRank on CommentView { From 8f6a1a6901d40fd071dd173a8572a67c90854ea8 Mon Sep 17 00:00:00 2001 From: krawieck Date: Thu, 3 Sep 2020 12:29:39 +0200 Subject: [PATCH 16/22] Add explenation why calculate hot rank and where it was taken from --- lib/util/hot_rank.dart | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/util/hot_rank.dart b/lib/util/hot_rank.dart index 309a9e5..6d56f4b 100644 --- a/lib/util/hot_rank.dart +++ b/lib/util/hot_rank.dart @@ -2,13 +2,17 @@ import 'dart:math' show log, max, pow, ln10; import 'package:lemmy_api_client/lemmy_api_client.dart'; +/// Calculates hot rank +/// because API always claims it's `0` +/// and web version of lemmy also calculates it when loading comments +/// +/// implementation taken from here: +/// https://github.com/LemmyNet/lemmy/blob/main/ui/src/utils.ts#L182-L203 double _calculateHotRank(int score, DateTime time) { log10(num x) => log(x) / ln10; final elapsed = (time.difference(DateTime.now()).inMilliseconds).abs() / 36e5; - // log instead of log10 in web version. does log == log10? - return (10000 * log10(max(1, 3 + score))) / pow(elapsed + 2, 1.8); } From 31e51c424fd9257498f9cdb4b0db096c9d4d51c7 Mon Sep 17 00:00:00 2001 From: krawieck Date: Thu, 3 Sep 2020 13:02:38 +0200 Subject: [PATCH 17/22] Move burden of fetching to full_post --- lib/pages/full_post.dart | 14 ++++++++++---- lib/widgets/post.dart | 4 +--- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/lib/pages/full_post.dart b/lib/pages/full_post.dart index cc27a13..a1677f0 100644 --- a/lib/pages/full_post.dart +++ b/lib/pages/full_post.dart @@ -1,6 +1,7 @@ import 'package:esys_flutter_share/esys_flutter_share.dart'; import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:lemmy_api_client/lemmy_api_client.dart'; import 'package:lemmy_api_client/src/models/post.dart'; import '../widgets/comment_section.dart'; @@ -10,9 +11,15 @@ class FullPostPage extends HookWidget { final Future fullPost; final PostView post; - FullPostPage(FullPost fullPost, {this.post}) - : fullPost = Future(() => fullPost); - FullPostPage.fromFuture(this.fullPost, {this.post}); + FullPostPage({@required int id, @required String instanceUrl}) + : assert(id != null), + assert(instanceUrl != null), + fullPost = LemmyApi(instanceUrl).v1.getPost(id: id), + post = null; + FullPostPage.fromPostView(this.post) + : fullPost = LemmyApi(post.communityActorId.split('/')[2]) + .v1 + .getPost(id: post.id); void sharePost() => Share.text('Share post', post.apId, 'text/plain'); @@ -22,7 +29,6 @@ class FullPostPage extends HookWidget { @override Widget build(BuildContext context) { - // final post var fullPostFuture = useFuture(this.fullPost); var fullPost = fullPostFuture.data; diff --git a/lib/widgets/post.dart b/lib/widgets/post.dart index 60546a4..d629c57 100644 --- a/lib/widgets/post.dart +++ b/lib/widgets/post.dart @@ -51,10 +51,8 @@ class Post extends StatelessWidget { } void _goToPost(BuildContext context) { - final api = LemmyApi(instanceUrl).v1; - final p = api.getPost(id: post.id); Navigator.of(context).push(MaterialPageRoute( - builder: (context) => FullPostPage.fromFuture(p, post: post))); + builder: (context) => FullPostPage.fromPostView(post))); } void _goToCommunity() { From b5277064a3300ca4795b3ee19de524b0b01f8920 Mon Sep 17 00:00:00 2001 From: krawieck Date: Thu, 3 Sep 2020 13:06:10 +0200 Subject: [PATCH 18/22] Add `Page` suffix to `Settings` --- lib/pages/profile_tab.dart | 2 +- lib/pages/settings.dart | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/pages/profile_tab.dart b/lib/pages/profile_tab.dart index 9a6e7d4..d05ce37 100644 --- a/lib/pages/profile_tab.dart +++ b/lib/pages/profile_tab.dart @@ -53,7 +53,7 @@ class UserProfileTab extends HookWidget { ), onPressed: () { Navigator.of(context) - .push(MaterialPageRoute(builder: (_) => Settings())); + .push(MaterialPageRoute(builder: (_) => SettingsPage())); }, ) ], diff --git a/lib/pages/settings.dart b/lib/pages/settings.dart index adb62a1..a030088 100644 --- a/lib/pages/settings.dart +++ b/lib/pages/settings.dart @@ -4,7 +4,7 @@ import 'package:provider/provider.dart'; import '../stores/config_store.dart'; -class Settings extends StatelessWidget { +class SettingsPage extends StatelessWidget { @override Widget build(BuildContext context) { var theme = Theme.of(context); From d49715fb642e7a5fd2edee26cb03f6106a97a251 Mon Sep 17 00:00:00 2001 From: krawieck Date: Thu, 3 Sep 2020 13:43:51 +0200 Subject: [PATCH 19/22] Revert "Add `Page` suffix to `Settings`" This reverts commit b5277064a3300ca4795b3ee19de524b0b01f8920. --- lib/pages/profile_tab.dart | 2 +- lib/pages/settings.dart | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/pages/profile_tab.dart b/lib/pages/profile_tab.dart index d05ce37..9a6e7d4 100644 --- a/lib/pages/profile_tab.dart +++ b/lib/pages/profile_tab.dart @@ -53,7 +53,7 @@ class UserProfileTab extends HookWidget { ), onPressed: () { Navigator.of(context) - .push(MaterialPageRoute(builder: (_) => SettingsPage())); + .push(MaterialPageRoute(builder: (_) => Settings())); }, ) ], diff --git a/lib/pages/settings.dart b/lib/pages/settings.dart index a030088..adb62a1 100644 --- a/lib/pages/settings.dart +++ b/lib/pages/settings.dart @@ -4,7 +4,7 @@ import 'package:provider/provider.dart'; import '../stores/config_store.dart'; -class SettingsPage extends StatelessWidget { +class Settings extends StatelessWidget { @override Widget build(BuildContext context) { var theme = Theme.of(context); From e309c165d3d584635a524e0e6dd46869a0bb1ee8 Mon Sep 17 00:00:00 2001 From: krawieck Date: Thu, 3 Sep 2020 13:56:37 +0200 Subject: [PATCH 20/22] Change `fullPostFuture` to `fullPostSnap` and simplify error handling --- lib/pages/full_post.dart | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/lib/pages/full_post.dart b/lib/pages/full_post.dart index a1677f0..c6bedcd 100644 --- a/lib/pages/full_post.dart +++ b/lib/pages/full_post.dart @@ -29,12 +29,11 @@ class FullPostPage extends HookWidget { @override Widget build(BuildContext context) { - var fullPostFuture = useFuture(this.fullPost); - - var fullPost = fullPostFuture.data; + final fullPostSnap = useFuture(this.fullPost); + final fullPost = fullPostSnap.data; final savedIcon = () { - if (fullPost != null) { + if (fullPostSnap.hasData) { if (fullPost.post.saved == null || !fullPost.post.saved) { return Icons.bookmark_border; } else { @@ -63,18 +62,18 @@ class FullPostPage extends HookWidget { icon: Icon(Icons.more_vert), onPressed: () {}), // TODO: more menu ], ), - body: fullPost != null || post != null + body: fullPostSnap.hasData || post != null // FUTURE SUCCESS ? ListView( physics: const AlwaysScrollableScrollPhysics(), children: [ - if (fullPost != null) + if (fullPostSnap.hasData) Post(fullPost.post, fullPost: true) else if (post != null) Post(post, fullPost: true) else CircularProgressIndicator(), - if (fullPost != null) + if (fullPostSnap.hasData) CommentSection(fullPost.comments, postCreatorId: fullPost.post.creatorId) else @@ -84,7 +83,7 @@ class FullPostPage extends HookWidget { ), ], ) - : fullPostFuture.error != null + : fullPostSnap.hasError // FUTURE FAILURE ? Center( child: Column( @@ -92,7 +91,7 @@ class FullPostPage extends HookWidget { children: [ Icon(Icons.error, size: 30), Padding(padding: EdgeInsets.all(5)), - Text('ERROR: ${fullPostFuture.error.toString()}'), + Text('ERROR: ${fullPostSnap.error.toString()}'), ], ), ) From 869bb0eccc3d3a88143019725b6d9304e89cdb4d Mon Sep 17 00:00:00 2001 From: krawieck Date: Thu, 3 Sep 2020 14:00:06 +0200 Subject: [PATCH 21/22] remove useless import --- lib/pages/full_post.dart | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/pages/full_post.dart b/lib/pages/full_post.dart index c6bedcd..ec44ca9 100644 --- a/lib/pages/full_post.dart +++ b/lib/pages/full_post.dart @@ -2,7 +2,6 @@ import 'package:esys_flutter_share/esys_flutter_share.dart'; import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:lemmy_api_client/lemmy_api_client.dart'; -import 'package:lemmy_api_client/src/models/post.dart'; import '../widgets/comment_section.dart'; import '../widgets/post.dart'; From a4ff7b533643051affa697350e8a30e177b802d7 Mon Sep 17 00:00:00 2001 From: krawieck Date: Thu, 3 Sep 2020 14:33:17 +0200 Subject: [PATCH 22/22] Change `Settings` to `SettingsPage` --- lib/pages/profile_tab.dart | 2 +- lib/pages/settings.dart | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/pages/profile_tab.dart b/lib/pages/profile_tab.dart index 9a6e7d4..d05ce37 100644 --- a/lib/pages/profile_tab.dart +++ b/lib/pages/profile_tab.dart @@ -53,7 +53,7 @@ class UserProfileTab extends HookWidget { ), onPressed: () { Navigator.of(context) - .push(MaterialPageRoute(builder: (_) => Settings())); + .push(MaterialPageRoute(builder: (_) => SettingsPage())); }, ) ], diff --git a/lib/pages/settings.dart b/lib/pages/settings.dart index adb62a1..a030088 100644 --- a/lib/pages/settings.dart +++ b/lib/pages/settings.dart @@ -4,7 +4,7 @@ import 'package:provider/provider.dart'; import '../stores/config_store.dart'; -class Settings extends StatelessWidget { +class SettingsPage extends StatelessWidget { @override Widget build(BuildContext context) { var theme = Theme.of(context);