Browse Source

added share, fixed attachments images filter

Veloe 3 tháng trước cách đây
mục cha
commit
76d9889789

+ 3 - 0
devtools_options.yaml

@@ -0,0 +1,3 @@
+description: This file stores settings for Dart & Flutter DevTools.
+documentation: https://docs.flutter.dev/tools/devtools/extensions#configure-extension-enablement-states
+extensions:

+ 0 - 4
lib/models/post.dart

@@ -1,7 +1,3 @@
-import 'package:flutter/material.dart';
-import 'package:veloe_kemono_party_flutter/main.dart';
-import 'package:veloe_kemono_party_flutter/models/creator.dart';
-
 import 'attachment.dart';
 
 class Post {

+ 26 - 4
lib/pages/widgets/post_container.dart

@@ -3,6 +3,7 @@ import 'package:flutter_widget_from_html/flutter_widget_from_html.dart';
 import 'package:url_launcher/url_launcher.dart';
 import 'package:veloe_kemono_party_flutter/models/attachment.dart';
 import 'smart_image_container.dart';
+import 'package:share_plus/share_plus.dart';
 import '../../models/post.dart';
 
 class PostContainer extends StatelessWidget {
@@ -118,7 +119,8 @@ class _PostActionsFooter extends StatelessWidget {
 }
 
 void _sharePost(Post post) {
-  //create link to share
+  var link = 'https://kemono.su/${post.service}/user/${post.user}/post/${post.id}';
+  Share.share(link);
 }
 
 class _PostContentSection extends StatelessWidget {
@@ -128,6 +130,10 @@ class _PostContentSection extends StatelessWidget {
 
   @override
   Widget build(BuildContext context) {
+    final imageAttachments = post.attachments
+      .where((a) => _isImageFile(a.link))
+      .toList();
+
     return Column(
       mainAxisSize: MainAxisSize.min,
       crossAxisAlignment: CrossAxisAlignment.start,
@@ -140,7 +146,7 @@ class _PostContentSection extends StatelessWidget {
         ),
 
         // Attachments Grid
-        if (post.attachments.isNotEmpty)
+        if (imageAttachments.isNotEmpty)
           LayoutBuilder(
             builder: (context, constraints) {
               return Column(
@@ -152,11 +158,11 @@ class _PostContentSection extends StatelessWidget {
                     gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
                       crossAxisCount: _calculateColumnCount(constraints.maxWidth),
                     ),
-                    itemCount: post.attachments.length,
+                    itemCount: imageAttachments.length,
                     itemBuilder: (context, index) => Padding(
                       padding: const EdgeInsets.all(4),
                       child: SmartImageContainer(
-                        imageUrl: post.attachments[index].link,
+                        imageUrl: imageAttachments[index].link,
                         //onTap: () => _handleAttachmentTap(index),
                       ),
                     ),
@@ -209,6 +215,22 @@ class _PostContentSection extends StatelessWidget {
       return 'Download';
     }
   }
+
+  bool _isImageFile(String url) {
+    try {
+      final uri = Uri.parse(url);
+      final path = uri.path.toLowerCase();
+      
+      final cleanPath = path.split('?').first.split('#').first;
+      const imageExtensions = {
+        'jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp', 'svg',
+        'tiff', 'heic', 'heif' 
+      };
+      return imageExtensions.any((ext) => cleanPath.endsWith('.$ext'));
+    } catch (e) {
+      return false; // Invalid URL format
+    }
+  }
 }
 
 Future<bool> _handleUrlLaunch(BuildContext context, String url) async {

+ 0 - 137
lib/pages/widgets/post_detail_view.dart

@@ -1,137 +0,0 @@
-import 'package:flutter/material.dart';
-import 'package:flutter_widget_from_html/flutter_widget_from_html.dart';
-import 'package:url_launcher/url_launcher.dart';
-import 'package:veloe_kemono_party_flutter/models/attachment.dart';
-import 'package:veloe_kemono_party_flutter/models/post.dart';
-import 'package:veloe_kemono_party_flutter/pages/widgets/smart_image_container.dart';
-
-class PostDetailView extends StatelessWidget {
-  final Post post;
-  
-  const PostDetailView({super.key, required this.post});
-
-  @override
-  Widget build(BuildContext context) {
-    return Scaffold(
-      appBar: AppBar(
-        title: Text(post.title),
-        elevation: 0,
-      ),
-      body: LayoutBuilder(
-        builder: (context, constraints) {
-          return ConstrainedBox(
-            constraints: BoxConstraints(
-              minHeight: constraints.maxHeight,
-              maxWidth: constraints.maxWidth,
-            ),
-            child: Column(
-              mainAxisSize: MainAxisSize.min,
-              crossAxisAlignment: CrossAxisAlignment.start,
-              children: [
-                // Header Section
-                _buildTitle(context),
-                
-                // Content Area
-                Flexible(
-                  child: Column(
-                    mainAxisSize: MainAxisSize.min,
-                    children: [
-                      if (post.attachments.isNotEmpty)
-                        _buildImageColumn(post.attachments),
-                      _buildHtmlContent(),
-                    ],
-                  ),
-                ),
-                
-                // Footer Section
-                _buildDateDisplay(context),
-              ],
-            ),
-          );
-        },
-      ),
-    );
-  }
-
-  Widget _buildTitle(BuildContext context) {
-    return Padding(
-      padding: const EdgeInsets.all(16.0),
-      child: Text(
-        post.title,
-        style: Theme.of(context).textTheme.headlineMedium?.copyWith(
-          fontWeight: FontWeight.w600,
-        ),
-      ),
-    );
-  }
-
-  Widget _buildImageColumn(List<Attachment> attachments) {
-    return Column(
-      children: attachments
-        .where((attachment) => _isImageFile(attachment.link))
-        .map((attachment) {
-        return Padding(
-          padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
-          child: SmartImageContainer(imageUrl: attachment.link),
-        );
-      }).toList(),
-    );
-  }
-
-  bool _isImageFile(String url) {
-  try {
-    final uri = Uri.parse(url);
-    final path = uri.path.toLowerCase();
-    
-    final cleanPath = path.split('?').first.split('#').first;
-    const imageExtensions = {
-      'jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp', 'svg',
-      'tiff', 'heic', 'heif' 
-    };
-    return imageExtensions.any((ext) => cleanPath.endsWith('.$ext'));
-  } catch (e) {
-    return false; // Invalid URL format
-  }
-}
-
-  Widget _buildHtmlContent() {
-    return Padding(
-      padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 24),
-      child: HtmlWidget(
-        post.content,
-        renderMode: RenderMode.column,
-        onTapUrl: (url) => launchUrl(Uri.parse(url)),
-        customWidgetBuilder: (element) {
-          if (element.localName == 'img') {
-            final src = element.attributes['src'];
-            return src != null 
-                ? Padding(
-                    padding: const EdgeInsets.symmetric(vertical: 8),
-                    child: SmartImageContainer(imageUrl: src),
-                  )
-                : const SizedBox.shrink();
-          }
-          return null;
-        },
-      ),
-    );
-  }
-
-  Widget _buildDateDisplay(BuildContext context) {
-    return Padding(
-      padding: const EdgeInsets.all(16.0),
-      child: Row(
-        children: [
-          Icon(Icons.calendar_today, size: 18, color: Colors.grey[700]),
-          const SizedBox(width: 8),
-          Text(post.published
-            ,
-            style: Theme.of(context).textTheme.bodyLarge?.copyWith(
-              color: Colors.grey[700],
-            ),
-          ),
-        ],
-      ),
-    );
-  }
-}

+ 2 - 0
macos/Flutter/GeneratedPluginRegistrant.swift

@@ -9,6 +9,7 @@ import audio_session
 import just_audio
 import package_info_plus
 import path_provider_foundation
+import share_plus
 import sqflite_darwin
 import url_launcher_macos
 import video_player_avfoundation
@@ -20,6 +21,7 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
   JustAudioPlugin.register(with: registry.registrar(forPlugin: "JustAudioPlugin"))
   FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin"))
   PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
+  SharePlusMacosPlugin.register(with: registry.registrar(forPlugin: "SharePlusMacosPlugin"))
   SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin"))
   UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin"))
   FVPVideoPlayerPlugin.register(with: registry.registrar(forPlugin: "FVPVideoPlayerPlugin"))

+ 26 - 2
pubspec.lock

@@ -193,6 +193,14 @@ packages:
       url: "https://pub.dev"
     source: hosted
     version: "3.1.2"
+  cross_file:
+    dependency: transitive
+    description:
+      name: cross_file
+      sha256: "7caf6a750a0c04effbb52a676dce9a4a592e10ad35c34d6d2d0e4811160d5670"
+      url: "https://pub.dev"
+    source: hosted
+    version: "0.3.4+2"
   crypto:
     dependency: transitive
     description:
@@ -580,10 +588,10 @@ packages:
     dependency: transitive
     description:
       name: mime
-      sha256: "41a20518f0cb1256669420fdba0cd90d21561e560ac240f26ef8322e45bb7ed6"
+      sha256: "801fd0b26f14a4a58ccb09d5892c3fbdeff209594300a542492cf13fba9d247a"
       url: "https://pub.dev"
     source: hosted
-    version: "2.0.0"
+    version: "1.0.6"
   nested:
     dependency: transitive
     description:
@@ -760,6 +768,22 @@ packages:
       url: "https://pub.dev"
     source: hosted
     version: "0.28.0"
+  share_plus:
+    dependency: "direct main"
+    description:
+      name: share_plus
+      sha256: "3ef39599b00059db0990ca2e30fca0a29d8b37aae924d60063f8e0184cf20900"
+      url: "https://pub.dev"
+    source: hosted
+    version: "7.2.2"
+  share_plus_platform_interface:
+    dependency: transitive
+    description:
+      name: share_plus_platform_interface
+      sha256: "251eb156a8b5fa9ce033747d73535bf53911071f8d3b6f4f0b578505ce0d4496"
+      url: "https://pub.dev"
+    source: hosted
+    version: "3.4.0"
   shelf:
     dependency: transitive
     description:

+ 1 - 0
pubspec.yaml

@@ -43,6 +43,7 @@ dependencies:
   intl: ^0.18.1
   flutter_widget_from_html: ^0.10.0
   url_launcher: ^6.2.0
+  share_plus: ^7.0.0
 
 dev_dependencies:
   flutter_test:

+ 3 - 0
windows/flutter/generated_plugin_registrant.cc

@@ -6,9 +6,12 @@
 
 #include "generated_plugin_registrant.h"
 
+#include <share_plus/share_plus_windows_plugin_c_api.h>
 #include <url_launcher_windows/url_launcher_windows.h>
 
 void RegisterPlugins(flutter::PluginRegistry* registry) {
+  SharePlusWindowsPluginCApiRegisterWithRegistrar(
+      registry->GetRegistrarForPlugin("SharePlusWindowsPluginCApi"));
   UrlLauncherWindowsRegisterWithRegistrar(
       registry->GetRegistrarForPlugin("UrlLauncherWindows"));
 }

+ 1 - 0
windows/flutter/generated_plugins.cmake

@@ -3,6 +3,7 @@
 #
 
 list(APPEND FLUTTER_PLUGIN_LIST
+  share_plus
   url_launcher_windows
 )