diff --git a/.github/workflows/pull_request.yml b/.github/workflows/pull_request.yml new file mode 100644 index 0000000..8cec717 --- /dev/null +++ b/.github/workflows/pull_request.yml @@ -0,0 +1,27 @@ +name: Feed SDK test on every PR + +on: + pull_request: + branches-ignore: + - master + +jobs: + run-flutter-test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + - uses: subosito/flutter-action@v2 + with: + flutter-version: ${{ env.FLUTTER_VERSION }} + - run: flutter pub get + + - name: Lint + run: flutter analyze > lint-results.txt + + - name: Upload the lint results as an artifact + if: always() + uses: actions/upload-artifact@v2 + with: + name: lint-results + path: lint-results.txt \ No newline at end of file diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..3ab308e --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,67 @@ +name: Create Tag and Release on Version Change + +on: + push: + branches: + - master + +permissions: write-all + +jobs: + create_tag: + name: Create Git Tag + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v3 + with: + fetch-depth: 0 + + - name: Check for version changes + run: | + # Fetch all tags from the remote repository + git fetch --tags + + # Get the previous version from the last release tag + export previous_version=$(git describe --tags --abbrev=0) + + # Get the current version from pubspec.yaml + export current_version=$(cat pubspec.yaml | grep 'version:' | awk '{print $2}') + + if [[ "$previous_version" != "v$current_version" ]]; then + echo "Version has changed from $previous_version to v$current_version." + else + echo "Version has not changed." + exit 1 + fi + + - name: Push Git Tag + run: | + # Git login + git config --global user.name "$(git log -n 1 --pretty=format:%an)" + git config --global user.email "$(git log -n 1 --pretty=format:%ae)" + + # Push a Git tag with the new version + export current_version=$(cat pubspec.yaml | grep 'version:' | awk '{print $2}') + git tag -a "v$current_version" -m "Version $current_version" + git push origin "v$current_version" + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + create-github-release: + name: Create GitHub Release + runs-on: ubuntu-latest + needs: create_tag + permissions: + contents: write + steps: + - name: Checkout code + uses: actions/checkout@v3 + with: + fetch-depth: 0 + + - name: Create Release + run: gh release create "$(git describe --tags --abbrev=0)" --generate-notes + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/analysis_options.yaml b/analysis_options.yaml index a5744c1..ea22b62 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -2,3 +2,30 @@ include: package:flutter_lints/flutter.yaml # Additional information about this file can be found at # https://dart.dev/guides/language/analysis-options +linter: + # The lint rules applied to this project can be customized in the + # section below to disable rules from the `package:flutter_lints/flutter.yaml` + # included above or to enable additional rules. A list of all available lints + # and their documentation is published at + # https://dart-lang.github.io/linter/lints/index.html. + # + # Instead of disabling a lint rule for the entire project in the + # section below, it can also be suppressed for a single line of code + # or a specific dart file by using the `// ignore: name_of_lint` and + # `// ignore_for_file: name_of_lint` syntax on the line or in the file + # producing the lint. + rules: + # Style rules + - camel_case_types + - library_names + - avoid_catches_without_on_clauses + - avoid_catching_errors + - avoid_empty_else + - unnecessary_brace_in_string_interps + - avoid_redundant_argument_values + - leading_newlines_in_multiline_strings + # formatting + - lines_longer_than_80_chars + - curly_braces_in_flow_control_structures + # doc comments + - slash_for_doc_comments \ No newline at end of file diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index 261cd9e..ad79e80 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -104,6 +104,12 @@ PODS: - GoogleUtilities/Logger - image_picker_ios (0.0.1): - Flutter + - media_kit_libs_ios_video (1.0.4): + - Flutter + - media_kit_native_event_loop (1.0.0): + - Flutter + - media_kit_video (0.0.1): + - Flutter - nanopb (2.30909.0): - nanopb/decode (= 2.30909.0) - nanopb/encode (= 2.30909.0) @@ -111,6 +117,8 @@ PODS: - nanopb/encode (2.30909.0) - open_filex (0.0.2): - Flutter + - package_info_plus (0.4.5): + - Flutter - path_provider_foundation (0.0.1): - Flutter - FlutterMacOS @@ -118,6 +126,8 @@ PODS: - Flutter - PromisesObjC (2.3.1) - ReachabilitySwift (5.0.0) + - screen_brightness_ios (0.1.0): + - Flutter - SDWebImage (5.18.1): - SDWebImage/Core (= 5.18.1) - SDWebImage/Core (5.18.1) @@ -141,7 +151,9 @@ PODS: - Flutter - video_player_avfoundation (0.0.1): - Flutter - - wakelock (0.0.1): + - volume_controller (0.0.1): + - Flutter + - wakelock_plus (0.0.1): - Flutter DEPENDENCIES: @@ -153,9 +165,14 @@ DEPENDENCIES: - Flutter (from `Flutter`) - flutter_keyboard_visibility (from `.symlinks/plugins/flutter_keyboard_visibility/ios`) - image_picker_ios (from `.symlinks/plugins/image_picker_ios/ios`) + - media_kit_libs_ios_video (from `.symlinks/plugins/media_kit_libs_ios_video/ios`) + - media_kit_native_event_loop (from `.symlinks/plugins/media_kit_native_event_loop/ios`) + - media_kit_video (from `.symlinks/plugins/media_kit_video/ios`) - open_filex (from `.symlinks/plugins/open_filex/ios`) + - package_info_plus (from `.symlinks/plugins/package_info_plus/ios`) - path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`) - permission_handler_apple (from `.symlinks/plugins/permission_handler_apple/ios`) + - screen_brightness_ios (from `.symlinks/plugins/screen_brightness_ios/ios`) - share_plus (from `.symlinks/plugins/share_plus/ios`) - shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`) - simple_s3 (from `.symlinks/plugins/simple_s3/ios`) @@ -163,7 +180,8 @@ DEPENDENCIES: - uni_links (from `.symlinks/plugins/uni_links/ios`) - url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`) - video_player_avfoundation (from `.symlinks/plugins/video_player_avfoundation/ios`) - - wakelock (from `.symlinks/plugins/wakelock/ios`) + - volume_controller (from `.symlinks/plugins/volume_controller/ios`) + - wakelock_plus (from `.symlinks/plugins/wakelock_plus/ios`) SPEC REPOS: trunk: @@ -203,12 +221,22 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/flutter_keyboard_visibility/ios" image_picker_ios: :path: ".symlinks/plugins/image_picker_ios/ios" + media_kit_libs_ios_video: + :path: ".symlinks/plugins/media_kit_libs_ios_video/ios" + media_kit_native_event_loop: + :path: ".symlinks/plugins/media_kit_native_event_loop/ios" + media_kit_video: + :path: ".symlinks/plugins/media_kit_video/ios" open_filex: :path: ".symlinks/plugins/open_filex/ios" + package_info_plus: + :path: ".symlinks/plugins/package_info_plus/ios" path_provider_foundation: :path: ".symlinks/plugins/path_provider_foundation/darwin" permission_handler_apple: :path: ".symlinks/plugins/permission_handler_apple/ios" + screen_brightness_ios: + :path: ".symlinks/plugins/screen_brightness_ios/ios" share_plus: :path: ".symlinks/plugins/share_plus/ios" shared_preferences_foundation: @@ -223,8 +251,10 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/url_launcher_ios/ios" video_player_avfoundation: :path: ".symlinks/plugins/video_player_avfoundation/ios" - wakelock: - :path: ".symlinks/plugins/wakelock/ios" + volume_controller: + :path: ".symlinks/plugins/volume_controller/ios" + wakelock_plus: + :path: ".symlinks/plugins/wakelock_plus/ios" SPEC CHECKSUMS: AWSCognito: f50de600804941d083af37a7568905f31a774727 @@ -248,14 +278,19 @@ SPEC CHECKSUMS: GoogleDataTransport: 54dee9d48d14580407f8f5fbf2f496e92437a2f2 GoogleUtilities: 13e2c67ede716b8741c7989e26893d151b2b2084 image_picker_ios: 4a8aadfbb6dc30ad5141a2ce3832af9214a705b5 + media_kit_libs_ios_video: a5fe24bc7875ccd6378a0978c13185e1344651c1 + media_kit_native_event_loop: e6b2ab20cf0746eb1c33be961fcf79667304fa2a + media_kit_video: 5da63f157170e5bf303bf85453b7ef6971218a2e nanopb: b552cce312b6c8484180ef47159bc0f65a1f0431 open_filex: 6e26e659846ec990262224a12ef1c528bb4edbe4 + package_info_plus: fd030dabf36271f146f1f3beacd48f564b0f17f7 path_provider_foundation: eaf5b3e458fc0e5fbb9940fb09980e853fe058b8 permission_handler_apple: e76247795d700c14ea09e3a2d8855d41ee80a2e6 PromisesObjC: c50d2056b5253dadbd6c2bea79b0674bd5a52fa4 ReachabilitySwift: 985039c6f7b23a1da463388634119492ff86c825 + screen_brightness_ios: 715ca807df953bf676d339f11464e438143ee625 SDWebImage: ebdbcebc7933a45226d9313bd0118bc052ad458b - share_plus: 056a1e8ac890df3e33cb503afffaf1e9b4fbae68 + share_plus: 599aa54e4ea31d4b4c0e9c911bcc26c55e791028 shared_preferences_foundation: 5b919d13b803cadd15ed2dc053125c68730e5126 simple_s3: dc1e236435ab824abf10e6147110fe86ab32c51c sqflite: 31f7eba61e3074736dff8807a9b41581e4f7f15a @@ -263,7 +298,8 @@ SPEC CHECKSUMS: uni_links: d97da20c7701486ba192624d99bffaaffcfc298a url_launcher_ios: 08a3dfac5fb39e8759aeb0abbd5d9480f30fc8b4 video_player_avfoundation: 81e49bb3d9fb63dccf9fa0f6d877dc3ddbeac126 - wakelock: d0fc7c864128eac40eba1617cb5264d9c940b46f + volume_controller: 531ddf792994285c9b17f9d8a7e4dcdd29b3eae9 + wakelock_plus: 8b09852c8876491e4b6d179e17dfe2a0b5f60d47 PODFILE CHECKSUM: 575f4f8ca7c0e6353949d50aceaee0b921a303ac diff --git a/example/ios/Runner/Info.plist b/example/ios/Runner/Info.plist index b002640..374c474 100644 --- a/example/ios/Runner/Info.plist +++ b/example/ios/Runner/Info.plist @@ -72,6 +72,8 @@ NSAllowsLocalNetworking + NSAllowsArbitraryLoads + NSCameraUsageDescription We require camera access to take pictures for uploading diff --git a/example/lib/cred_screen.dart b/example/lib/cred_screen.dart index 5c9ca1f..cdfed61 100644 --- a/example/lib/cred_screen.dart +++ b/example/lib/cred_screen.dart @@ -104,6 +104,7 @@ class _CredScreenState extends State { // Subscribe to link changes _streamSubscription = linkStream.listen((String? link) async { + initialURILinkHandled = true; if (link != null) { // Handle the deep link // You can extract any parameters from the uri object here diff --git a/example/lib/user_local_preference.dart b/example/lib/user_local_preference.dart deleted file mode 100644 index 2dd12cd..0000000 --- a/example/lib/user_local_preference.dart +++ /dev/null @@ -1,58 +0,0 @@ -// import 'dart:convert'; - -// import 'package:likeminds_feed/likeminds_feed.dart'; -// import 'package:shared_preferences/shared_preferences.dart'; - -// class UserLocalPreference { -// SharedPreferences? _sharedPreferences; - -// static final UserLocalPreference _instance = UserLocalPreference._(); -// static UserLocalPreference get instance => _instance; - -// UserLocalPreference._(); - -// final String _domainKey = 'domain_example'; -// final String _userKey = 'user_example'; -// final String _memberStateKey = 'isCm_example'; - -// Future initialize() async { -// _sharedPreferences = await SharedPreferences.getInstance(); -// } - -// Future storeUserData(User user) async { -// UserEntity userEntity = user.toEntity(); -// Map userData = userEntity.toJson(); -// String userString = jsonEncode(userData); -// _sharedPreferences!.setString(_userKey, userString); -// } - -// Future storeUserId(String userId) async { -// _sharedPreferences!.setString(_userKey, userId); -// } - -// String? fetchUserId() { -// return _sharedPreferences!.getString(_userKey); -// } - -// User fetchUserData() { -// Map userData = -// jsonDecode(_sharedPreferences!.getString(_userKey)!); -// return User.fromEntity(UserEntity.fromJson(userData)); -// } - -// Future storeMemberState(bool isCm) async { -// _sharedPreferences!.setBool(_memberStateKey, isCm); -// } - -// bool fetchMemberState() { -// return _sharedPreferences!.getBool(_memberStateKey)!; -// } - -// Future storeAppDomain(String domain) async { -// _sharedPreferences!.setString(_domainKey, domain); -// } - -// String getAppDomain() { -// return _sharedPreferences!.getString(_domainKey)!; -// } -// } diff --git a/example/pubspec.lock b/example/pubspec.lock index 9b8d47b..41bf078 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -755,24 +755,24 @@ packages: dependency: transitive description: name: likeminds_feed - sha256: "6cea6fe3a639f41a9498c1b046652ffbe1af4aa98036dbfedc2b01a9dfbf7786" + sha256: e47b77e3eadfc475cd62e9bc1ea9c76fb64b5a3dc9cdb548782b06423f7c8e28 url: "https://pub.dev" source: hosted - version: "1.6.1" + version: "1.6.3" likeminds_feed_ss_fl: dependency: "direct main" description: path: ".." relative: true source: path - version: "1.1.2" + version: "1.2.1" likeminds_feed_ui_fl: dependency: transitive description: path: "../../LikeMinds-Flutter-Feed-UI" relative: true source: path - version: "1.3.2" + version: "1.3.5" lints: dependency: transitive description: diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 97c0bcd..8383c43 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -16,7 +16,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html # In Windows, build-name is used as the major, minor, and patch parts # of the product and file versions while build-number is used as the build suffix. -version: 1.2.1 +version: 1.2.2 environment: sdk: '>=3.0.0 <4.0.0' diff --git a/lib/likeminds_feed_ss_fl.dart b/lib/likeminds_feed_ss_fl.dart index f8cb131..34253c9 100644 --- a/lib/likeminds_feed_ss_fl.dart +++ b/lib/likeminds_feed_ss_fl.dart @@ -2,27 +2,25 @@ library likeminds_feed_ss_fl; import 'package:firebase_core/firebase_core.dart'; import 'package:flutter/material.dart'; -import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_no_internet_widget/flutter_no_internet_widget.dart'; import 'package:likeminds_feed/likeminds_feed.dart'; import 'package:likeminds_feed_ss_fl/src/services/navigation_service.dart'; -import 'package:likeminds_feed_ss_fl/src/utils/icons.dart'; import 'package:likeminds_feed_ss_fl/src/utils/network_handling.dart'; import 'package:likeminds_feed_ss_fl/src/utils/utils.dart'; import 'package:likeminds_feed_ss_fl/src/views/universal_feed_page.dart'; import 'package:likeminds_feed_ui_fl/likeminds_feed_ui_fl.dart'; -import 'package:likeminds_feed_ss_fl/src/blocs/new_post/new_post_bloc.dart'; import 'package:likeminds_feed_ss_fl/src/services/likeminds_service.dart'; import 'package:likeminds_feed_ss_fl/src/services/service_locator.dart'; import 'package:likeminds_feed_ss_fl/src/utils/constants/ui_constants.dart'; import 'package:likeminds_feed_ss_fl/src/utils/credentials/credentials.dart'; -import 'package:overlay_support/overlay_support.dart'; +import 'package:media_kit/media_kit.dart'; export 'src/services/service_locator.dart'; export 'src/utils/analytics/analytics.dart'; export 'src/utils/notifications/notification_handler.dart'; export 'src/utils/share/share_post.dart'; +export 'src/utils/local_preference/user_local_preference.dart'; /// Flutter environment manager v0.0.1 const prodFlag = !bool.fromEnvironment('DEBUG'); @@ -34,11 +32,10 @@ class LMFeed extends StatefulWidget { final String? userId; final String? userName; final String apiKey; + final String? imageUrl; final Function(BuildContext context)? openChatCallback; final LMSDKCallback? callback; - static LMFeed? _instance; - /// INIT - Get the LMFeed instance and pass the credentials (if any) /// to the instance. This will be used to initialize the app. /// If no credentials are provided, the app will run with the default @@ -46,6 +43,7 @@ class LMFeed extends StatefulWidget { static LMFeed instance({ String? userId, String? userName, + String? imageUrl, LMSDKCallback? callback, Function(BuildContext context)? openChatCallback, required String apiKey, @@ -55,6 +53,7 @@ class LMFeed extends StatefulWidget { userName: userName, callback: callback, apiKey: apiKey, + imageUrl: imageUrl, openChatCallback: openChatCallback, ); } @@ -79,6 +78,7 @@ class LMFeed extends StatefulWidget { {Key? key, this.userId, this.userName, + this.imageUrl, required this.callback, required this.apiKey, this.openChatCallback}) @@ -91,9 +91,11 @@ class LMFeed extends StatefulWidget { class _LMFeedState extends State { User? user; late final String userId; + String? imageUrl; late final String userName; late final bool isProd; late final NetworkConnectivity networkConnectivity; + late final Future initiateUser; ValueNotifier rebuildOnConnectivityChange = ValueNotifier(false); @override @@ -101,14 +103,29 @@ class _LMFeedState extends State { super.initState(); networkConnectivity = NetworkConnectivity.instance; networkConnectivity.initialise(); - + MediaKit.ensureInitialized(); isProd = prodFlag; userId = widget.userId!.isEmpty ? isProd ? CredsProd.botId : CredsDev.botId : widget.userId!; + imageUrl = widget.imageUrl; userName = widget.userName!.isEmpty ? "Test username" : widget.userName!; + if (imageUrl == null || imageUrl!.isEmpty) { + initiateUser = + locator().initiateUser((InitiateUserRequestBuilder() + ..userId(userId) + ..userName(userName)) + .build()); + } else { + initiateUser = + locator().initiateUser((InitiateUserRequestBuilder() + ..userId(userId) + ..userName(userName) + ..imageUrl(imageUrl!)) + .build()); + } firebase(); } @@ -138,12 +155,14 @@ class _LMFeedState extends State { color: kPrimaryColor, ), kVerticalPaddingLarge, - Text("No internet\nCheck your connection and try again", - textAlign: TextAlign.center, - style: TextStyle( - color: kPrimaryColor, - fontSize: 14, - )), + Text( + "No internet\nCheck your connection and try again", + textAlign: TextAlign.center, + style: TextStyle( + color: kPrimaryColor, + fontSize: 14, + ), + ), ], ), ), @@ -161,87 +180,75 @@ class _LMFeedState extends State { }, loadingWidget: const Center(child: CircularProgressIndicator()), online: ValueListenableBuilder( - valueListenable: rebuildOnConnectivityChange, - builder: (context, _, __) { - return FutureBuilder( - future: locator().initiateUser( - (InitiateUserRequestBuilder() - ..userId(userId) - ..userName(userName)) - .build(), - ), - initialData: null, - builder: (BuildContext context, AsyncSnapshot snapshot) { - if (snapshot.hasData) { - InitiateUserResponse response = snapshot.data; - if (response.success) { - user = response.initiateUser?.user; - - //Get community configurations - locator().getCommunityConfigurations(); - - LMNotificationHandler.instance.registerDevice(user!.id); - return MaterialApp( - debugShowCheckedModeBanner: !isProd, - navigatorKey: locator().navigatorKey, - theme: ThemeData.from( - colorScheme: ColorScheme.fromSeed( - seedColor: kPrimaryColor, - primary: kPrimaryColor, - secondary: primary500, - onSecondary: kSecondaryColor700, - ), - ), - title: 'LM Feed', - home: FutureBuilder( - future: locator().getMemberState(), - initialData: null, - builder: - (BuildContext context, AsyncSnapshot snapshot) { - if (snapshot.hasData) { - return UniversalFeedScreen( - openChatCallback: widget.openChatCallback, - ); - } - - return Container( - height: MediaQuery.of(context).size.height, - width: MediaQuery.of(context).size.width, - color: kBackgroundColor, - child: const Center( - child: LMLoader( - isPrimary: true, - ), - ), + valueListenable: rebuildOnConnectivityChange, + builder: (context, _, __) { + return FutureBuilder( + future: initiateUser, + initialData: null, + builder: (BuildContext context, AsyncSnapshot snapshot) { + if (snapshot.hasData) { + InitiateUserResponse response = snapshot.data; + if (response.success) { + user = response.initiateUser?.user; + + //Get community configurations + locator().getCommunityConfigurations(); + + LMNotificationHandler.instance.registerDevice(user!.id); + return MaterialApp( + theme: suraasaTheme, + debugShowCheckedModeBanner: !isProd, + navigatorKey: locator().navigatorKey, + title: 'LM Feed', + home: FutureBuilder( + future: locator().getMemberState(), + initialData: null, + builder: (BuildContext context, AsyncSnapshot snapshot) { + if (snapshot.hasData) { + return UniversalFeedScreen( + openChatCallback: widget.openChatCallback, ); - }, - ), - ); - } else {} - } else if (snapshot.hasError) { - debugPrint("Error - ${snapshot.error}"); - return Container( - height: MediaQuery.of(context).size.height, - width: MediaQuery.of(context).size.width, - color: kBackgroundColor, - child: const Center( - child: Text("An error has occured", - textAlign: TextAlign.center, - style: TextStyle( - color: Colors.black, - fontSize: 16, - )), + } + + return Container( + height: MediaQuery.of(context).size.height, + width: MediaQuery.of(context).size.width, + color: kBackgroundColor, + child: const Center( + child: LMLoader( + isPrimary: true, + ), + ), + ); + }, ), ); - } + } else {} + } else if (snapshot.hasError) { + debugPrint("Error - ${snapshot.error}"); return Container( height: MediaQuery.of(context).size.height, width: MediaQuery.of(context).size.width, color: kBackgroundColor, + child: const Center( + child: Text("An error has occured", + textAlign: TextAlign.center, + style: TextStyle( + color: Colors.black, + fontSize: 16, + )), + ), ); - }, - ); - }), + } + return Container( + height: MediaQuery.of(context).size.height, + width: MediaQuery.of(context).size.width, + color: kBackgroundColor, + ); + }, + ); + }, + ), ); } } diff --git a/lib/src/utils/constants/ui_constants.dart b/lib/src/utils/constants/ui_constants.dart index 3ab5089..652115e 100644 --- a/lib/src/utils/constants/ui_constants.dart +++ b/lib/src/utils/constants/ui_constants.dart @@ -47,3 +47,12 @@ const SizedBox kVerticalPaddingSmall = SizedBox(height: kPaddingSmall); const SizedBox kVerticalPaddingXSmall = SizedBox(height: kPaddingXSmall); const SizedBox kVerticalPaddingLarge = SizedBox(height: kPaddingLarge); const SizedBox kVerticalPaddingMedium = SizedBox(height: kPaddingMedium); + +ThemeData suraasaTheme = ThemeData.from( + colorScheme: ColorScheme.fromSeed( + seedColor: kPrimaryColor, + primary: kPrimaryColor, + secondary: primary500, + onSecondary: kSecondaryColor700, + ), +); diff --git a/lib/src/utils/local_preference/user_local_preference.dart b/lib/src/utils/local_preference/user_local_preference.dart index 7e3fd2c..95753a0 100644 --- a/lib/src/utils/local_preference/user_local_preference.dart +++ b/lib/src/utils/local_preference/user_local_preference.dart @@ -1,12 +1,15 @@ import 'dart:convert'; import 'package:likeminds_feed/likeminds_feed.dart'; +import 'package:likeminds_feed_ss_fl/likeminds_feed_ss_fl.dart'; +import 'package:likeminds_feed_ss_fl/src/services/likeminds_service.dart'; import 'package:shared_preferences/shared_preferences.dart'; class UserLocalPreference { SharedPreferences? _sharedPreferences; static UserLocalPreference? _instance; + static UserLocalPreference get instance => _instance ??= UserLocalPreference._(); @@ -27,8 +30,9 @@ class UserLocalPreference { } User fetchUserData() { - Map userData = - jsonDecode(_sharedPreferences!.getString(_userKey)!); + String? userDataString = _sharedPreferences!.getString(_userKey); + + Map userData = jsonDecode(userDataString!); return User.fromEntity(UserEntity.fromJson(userData)); } @@ -49,6 +53,15 @@ class UserLocalPreference { } MemberStateResponse fetchMemberRights() { + String? getMemberStateString = + _sharedPreferences!.getString('memberRights'); + + if (getMemberStateString == null) { + locator().getMemberState(); + return MemberStateResponse( + success: false, errorMessage: "An error occurred"); + } + Map memberRights = jsonDecode(_sharedPreferences!.getString('memberRights')!); return MemberStateResponse.fromJson(memberRights); @@ -56,16 +69,17 @@ class UserLocalPreference { bool fetchMemberRight(int id) { MemberStateResponse memberStateResponse = fetchMemberRights(); + if (memberStateResponse.success == false || + memberStateResponse.memberRights == null) { + return true; + } final memberRights = memberStateResponse.memberRights; - if (memberRights == null) { + + final right = memberRights!.where((element) => element.state == id); + if (right.isEmpty) { return true; } else { - final right = memberRights.where((element) => element.state == id); - if (right.isEmpty) { - return true; - } else { - return right.first.isSelected; - } + return right.first.isSelected; } } @@ -92,8 +106,16 @@ class UserLocalPreference { } Future getCommunityConfigurations() async { + String? communityConfigurationString = + _sharedPreferences!.getString('communityConfigurations'); + + if (communityConfigurationString == null) { + return CommunityConfigurations(value: {}, type: '', description: ''); + } + Map communityConfigurations = - jsonDecode(_sharedPreferences!.getString('communityConfigurations')!); + jsonDecode(communityConfigurationString); + final entity = CommunityConfigurationsEntity.fromJson(communityConfigurations); return CommunityConfigurations.fromEntity(entity); diff --git a/lib/src/utils/post/post_media_picker.dart b/lib/src/utils/post/post_media_picker.dart index 395e825..9f9d9d1 100644 --- a/lib/src/utils/post/post_media_picker.dart +++ b/lib/src/utils/post/post_media_picker.dart @@ -90,7 +90,7 @@ class PostMediaPicker { // final XFile? pickedFile = List videoFiles = []; final FilePickerResult? pickedFiles = await FilePicker.platform.pickFiles( - allowMultiple: true, + allowMultiple: false, type: FileType.video, // allowedExtensions: videoExtentions, ); diff --git a/lib/src/utils/share/share_post.dart b/lib/src/utils/share/share_post.dart index bc239b3..7280b0e 100644 --- a/lib/src/utils/share/share_post.dart +++ b/lib/src/utils/share/share_post.dart @@ -14,16 +14,16 @@ class SharePost { static String userId = prodFlag ? CredsProd.botId : CredsDev.botId; static String apiKey = prodFlag ? CredsProd.apiKey : CredsDev.apiKey; // TODO: Add domain to your application - String domain = 'suraasalearn://www.suraasa.com'; + String domain = 'https://www.suraasa.com'; // fetches the domain given by client at time of initialization of Feed // below function creates a link from domain and post id String createLink(String postId) { int length = domain.length; if (domain[length - 1] == '/') { - return "${domain}post?post_id=$postId"; + return "${domain}community/post?post_id=$postId"; } else { - return "$domain/post?post_id=$postId"; + return "$domain/community/post?post_id=$postId"; } } @@ -45,17 +45,21 @@ class SharePost { } } - Future handlePostDeepLink(DeepLinkRequest request, BuildContext context) async { + Future handlePostDeepLink( + DeepLinkRequest request, + GlobalKey navigatorKey, + ) async { List secondPathSegment = request.link.split('post_id='); if (secondPathSegment.length > 1 && secondPathSegment[1] != null) { String postId = secondPathSegment[1]; - await locator().initiateUser((InitiateUserRequestBuilder() - ..apiKey(request.apiKey) - ..userId(request.userUniqueId) - ..userName(request.userName)) - .build()); + await locator() + .initiateUser((InitiateUserRequestBuilder() + ..apiKey(request.apiKey) + ..userId(request.userUniqueId) + ..userName(request.userName)) + .build()); - Navigator.of(context).push( + navigatorKey.currentState!.push( MaterialPageRoute( builder: (context) => PostDetailScreen(postId: postId), ), @@ -73,13 +77,15 @@ class SharePost { } } - Future parseDeepLink(DeepLinkRequest request, BuildContext context) async { - if (Uri.parse(request.link).isAbsolute) { - final firstPathSegment = getFirstPathSegment(request.link); - if (firstPathSegment == "post") { - return handlePostDeepLink(request, context); + Future parseDeepLink( + DeepLinkRequest request, GlobalKey navigatorKey) async { + final link = Uri.parse(request.link); + if (link.isAbsolute) { + if (link.path == '/community/post') { + return handlePostDeepLink(request, navigatorKey); } - return DeepLinkResponse(success: false, errorMessage: 'URI not supported'); + return DeepLinkResponse( + success: false, errorMessage: 'URI not supported'); } else { return DeepLinkResponse( success: false, diff --git a/lib/src/views/post/new_post_screen.dart b/lib/src/views/post/new_post_screen.dart index 58e7055..598f93e 100644 --- a/lib/src/views/post/new_post_screen.dart +++ b/lib/src/views/post/new_post_screen.dart @@ -63,6 +63,7 @@ class _NewPostScreenState extends State { bool isDocumentPost = true; // flag for document or media post bool isMediaPost = true; + bool isVideoAttached = false; bool isUploading = false; String previewLink = ''; @@ -134,6 +135,7 @@ class _NewPostScreenState extends State { isDocumentPost = true; isMediaPost = true; showLinkPreview = true; + isVideoAttached = false; } setState(() {}); } @@ -158,14 +160,20 @@ class _NewPostScreenState extends State { LMAnalytics.get().track(AnalyticsKeys.documentAttachedInPost, {'document_count': documentCount}); } else { - int imageCount = 0; - for (var element in postMedia) { - if (element.mediaType == MediaType.image) { - imageCount++; + if (postMedia.first.mediaType == MediaType.video) { + LMAnalytics.get() + .track(AnalyticsKeys.imageAttachedToPost, {'video_count': 1}); + isVideoAttached = true; + } else { + int imageCount = 0; + for (var element in postMedia) { + if (element.mediaType == MediaType.image) { + imageCount++; + } } + LMAnalytics.get().track( + AnalyticsKeys.imageAttachedToPost, {'image_count': imageCount}); } - LMAnalytics.get().track( - AnalyticsKeys.imageAttachedToPost, {'image_count': imageCount}); } } @@ -195,6 +203,7 @@ class _NewPostScreenState extends State { } else { if (postMedia.isEmpty) { isMediaPost = true; + isVideoAttached = false; showLinkPreview = true; } setState(() { @@ -207,7 +216,7 @@ class _NewPostScreenState extends State { if (uploadResponse) { isDocumentPost = true; showLinkPreview = false; - isMediaPost = true; + isMediaPost = false; setState(() { isUploading = false; }); @@ -215,6 +224,7 @@ class _NewPostScreenState extends State { if (postMedia.isEmpty) { isDocumentPost = true; isMediaPost = true; + isVideoAttached = false; showLinkPreview = true; } setState(() { @@ -613,14 +623,6 @@ class _NewPostScreenState extends State { Row( children: [ SizedBox( - // height: 180, - // width: postMedia[ - // index] - // .mediaType == - // MediaType - // .video - // ? 200 - // : 180, child: Stack( children: [ postMedia[index].mediaType == @@ -644,11 +646,13 @@ class _NewPostScreenState extends State { // 180, boxFit: BoxFit .contain, + autoPlay: false, showControls: false, // width: // 300, borderRadius: 18, + isMute: true, ), ), ) @@ -663,10 +667,6 @@ class _NewPostScreenState extends State { width: 200, color: Colors.black, child: LMImage( - // height: - // 180, - // width: - // 180, boxFit: BoxFit .contain, borderRadius: 18, @@ -806,98 +806,107 @@ class _NewPostScreenState extends State { ), //BoxShadow ], ), - child: Padding( - padding: const EdgeInsets.all(8.0), - child: Row( - mainAxisAlignment: MainAxisAlignment.start, - children: [ - isMediaPost - ? LMIconButton( - icon: LMIcon( - type: LMIconType.svg, - assetPath: kAssetGalleryIcon, - color: - Theme.of(context).colorScheme.primary, - boxPadding: 0, - size: 44, - ), - onTap: (active) async { - LMAnalytics.get().track( - AnalyticsKeys.clickedOnAttachment, - {'type': 'image'}); - final result = - await handlePermissions(context, 1); - if (result) { - pickImages(); - } - }, - ) - : const SizedBox.shrink(), - // isMediaPost - // ? const SizedBox(width: 8) - // : const SizedBox.shrink(), - // isMediaPost - // ? LMIconButton( - // icon: LMIcon( - // type: LMIconType.svg, - // assetPath: kAssetVideoIcon, - // color: - // Theme.of(context).colorScheme.primary, - // boxPadding: 0, - // size: 44, - // ), - // onTap: (active) async { - // onUploading(); - // List? pickedMediaFiles = - // await PostMediaPicker.pickVideos( - // postMedia.length); - // if (pickedMediaFiles != null) { - // setPickedMediaFiles(pickedMediaFiles); - // onUploadedMedia(true); - // } else { - // onUploadedMedia(false); - // } - // }, - // ) - // : const SizedBox.shrink(), - isDocumentPost - ? const SizedBox(width: 8) - : const SizedBox.shrink(), - isDocumentPost - ? LMIconButton( - icon: LMIcon( - type: LMIconType.svg, - assetPath: kAssetDocPDFIcon, - color: - Theme.of(context).colorScheme.primary, - boxPadding: 0, - size: 44, - ), - onTap: (active) async { - if (postMedia.length >= 3) { - // TODO: Add your own toast message for document limit - return; - } - onUploading(); - LMAnalytics.get().track( - AnalyticsKeys.clickedOnAttachment, - {'type': 'file'}); - List? pickedMediaFiles = - await PostMediaPicker.pickDocuments( - postMedia.length); - if (pickedMediaFiles != null) { - setPickedMediaFiles(pickedMediaFiles); - onUploadedDocument(true); - } else { - onUploadedDocument(false); - } - }, - ) - : const SizedBox.shrink(), - const SizedBox(width: 8), - ], - ), - ), + child: isVideoAttached + ? const SizedBox.shrink() + : Padding( + padding: const EdgeInsets.all(8.0), + child: Row( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + isMediaPost + ? LMIconButton( + icon: LMIcon( + type: LMIconType.svg, + assetPath: kAssetGalleryIcon, + color: Theme.of(context) + .colorScheme + .primary, + boxPadding: 0, + size: 44, + ), + onTap: (active) async { + LMAnalytics.get().track( + AnalyticsKeys.clickedOnAttachment, + {'type': 'image'}); + final result = + await handlePermissions( + context, 1); + if (result) { + pickImages(); + } + }, + ) + : const SizedBox.shrink(), + isMediaPost && postMedia.isEmpty + ? const SizedBox(width: 8) + : const SizedBox.shrink(), + isMediaPost && postMedia.isEmpty + ? LMIconButton( + icon: LMIcon( + type: LMIconType.svg, + assetPath: kAssetVideoIcon, + color: Theme.of(context) + .colorScheme + .primary, + boxPadding: 0, + size: 44, + ), + onTap: (active) async { + onUploading(); + List? pickedMediaFiles = + await PostMediaPicker.pickVideos( + postMedia.length); + if (pickedMediaFiles != null) { + setPickedMediaFiles( + pickedMediaFiles); + onUploadedMedia(true); + } else { + onUploadedMedia(false); + } + }, + ) + : const SizedBox.shrink(), + isDocumentPost + ? const SizedBox(width: 8) + : const SizedBox.shrink(), + isDocumentPost + ? LMIconButton( + icon: LMIcon( + type: LMIconType.svg, + assetPath: kAssetDocPDFIcon, + color: Theme.of(context) + .colorScheme + .primary, + boxPadding: 0, + size: 44, + ), + onTap: (active) async { + if (postMedia.length >= 3) { + // TODO: Add your own toast message for document limit + return; + } + onUploading(); + LMAnalytics.get().track( + AnalyticsKeys.clickedOnAttachment, + {'type': 'file'}); + List? pickedMediaFiles = + await PostMediaPicker + .pickDocuments( + postMedia.length); + if (pickedMediaFiles != null) { + setPickedMediaFiles( + pickedMediaFiles); + onUploadedDocument(true); + } else { + onUploadedDocument(false); + } + }, + ) + : const SizedBox.shrink(), + const SizedBox(width: 8), + ], + ), + ), ), ), ], diff --git a/lib/src/views/post_detail_screen.dart b/lib/src/views/post_detail_screen.dart index c51b10a..6697ee9 100644 --- a/lib/src/views/post_detail_screen.dart +++ b/lib/src/views/post_detail_screen.dart @@ -73,8 +73,6 @@ class _PostDetailScreenState extends State { _addCommentBloc.close(); _addCommentReplyBloc.close(); _pagingController.dispose(); - _commentController?.dispose(); - focusNode.dispose(); rebuildButton.dispose(); rebuildPostWidget.dispose(); rebuildReplyWidget.dispose(); @@ -267,7 +265,7 @@ class _PostDetailScreenState extends State { bool checkCommentRights() { final MemberStateResponse memberStateResponse = UserLocalPreference.instance.fetchMemberRights(); - if (memberStateResponse.state == 1) { + if (!memberStateResponse.success || memberStateResponse.state == 1) { return true; } bool memberRights = UserLocalPreference.instance.fetchMemberRight(10); @@ -303,882 +301,885 @@ class _PostDetailScreenState extends State { create: (context) => _toggleLikeCommentBloc, ), ], - child: Scaffold( - resizeToAvoidBottomInset: true, - bottomSheet: ValueListenableBuilder( - valueListenable: rebuildPostWidget, - builder: (context, _, __) { - return postData == null - ? const SizedBox() - : SafeArea( - child: BlocConsumer( - bloc: _addCommentReplyBloc, - listener: (context, state) { - if (state is ReplyCommentCanceled) { - deselectCommentToReply(); - } - if (state is EditCommentCanceled) { - deselectCommentToEdit(); - } - if (state is CommentDeleted) { - removeCommentFromList(state.commentId); - } - if (state is EditReplyLoading) { - deselectCommentToEdit(); - } - if (state is ReplyEditingStarted) { - selectCommentToEdit( - state.commentId, state.replyId, state.text); - } - if (state is EditCommentLoading) { - deselectCommentToEdit(); - } - if (state is CommentEditingStarted) { - selectCommentToEdit( - state.commentId, null, state.text); - } - if (state is AddCommentReplySuccess) { - debugPrint("AddCommentReplySuccess"); - _commentController!.clear(); - addReplyToList(state); - deselectCommentToReply(); - } - if (state is AddCommentReplyError) { - deselectCommentToReply(); - } - if (state is EditCommentSuccess) { - updateCommentInList(state); - } - if (state is EditReplySuccess) {} - }, - builder: (context, state) => Container( - decoration: BoxDecoration( - color: kWhiteColor, - boxShadow: [ - BoxShadow( - color: Colors.black.withOpacity(0.1), - blurRadius: 10, - offset: const Offset(0, -5), - ), - ], - ), - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - kVerticalPaddingMedium, - ValueListenableBuilder( - valueListenable: rebuildReplyWidget, - builder: (context, _, __) { - return isEditing || isReplying - ? Container( - padding: - const EdgeInsets.symmetric( - horizontal: 16, - vertical: 8), - child: Row( - children: [ - LMTextView( - text: isEditing - ? "Editing ${selectedReplyId != null ? 'reply' : 'comment'}" - : "Replying to", - textStyle: const TextStyle( - fontSize: 14, - fontWeight: - FontWeight.w500, - color: kGrey1Color, + child: Theme( + data: suraasaTheme, + child: Scaffold( + resizeToAvoidBottomInset: true, + bottomSheet: ValueListenableBuilder( + valueListenable: rebuildPostWidget, + builder: (context, _, __) { + return postData == null + ? const SizedBox() + : SafeArea( + child: BlocConsumer( + bloc: _addCommentReplyBloc, + listener: (context, state) { + if (state is ReplyCommentCanceled) { + deselectCommentToReply(); + } + if (state is EditCommentCanceled) { + deselectCommentToEdit(); + } + if (state is CommentDeleted) { + removeCommentFromList(state.commentId); + } + if (state is EditReplyLoading) { + deselectCommentToEdit(); + } + if (state is ReplyEditingStarted) { + selectCommentToEdit( + state.commentId, state.replyId, state.text); + } + if (state is EditCommentLoading) { + deselectCommentToEdit(); + } + if (state is CommentEditingStarted) { + selectCommentToEdit( + state.commentId, null, state.text); + } + if (state is AddCommentReplySuccess) { + debugPrint("AddCommentReplySuccess"); + _commentController!.clear(); + addReplyToList(state); + deselectCommentToReply(); + } + if (state is AddCommentReplyError) { + deselectCommentToReply(); + } + if (state is EditCommentSuccess) { + updateCommentInList(state); + } + if (state is EditReplySuccess) {} + }, + builder: (context, state) => Container( + decoration: BoxDecoration( + color: kWhiteColor, + boxShadow: [ + BoxShadow( + color: Colors.black.withOpacity(0.1), + blurRadius: 10, + offset: const Offset(0, -5), + ), + ], + ), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + kVerticalPaddingMedium, + ValueListenableBuilder( + valueListenable: rebuildReplyWidget, + builder: (context, _, __) { + return isEditing || isReplying + ? Container( + padding: + const EdgeInsets.symmetric( + horizontal: 16, + vertical: 8), + child: Row( + children: [ + LMTextView( + text: isEditing + ? "Editing ${selectedReplyId != null ? 'reply' : 'comment'}" + : "Replying to", + textStyle: const TextStyle( + fontSize: 14, + fontWeight: + FontWeight.w500, + color: kGrey1Color, + ), ), - ), - const SizedBox( - width: 8, - ), - isEditing - ? const SizedBox() - : LMTextView( - text: - selectedUsername!, - textStyle: - const TextStyle( - fontSize: 14, - fontWeight: - FontWeight.w500, - color: kLinkColor, + const SizedBox( + width: 8, + ), + isEditing + ? const SizedBox() + : LMTextView( + text: + selectedUsername!, + textStyle: + const TextStyle( + fontSize: 14, + fontWeight: + FontWeight.w500, + color: kLinkColor, + ), ), - ), - const Spacer(), - LMIconButton( - onTap: (active) { - if (isEditing) { - if (selectedReplyId != - null) { - _addCommentReplyBloc.add( - EditReplyCancel()); + const Spacer(), + LMIconButton( + onTap: (active) { + if (isEditing) { + if (selectedReplyId != + null) { + _addCommentReplyBloc.add( + EditReplyCancel()); + } else { + _addCommentReplyBloc.add( + EditCommentCancel()); + } + deselectCommentToEdit(); } else { - _addCommentReplyBloc.add( - EditCommentCancel()); + deselectCommentToReply(); } - deselectCommentToEdit(); - } else { - deselectCommentToReply(); - } - }, - icon: const LMIcon( - type: LMIconType.icon, - icon: Icons.close, - color: kGreyColor, - size: 24, + }, + icon: const LMIcon( + type: LMIconType.icon, + icon: Icons.close, + color: kGreyColor, + size: 24, + ), ), - ), - ], - ), - ) - : const SizedBox(); - }), - Container( - decoration: BoxDecoration( - color: kPrimaryColor.withOpacity(0.04), - borderRadius: BorderRadius.circular(24)), - margin: const EdgeInsets.symmetric( - horizontal: 8.0), - padding: const EdgeInsets.all(3.0), - child: Row( - children: [ - LMProfilePicture( - fallbackText: currentUser.name, - imageUrl: currentUser.imageUrl, - onTap: () { - if (currentUser.sdkClientInfo != - null) { - locator() - .routeToProfile(currentUser - .sdkClientInfo! - .userUniqueId); - } - }, - size: 36, - ), - Expanded( - child: TaggingAheadTextField( - isDown: false, - maxLines: 5, - onTagSelected: (tag) { - userTags.add(tag); + ], + ), + ) + : const SizedBox(); + }), + Container( + decoration: BoxDecoration( + color: kPrimaryColor.withOpacity(0.04), + borderRadius: BorderRadius.circular(24)), + margin: const EdgeInsets.symmetric( + horizontal: 8.0), + padding: const EdgeInsets.all(3.0), + child: Row( + children: [ + LMProfilePicture( + fallbackText: currentUser.name, + imageUrl: currentUser.imageUrl, + onTap: () { + if (currentUser.sdkClientInfo != + null) { + locator() + .routeToProfile(currentUser + .sdkClientInfo! + .userUniqueId); + } }, - controller: _commentController!, - decoration: InputDecoration( - enabled: right, - border: InputBorder.none, - hintText: right - ? 'Write a comment' - : "You do not have permission to comment.", + size: 36, + ), + Expanded( + child: TaggingAheadTextField( + isDown: false, + maxLines: 5, + onTagSelected: (tag) { + userTags.add(tag); + }, + controller: _commentController!, + decoration: InputDecoration( + enabled: right, + border: InputBorder.none, + hintText: right + ? 'Write a comment' + : "You do not have permission to comment.", + ), + focusNode: focusNode, + onChange: (String p0) {}, ), - focusNode: focusNode, - onChange: (String p0) {}, ), - ), - Container( - padding: const EdgeInsets.symmetric( - horizontal: 8.0), - child: !right - ? null - : ValueListenableBuilder( - valueListenable: - rebuildReplyWidget, - builder: (context, _, __) => - isReplying || isEditing - ? BlocConsumer< - AddCommentReplyBloc, - AddCommentReplyState>( - bloc: - _addCommentReplyBloc, - listener: (context, - state) {}, - buildWhen: - (previous, - current) { - if (current - is ReplyEditingStarted) { - return false; - } - if (current - is EditReplyLoading) { - return false; - } - if (current - is CommentEditingStarted) { - return false; - } - if (current - is EditCommentLoading) { - return false; - } - return true; - }, - builder: (context, - state) { - if (state - is AddCommentReplyLoading) { - return const SizedBox( - height: 15, - width: 15, - child: - CircularProgressIndicator( - strokeWidth: - 2, - ), - ); - } - return ValueListenableBuilder( - valueListenable: - rebuildButton, - builder: ( - context, - s, - a, - ) { - return LMTextButton( - text: - LMTextView( + Container( + padding: const EdgeInsets.symmetric( + horizontal: 8.0), + child: !right + ? null + : ValueListenableBuilder( + valueListenable: + rebuildReplyWidget, + builder: (context, _, __) => + isReplying || isEditing + ? BlocConsumer< + AddCommentReplyBloc, + AddCommentReplyState>( + bloc: + _addCommentReplyBloc, + listener: (context, + state) {}, + buildWhen: + (previous, + current) { + if (current + is ReplyEditingStarted) { + return false; + } + if (current + is EditReplyLoading) { + return false; + } + if (current + is CommentEditingStarted) { + return false; + } + if (current + is EditCommentLoading) { + return false; + } + return true; + }, + builder: (context, + state) { + if (state + is AddCommentReplyLoading) { + return const SizedBox( + height: 15, + width: 15, + child: + CircularProgressIndicator( + strokeWidth: + 2, + ), + ); + } + return ValueListenableBuilder( + valueListenable: + rebuildButton, + builder: ( + context, + s, + a, + ) { + return LMTextButton( text: - "Post", - textStyle: - TextStyle( - color: right - ? kPrimaryColor - : Colors.transparent, - fontSize: - 12.5, + LMTextView( + text: + "Post", + textStyle: + TextStyle( + color: right + ? kPrimaryColor + : Colors.transparent, + fontSize: + 12.5, + ), ), - ), - onTap: - () { - closeOnScreenKeyboard(); - String commentText = TaggingHelper.encodeString( - _commentController!.text, - userTags); - commentText = - commentText.trim(); - if (commentText - .isEmpty) { - toast( - "Please write something to post"); - return; - } + onTap: + () { + closeOnScreenKeyboard(); + String commentText = TaggingHelper.encodeString( + _commentController!.text, + userTags); + commentText = + commentText.trim(); + if (commentText + .isEmpty) { + toast( + "Please write something to post"); + return; + } - if (isEditing) { - if (selectedReplyId != - null) { - _addCommentReplyBloc.add( - EditReply( - editCommentReplyRequest: (EditCommentReplyRequestBuilder() - ..postId(widget.postId) - ..text(commentText) - ..commentId(selectedCommentId!) - ..replyId(selectedReplyId!)) - .build(), - ), - ); + if (isEditing) { + if (selectedReplyId != + null) { + _addCommentReplyBloc.add( + EditReply( + editCommentReplyRequest: (EditCommentReplyRequestBuilder() + ..postId(widget.postId) + ..text(commentText) + ..commentId(selectedCommentId!) + ..replyId(selectedReplyId!)) + .build(), + ), + ); + } else { + _addCommentReplyBloc.add( + EditComment( + editCommentRequest: (EditCommentRequestBuilder() + ..postId(widget.postId) + ..text(commentText) + ..commentId(selectedCommentId!)) + .build(), + ), + ); + } } else { - _addCommentReplyBloc.add( - EditComment( - editCommentRequest: (EditCommentRequestBuilder() - ..postId(widget.postId) - ..text(commentText) - ..commentId(selectedCommentId!)) - .build(), - ), - ); - } - } else { - _addCommentReplyBloc - .add(AddCommentReply( - addCommentRequest: (AddCommentReplyRequestBuilder() - ..postId(widget.postId) - ..text(commentText) - ..commentId(selectedCommentId!)) - .build(), - userId: - selectedUserId ?? '', - )); + _addCommentReplyBloc + .add(AddCommentReply( + addCommentRequest: (AddCommentReplyRequestBuilder() + ..postId(widget.postId) + ..text(commentText) + ..commentId(selectedCommentId!)) + .build(), + userId: + selectedUserId ?? '', + )); - _commentController - ?.clear(); - } - }, - ); - }); - }, - ) - : BlocConsumer< - AddCommentBloc, - AddCommentState>( - bloc: - _addCommentBloc, - listener: (context, - state) { - if (state - is AddCommentSuccess) { - addCommentToList( - state); - } - if (state - is AddCommentLoading) { - deselectCommentToEdit(); - } - }, - builder: (context, - state) { - if (state - is AddCommentLoading) { - return const SizedBox( - height: 15, - width: 15, - child: - CircularProgressIndicator( - strokeWidth: - 2, - ), - ); - } - return ValueListenableBuilder( - valueListenable: - rebuildButton, - builder: - (context, - s, - a) { - return LMTextButton( - height: - 18, - text: - const LMTextView( + _commentController + ?.clear(); + } + }, + ); + }); + }, + ) + : BlocConsumer< + AddCommentBloc, + AddCommentState>( + bloc: + _addCommentBloc, + listener: (context, + state) { + if (state + is AddCommentSuccess) { + addCommentToList( + state); + } + if (state + is AddCommentLoading) { + deselectCommentToEdit(); + } + }, + builder: (context, + state) { + if (state + is AddCommentLoading) { + return const SizedBox( + height: 15, + width: 15, + child: + CircularProgressIndicator( + strokeWidth: + 2, + ), + ); + } + return ValueListenableBuilder( + valueListenable: + rebuildButton, + builder: + (context, + s, + a) { + return LMTextButton( + height: + 18, text: - "Post", - textAlign: - TextAlign.center, - textStyle: - TextStyle( - fontSize: - 12.5, - color: - kPrimaryColor, + const LMTextView( + text: + "Post", + textAlign: + TextAlign.center, + textStyle: + TextStyle( + fontSize: + 12.5, + color: + kPrimaryColor, + ), ), - ), - onTap: - () { - closeOnScreenKeyboard(); - String - commentText = - TaggingHelper.encodeString( - _commentController! - .text, - userTags, - ); - commentText = - commentText.trim(); - if (commentText - .isEmpty) { - toast( - "Please write something to post"); - return; - } + onTap: + () { + closeOnScreenKeyboard(); + String + commentText = + TaggingHelper.encodeString( + _commentController! + .text, + userTags, + ); + commentText = + commentText.trim(); + if (commentText + .isEmpty) { + toast( + "Please write something to post"); + return; + } - if (postDetailResponse != - null) { - postDetailResponse!.users?.putIfAbsent( - currentUser.userUniqueId, - () => currentUser); - } + if (postDetailResponse != + null) { + postDetailResponse!.users?.putIfAbsent( + currentUser.userUniqueId, + () => currentUser); + } - _addCommentBloc - .add( - AddComment( - addCommentRequest: (AddCommentRequestBuilder() - ..postId(widget.postId) - ..text(commentText)) - .build(), - ), - ); + _addCommentBloc + .add( + AddComment( + addCommentRequest: (AddCommentRequestBuilder() + ..postId(widget.postId) + ..text(commentText)) + .build(), + ), + ); - closeOnScreenKeyboard(); - _commentController - ?.clear(); - }, - ); - }); - }, - ), - ), - ), - ], + closeOnScreenKeyboard(); + _commentController + ?.clear(); + }, + ); + }); + }, + ), + ), + ), + ], + ), ), - ), - kVerticalPaddingLarge, - ], + kVerticalPaddingLarge, + ], + ), ), ), - ), - ); - }, - ), - backgroundColor: kBackgroundColor, - appBar: AppBar( - leading: LMIconButton( - icon: const LMIcon( - type: LMIconType.icon, - icon: Icons.arrow_back_ios, - color: kPrimaryColor, - size: 28, - ), - onTap: (active) { - Navigator.pop(context); + ); }, - containerSize: 48, ), - backgroundColor: kWhiteColor, - title: const LMTextView( - text: "Comments", - textStyle: TextStyle( - fontSize: 20, - fontWeight: FontWeight.w500, - color: kHeadingColor, + backgroundColor: kBackgroundColor, + appBar: AppBar( + leading: LMIconButton( + icon: const LMIcon( + type: LMIconType.icon, + icon: Icons.arrow_back_ios, + color: kPrimaryColor, + size: 28, + ), + onTap: (active) { + Navigator.pop(context); + }, + containerSize: 48, ), + backgroundColor: Colors.white, + title:const LMTextView( + text: "Comments", + textStyle: TextStyle( + fontSize: 20, + fontWeight: FontWeight.w500, + color: kHeadingColor, + ), + ), + elevation: 1, ), - elevation: 1, - ), - body: BlocConsumer( - listener: (context, state) { - if (state is AllCommentsLoaded) { - _page++; - if (state.postDetails.postReplies!.replies.length < 10) { - _pagingController - .appendLastPage(state.postDetails.postReplies!.replies); - } else { - _pagingController.appendPage( - state.postDetails.postReplies!.replies, _page); - } - } - }, - bloc: _allCommentsBloc, - builder: (context, state) { - if (state is AllCommentsLoaded || - state is PaginatedAllCommentsLoading) { + body: BlocConsumer( + listener: (context, state) { if (state is AllCommentsLoaded) { - debugPrint("AllCommentsLoaded$state"); - postDetailResponse = state.postDetails; - postDetailResponse!.users!.putIfAbsent( - currentUser.userUniqueId, () => currentUser); - } else { - debugPrint("PaginatedAllCommentsLoading$state"); - postDetailResponse = - (state as PaginatedAllCommentsLoading).prevPostDetails; - postDetailResponse!.users!.putIfAbsent( - currentUser.userUniqueId, () => currentUser); + _page++; + if (state.postDetails.postReplies!.replies.length < 10) { + _pagingController + .appendLastPage(state.postDetails.postReplies!.replies); + } else { + _pagingController.appendPage( + state.postDetails.postReplies!.replies, _page); + } } - return RefreshIndicator( - onRefresh: () async { - await updatePostDetails(context); - _commentRepliesBloc.add(ClearCommentReplies()); - _pagingController.refresh(); - _page = 1; - }, - child: ValueListenableBuilder( - valueListenable: rebuildPostWidget, - builder: (context, _, __) { - return BlocListener( - bloc: newPostBloc, - listener: (context, state) { - if (state is EditPostUploaded) { - postData = state.postData; - rebuildPostWidget.value = - !rebuildPostWidget.value; - } - if (state is PostUpdateState) { - postData = state.post; - } - }, - child: CustomScrollView( - slivers: [ - const SliverPadding( - padding: EdgeInsets.only(top: 16)), - SliverToBoxAdapter( - child: postData == null - ? const Center( - child: CircularProgressIndicator( - color: kPrimaryColor, - ), - ) - : GestureDetector( - onTap: () { - closeOnScreenKeyboard(); - }, - behavior: HitTestBehavior.translucent, - child: Container( - color: Colors.transparent, - child: SSPostWidget( - post: postData!, - topics: - postDetailResponse!.topics ?? - {}, - user: postDetailResponse!.users![ - postDetailResponse! - .postReplies!.userId]!, - onTap: () {}, - isFeed: false, - refresh: (bool isDeleted) async { - if (isDeleted) { - Navigator.pop(context); - } - }, + }, + bloc: _allCommentsBloc, + builder: (context, state) { + if (state is AllCommentsLoaded || + state is PaginatedAllCommentsLoading) { + if (state is AllCommentsLoaded) { + debugPrint("AllCommentsLoaded$state"); + postDetailResponse = state.postDetails; + postDetailResponse!.users!.putIfAbsent( + currentUser.userUniqueId, () => currentUser); + } else { + debugPrint("PaginatedAllCommentsLoading$state"); + postDetailResponse = + (state as PaginatedAllCommentsLoading).prevPostDetails; + postDetailResponse!.users!.putIfAbsent( + currentUser.userUniqueId, () => currentUser); + } + return RefreshIndicator( + onRefresh: () async { + await updatePostDetails(context); + _commentRepliesBloc.add(ClearCommentReplies()); + _pagingController.refresh(); + _page = 1; + }, + child: ValueListenableBuilder( + valueListenable: rebuildPostWidget, + builder: (context, _, __) { + return BlocListener( + bloc: newPostBloc, + listener: (context, state) { + if (state is EditPostUploaded) { + postData = state.postData; + rebuildPostWidget.value = + !rebuildPostWidget.value; + } + if (state is PostUpdateState) { + postData = state.post; + } + }, + child: CustomScrollView( + slivers: [ + const SliverPadding( + padding: EdgeInsets.only(top: 16)), + SliverToBoxAdapter( + child: postData == null + ? const Center( + child: CircularProgressIndicator( + color: kPrimaryColor, + ), + ) + : GestureDetector( + onTap: () { + closeOnScreenKeyboard(); + }, + behavior: HitTestBehavior.translucent, + child: Container( + color: Colors.transparent, + child: SSPostWidget( + post: postData!, + topics: + postDetailResponse!.topics ?? + {}, + user: postDetailResponse!.users![ + postDetailResponse! + .postReplies!.userId]!, + onTap: () {}, + isFeed: false, + refresh: (bool isDeleted) async { + if (isDeleted) { + Navigator.pop(context); + } + }, + ), ), ), - ), - ), - const SliverPadding( - padding: EdgeInsets.only(bottom: 12), - ), - postData == null - ? const SliverToBoxAdapter( - child: SizedBox(), - ) - : PagedSliverList( - pagingController: _pagingController, - builderDelegate: - PagedChildBuilderDelegate( - noMoreItemsIndicatorBuilder: - (context) => - const SizedBox(height: 75), - noItemsFoundIndicatorBuilder: - (context) => const Column( - children: [ - SizedBox(height: 42), - Text( - 'No comment found', - style: TextStyle( - fontSize: kFontMedium, + ), + const SliverPadding( + padding: EdgeInsets.only(bottom: 12), + ), + postData == null + ? const SliverToBoxAdapter( + child: SizedBox(), + ) + : PagedSliverList( + pagingController: _pagingController, + builderDelegate: + PagedChildBuilderDelegate( + noMoreItemsIndicatorBuilder: + (context) => + const SizedBox(height: 75), + noItemsFoundIndicatorBuilder: + (context) => const Column( + children: [ + SizedBox(height: 42), + Text( + 'No comment found', + style: TextStyle( + fontSize: kFontMedium, + ), ), - ), - SizedBox(height: 12), - Text( - 'Be the first one to comment', - style: TextStyle( - fontSize: kFontSmall, + SizedBox(height: 12), + Text( + 'Be the first one to comment', + style: TextStyle( + fontSize: kFontSmall, + ), ), - ), - SizedBox(height: 180), - ], - ), - itemBuilder: (context, item, index) { - bool replyShown = false; - return Container( - decoration: const BoxDecoration( - color: kWhiteColor, - border: Border( - bottom: BorderSide( - width: 0.2, - color: Colors.black45, + SizedBox(height: 180), + ], + ), + itemBuilder: (context, item, index) { + bool replyShown = false; + return Container( + decoration: const BoxDecoration( + color: kWhiteColor, + border: Border( + bottom: BorderSide( + width: 0.2, + color: Colors.black45, + ), ), ), - ), - child: Column( - children: [ - StatefulBuilder(builder: - (context, - setCommentState) { - item.menuItems.removeWhere( - (element) => - element.id == - commentReportId || - element.id == - commentEditId); - return LMCommentTile( - key: ValueKey(item.id), - onTagTap: - (String userId) { - locator() - .routeToProfile( - userId); - }, - onMenuTap: (id) { - if (id == - commentDeleteId) { - deselectCommentToEdit(); - deselectCommentToReply(); - // Delete post - showDialog( - context: context, - builder: - (childContext) => - deleteConfirmationDialog( - childContext, - title: - 'Delete Comment', - userId: - item.userId, - content: - 'Are you sure you want to delete this post. This action can not be reversed.', - action: (String - reason) async { - Navigator.of(childContext) - .pop(); - //Implement delete post analytics tracking - LMAnalytics.get() - .track( - AnalyticsKeys.commentDeleted, - { - "post_id": widget.postId, - "comment_id": item.id, - }, - ); - if (postDetailResponse != - null) { - postDetailResponse!.users?.putIfAbsent(currentUser.userUniqueId, - () => currentUser); - } - _addCommentReplyBloc.add(DeleteComment((DeleteCommentRequestBuilder() - ..postId(widget.postId) - ..commentId(item.id) - ..reason(reason.isEmpty ? "Reason for deletion" : reason)) - .build())); - }, - actionText: - 'Delete', - )); - } else if (id == - commentEditId) { - debugPrint( - 'Editing functionality'); - _addCommentReplyBloc.add( - EditCommentCancel()); - _addCommentReplyBloc - .add( - EditingComment( - commentId: - item.id, - text: item.text, - ), - ); - } - }, - comment: item, - user: postDetailResponse! - .users![item.userId]!, - profilePicture: - LMProfilePicture( - fallbackText: - postDetailResponse! - .users![item - .userId]! - .name, - onTap: () { - if (postDetailResponse! - .users![item - .userId]! - .sdkClientInfo != - null) { - locator().routeToProfile( - postDetailResponse! - .users![item - .userId]! - .sdkClientInfo! - .userUniqueId); - } + child: Column( + children: [ + StatefulBuilder(builder: + (context, + setCommentState) { + item.menuItems.removeWhere( + (element) => + element.id == + commentReportId || + element.id == + commentEditId); + return LMCommentTile( + key: ValueKey(item.id), + onTagTap: + (String userId) { + locator() + .routeToProfile( + userId); }, - imageUrl: - postDetailResponse! - .users![item - .userId]! - .imageUrl, - size: 36, - backgroundColor: - kPrimaryColor, - ), - subtitleText: LMTextView( - text: - "@${postDetailResponse!.users![item.userId]!.name.toLowerCase().split(' ').join()} · ${timeago.format(item.createdAt)}", - textStyle: - const TextStyle( - fontSize: 12, - fontWeight: - FontWeight.w400, - color: - kSecondaryColor700, - ), - ), - actionsPadding: - const EdgeInsets.only( - left: 48), - commentActions: [ - LMTextButton( - margin: 10, - text: LMTextView( - text: item.likesCount == - 0 - ? "Like" - : item.likesCount == - 1 - ? "1 Like" - : "${item.likesCount} Likes", - textStyle: - const TextStyle( - color: - kSecondaryColor700, - fontSize: - 12), - ), - activeText: - LMTextView( - text: item.likesCount == - 0 - ? "Like" - : item.likesCount == - 1 - ? "1 Like" - : "${item.likesCount} Likes", - textStyle: - const TextStyle( - color: - kPrimaryColor, - fontSize: - 12), - ), - onTap: () { - _toggleLikeCommentBloc + onMenuTap: (id) { + if (id == + commentDeleteId) { + deselectCommentToEdit(); + deselectCommentToReply(); + // Delete post + showDialog( + context: context, + builder: + (childContext) => + deleteConfirmationDialog( + childContext, + title: + 'Delete Comment', + userId: + item.userId, + content: + 'Are you sure you want to delete this post. This action can not be reversed.', + action: (String + reason) async { + Navigator.of(childContext) + .pop(); + //Implement delete post analytics tracking + LMAnalytics.get() + .track( + AnalyticsKeys.commentDeleted, + { + "post_id": widget.postId, + "comment_id": item.id, + }, + ); + if (postDetailResponse != + null) { + postDetailResponse!.users?.putIfAbsent(currentUser.userUniqueId, + () => currentUser); + } + _addCommentReplyBloc.add(DeleteComment((DeleteCommentRequestBuilder() + ..postId(widget.postId) + ..commentId(item.id) + ..reason(reason.isEmpty ? "Reason for deletion" : reason)) + .build())); + }, + actionText: + 'Delete', + )); + } else if (id == + commentEditId) { + debugPrint( + 'Editing functionality'); + _addCommentReplyBloc.add( + EditCommentCancel()); + _addCommentReplyBloc .add( - ToggleLikeComment( - toggleLikeCommentRequest: - (ToggleLikeCommentRequestBuilder() - ..commentId( - item.id) - ..postId( - widget.postId)) - .build(), + EditingComment( + commentId: + item.id, + text: item.text, ), ); - setCommentState(() { - if (item - .isLiked) { - item.likesCount -= - 1; - } else { - item.likesCount += - 1; - } - item.isLiked = - !item.isLiked; - }); - }, - icon: const LMIcon( - type: - LMIconType.svg, - assetPath: - kAssetLikeIcon, - size: 20, - ), - activeIcon: - const LMIcon( - type: - LMIconType.svg, - assetPath: - kAssetLikeFilledIcon, - size: 20, - ), - isActive: - item.isLiked, - ), - const SizedBox( - width: 12), - Row( - children: [ - LMTextButton( - margin: 10, - text: - const LMTextView( - text: - "Reply", - textStyle: - TextStyle( - fontSize: - 12, - )), - onTap: () { - selectCommentToReply( - item.id, + } + }, + comment: item, + user: postDetailResponse! + .users![item.userId]!, + profilePicture: + LMProfilePicture( + fallbackText: + postDetailResponse! + .users![item + .userId]! + .name, + onTap: () { + if (postDetailResponse! + .users![item + .userId]! + .sdkClientInfo != + null) { + locator().routeToProfile( postDetailResponse! .users![item .userId]! - .name, - item.userId, - ); - }, - icon: - const LMIcon( - type: LMIconType - .svg, - assetPath: - kAssetCommentIcon, - size: 20, - ), + .sdkClientInfo! + .userUniqueId); + } + }, + imageUrl: + postDetailResponse! + .users![item + .userId]! + .imageUrl, + size: 36, + backgroundColor: + kPrimaryColor, + ), + subtitleText: LMTextView( + text: + "@${postDetailResponse!.users![item.userId]!.name.toLowerCase().split(' ').join()} · ${timeago.format(item.createdAt)}", + textStyle: + const TextStyle( + fontSize: 12, + fontWeight: + FontWeight.w400, + color: + kSecondaryColor700, + ), + ), + actionsPadding: + const EdgeInsets.only( + left: 48), + commentActions: [ + LMTextButton( + margin: 10, + text: LMTextView( + text: item.likesCount == + 0 + ? "Like" + : item.likesCount == + 1 + ? "1 Like" + : "${item.likesCount} Likes", + textStyle: + const TextStyle( + color: + kSecondaryColor700, + fontSize: + 12), ), - kHorizontalPaddingMedium, - item.repliesCount > - 0 - ? LMTextButton( - onTap: () { - if (!replyShown) { - _commentRepliesBloc.add(GetCommentReplies( - commentDetailRequest: (GetCommentRequestBuilder() - ..commentId(item.id) - ..postId(widget.postId) - ..page(1)) - .build(), - forLoadMore: true)); - replyShown = - true; - } - }, - text: - LMTextView( + activeText: + LMTextView( + text: item.likesCount == + 0 + ? "Like" + : item.likesCount == + 1 + ? "1 Like" + : "${item.likesCount} Likes", + textStyle: + const TextStyle( + color: + kPrimaryColor, + fontSize: + 12), + ), + onTap: () { + _toggleLikeCommentBloc + .add( + ToggleLikeComment( + toggleLikeCommentRequest: + (ToggleLikeCommentRequestBuilder() + ..commentId( + item.id) + ..postId( + widget.postId)) + .build(), + ), + ); + setCommentState(() { + if (item + .isLiked) { + item.likesCount -= + 1; + } else { + item.likesCount += + 1; + } + item.isLiked = + !item.isLiked; + }); + }, + icon: const LMIcon( + type: + LMIconType.svg, + assetPath: + kAssetLikeIcon, + size: 20, + ), + activeIcon: + const LMIcon( + type: + LMIconType.svg, + assetPath: + kAssetLikeFilledIcon, + size: 20, + ), + isActive: + item.isLiked, + ), + const SizedBox( + width: 12), + Row( + children: [ + LMTextButton( + margin: 10, + text: + const LMTextView( + text: + "Reply", + textStyle: + TextStyle( + fontSize: + 12, + )), + onTap: () { + selectCommentToReply( + item.id, + postDetailResponse! + .users![item + .userId]! + .name, + item.userId, + ); + }, + icon: + const LMIcon( + type: LMIconType + .svg, + assetPath: + kAssetCommentIcon, + size: 20, + ), + ), + kHorizontalPaddingMedium, + item.repliesCount > + 0 + ? LMTextButton( + onTap: () { + if (!replyShown) { + _commentRepliesBloc.add(GetCommentReplies( + commentDetailRequest: (GetCommentRequestBuilder() + ..commentId(item.id) + ..postId(widget.postId) + ..page(1)) + .build(), + forLoadMore: true)); + replyShown = + true; + } + }, text: - "${item.repliesCount} ${item.repliesCount > 1 ? 'Replies' : 'Reply'}", - textStyle: - const TextStyle( - color: - kPrimaryColor, + LMTextView( + text: + "${item.repliesCount} ${item.repliesCount > 1 ? 'Replies' : 'Reply'}", + textStyle: + const TextStyle( + color: + kPrimaryColor, + ), ), - ), - ) - : const SizedBox() - ], - ), - ], - ); - }), - CommentReplyWidget( - refresh: () { - _pagingController - .refresh(); - }, - postId: widget.postId, - reply: item, - user: postDetailResponse! - .users![item.userId]!, - ), - ], - ), - ); - }, + ) + : const SizedBox() + ], + ), + ], + ); + }), + CommentReplyWidget( + refresh: () { + _pagingController + .refresh(); + }, + postId: widget.postId, + reply: item, + user: postDetailResponse! + .users![item.userId]!, + ), + ], + ), + ); + }, + ), ), - ), - ], - ), - ); - }), - ); - } - return const Center(child: CircularProgressIndicator()); - }, - )), + ], + ), + ); + }), + ); + } + return const Center(child: CircularProgressIndicator()); + }, + )), + ), ), ); } diff --git a/lib/src/views/universal_feed_page.dart b/lib/src/views/universal_feed_page.dart index 0810ffa..7347ce1 100644 --- a/lib/src/views/universal_feed_page.dart +++ b/lib/src/views/universal_feed_page.dart @@ -28,6 +28,7 @@ import 'package:overlay_support/overlay_support.dart'; class UniversalFeedScreen extends StatefulWidget { final Function(BuildContext context)? openChatCallback; + const UniversalFeedScreen({ this.openChatCallback, super.key, @@ -44,10 +45,13 @@ class _UniversalFeedScreenState extends State { * it is set to 62 if the topics are not empty */ final ScrollController _controller = ScrollController(); + // notifies value listenable builder to rebuild the topic feed ValueNotifier rebuildTopicFeed = ValueNotifier(false); + // future to get the topics Future? getTopicsResponse; + // list of selected topics by the user List selectedTopics = []; bool topicVisible = true; @@ -94,7 +98,7 @@ class _UniversalFeedScreenState extends State { bool checkPostCreationRights() { final MemberStateResponse memberStateResponse = UserLocalPreference.instance.fetchMemberRights(); - if (memberStateResponse.state == 1) { + if (!memberStateResponse.success || memberStateResponse.state == 1) { return true; } final memberRights = UserLocalPreference.instance.fetchMemberRight(9); @@ -486,6 +490,7 @@ class _UniversalFeedScreenState extends State { class FeedRoomErrorView extends StatelessWidget { final String message; + const FeedRoomErrorView({super.key, required this.message}); @override @@ -561,7 +566,7 @@ class _FeedRoomViewState extends State { bool checkPostCreationRights() { final MemberStateResponse memberStateResponse = UserLocalPreference.instance.fetchMemberRights(); - if (memberStateResponse.state == 1) { + if (!memberStateResponse.success || memberStateResponse.state == 1) { return true; } final memberRights = UserLocalPreference.instance.fetchMemberRight(9); @@ -569,6 +574,7 @@ class _FeedRoomViewState extends State { } var iconContainerHeight = 90.00; + @override void initState() { super.initState(); diff --git a/lib/src/widgets/media_widget.dart b/lib/src/widgets/media_widget.dart index c6300e8..7cdc800 100644 --- a/lib/src/widgets/media_widget.dart +++ b/lib/src/widgets/media_widget.dart @@ -72,7 +72,7 @@ class _SSPostMediaState extends State { documentIcon: const LMIcon( type: LMIconType.svg, assetPath: kAssetPDFIcon, - size: 20, + size: 12, ), size: PostHelper.getFileSizeString(bytes: e.attachmentMeta.size!), documentUrl: e.attachmentMeta.url, diff --git a/pubspec.lock b/pubspec.lock index 4a4bbe7..1595650 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -25,6 +25,14 @@ packages: url: "https://pub.dev" source: hosted version: "5.13.0" + archive: + dependency: transitive + description: + name: archive + sha256: "0da817eab9833cc222ee5575789664e99f60fe0c554be55dc1979f9b4ec6dd73" + url: "https://pub.dev" + source: hosted + version: "3.4.8" args: dependency: transitive description: @@ -125,26 +133,26 @@ packages: dependency: transitive description: name: cached_network_image - sha256: fd3d0dc1d451f9a252b32d95d3f0c3c487bc41a75eba2e6097cb0b9c71491b15 + sha256: f98972704692ba679db144261172a8e20feb145636c617af0eb4022132a6797f url: "https://pub.dev" source: hosted - version: "3.2.3" + version: "3.3.0" cached_network_image_platform_interface: dependency: transitive description: name: cached_network_image_platform_interface - sha256: bb2b8403b4ccdc60ef5f25c70dead1f3d32d24b9d6117cfc087f496b178594a7 + sha256: "56aa42a7a01e3c9db8456d9f3f999931f1e05535b5a424271e9a38cabf066613" url: "https://pub.dev" source: hosted - version: "2.0.0" + version: "3.0.0" cached_network_image_web: dependency: transitive description: name: cached_network_image_web - sha256: b8eb814ebfcb4dea049680f8c1ffb2df399e4d03bf7a352c775e26fa06e02fa0 + sha256: "759b9a9f8f6ccbb66c185df805fac107f05730b1dab9c64626d1008cca532257" url: "https://pub.dev" source: hosted - version: "1.0.2" + version: "1.1.0" carousel_slider: dependency: transitive description: @@ -161,14 +169,6 @@ packages: url: "https://pub.dev" source: hosted version: "1.3.0" - charcode: - dependency: transitive - description: - name: charcode - sha256: fb98c0f6d12c920a02ee2d998da788bca066ca5f148492b7085ee23372b12306 - url: "https://pub.dev" - source: hosted - version: "1.3.1" checked_yaml: dependency: transitive description: @@ -330,7 +330,7 @@ packages: source: hosted version: "2.0.5" extended_image: - dependency: transitive + dependency: "direct main" description: name: extended_image sha256: b4d72a27851751cfadaf048936d42939db7cd66c08fdcfe651eeaa1179714ee6 @@ -389,10 +389,10 @@ packages: dependency: "direct main" description: name: file_picker - sha256: b85eb92b175767fdaa0c543bf3b0d1f610fe966412ea72845fe5ba7801e763ff + sha256: "9d6e95ec73abbd31ec54d0e0df8a961017e165aba1395e462e5b31ea0c165daf" url: "https://pub.dev" source: hosted - version: "5.2.10" + version: "5.3.1" file_selector_linux: dependency: transitive description: @@ -481,14 +481,6 @@ packages: url: "https://pub.dev" source: hosted version: "1.1.0" - flick_video_player: - dependency: transitive - description: - name: flick_video_player - sha256: edd39b56b74a11a627fa560507797896af951d4b1439f4c403edbcfe10af2047 - url: "https://pub.dev" - source: hosted - version: "0.5.0" flutter: dependency: "direct main" description: flutter @@ -502,14 +494,6 @@ packages: url: "https://pub.dev" source: hosted version: "8.1.3" - flutter_blurhash: - dependency: transitive - description: - name: flutter_blurhash - sha256: "05001537bd3fac7644fa6558b09ec8c0a3f2eba78c0765f88912882b1331a5c6" - url: "https://pub.dev" - source: hosted - version: "0.7.0" flutter_cache_manager: dependency: transitive description: @@ -664,7 +648,7 @@ packages: source: hosted version: "0.15.4" http: - dependency: transitive + dependency: "direct main" description: name: http sha256: "759d1a329847dd0f39226c688d3e06a6b8679668e350e2891a6474f8b4bb8525" @@ -695,6 +679,14 @@ packages: url: "https://pub.dev" source: hosted version: "4.0.2" + image: + dependency: transitive + description: + name: image + sha256: "028f61960d56f26414eb616b48b04eb37d700cbe477b7fb09bf1d7ce57fd9271" + url: "https://pub.dev" + source: hosted + version: "4.1.3" image_picker: dependency: "direct main" description: @@ -818,17 +810,18 @@ packages: likeminds_feed: dependency: "direct main" description: - path: "../LikeMinds-Flutter-Feed-SDK" - relative: true - source: path - version: "1.4.0" + name: likeminds_feed + sha256: e47b77e3eadfc475cd62e9bc1ea9c76fb64b5a3dc9cdb548782b06423f7c8e28 + url: "https://pub.dev" + source: hosted + version: "1.6.3" likeminds_feed_ui_fl: dependency: "direct main" description: path: "../LikeMinds-Flutter-Feed-UI" relative: true source: path - version: "1.1.0" + version: "1.3.5" lints: dependency: transitive description: @@ -861,6 +854,78 @@ packages: url: "https://pub.dev" source: hosted version: "0.5.0" + media_kit: + dependency: transitive + description: + name: media_kit + sha256: "3289062540e3b8b9746e5c50d95bd78a9289826b7227e253dff806d002b9e67a" + url: "https://pub.dev" + source: hosted + version: "1.1.10+1" + media_kit_libs_android_video: + dependency: transitive + description: + name: media_kit_libs_android_video + sha256: "9dd8012572e4aff47516e55f2597998f0a378e3d588d0fad0ca1f11a53ae090c" + url: "https://pub.dev" + source: hosted + version: "1.3.6" + media_kit_libs_ios_video: + dependency: transitive + description: + name: media_kit_libs_ios_video + sha256: b5382994eb37a4564c368386c154ad70ba0cc78dacdd3fb0cd9f30db6d837991 + url: "https://pub.dev" + source: hosted + version: "1.1.4" + media_kit_libs_linux: + dependency: transitive + description: + name: media_kit_libs_linux + sha256: e186891c31daa6bedab4d74dcdb4e8adfccc7d786bfed6ad81fe24a3b3010310 + url: "https://pub.dev" + source: hosted + version: "1.1.3" + media_kit_libs_macos_video: + dependency: transitive + description: + name: media_kit_libs_macos_video + sha256: f26aa1452b665df288e360393758f84b911f70ffb3878032e1aabba23aa1032d + url: "https://pub.dev" + source: hosted + version: "1.1.4" + media_kit_libs_video: + dependency: transitive + description: + name: media_kit_libs_video + sha256: "3688e0c31482074578652bf038ce6301a5d21e1eda6b54fc3117ffeb4bdba067" + url: "https://pub.dev" + source: hosted + version: "1.0.4" + media_kit_libs_windows_video: + dependency: transitive + description: + name: media_kit_libs_windows_video + sha256: "7bace5f35d9afcc7f9b5cdadb7541d2191a66bb3fc71bfa11c1395b3360f6122" + url: "https://pub.dev" + source: hosted + version: "1.0.9" + media_kit_native_event_loop: + dependency: transitive + description: + name: media_kit_native_event_loop + sha256: a605cf185499d14d58935b8784955a92a4bf0ff4e19a23de3d17a9106303930e + url: "https://pub.dev" + source: hosted + version: "1.0.8" + media_kit_video: + dependency: transitive + description: + name: media_kit_video + sha256: c048d11a19e379aebbe810647636e3fc6d18374637e2ae12def4ff8a4b99a882 + url: "https://pub.dev" + source: hosted + version: "1.2.4" meta: dependency: transitive description: @@ -921,10 +986,10 @@ packages: dependency: transitive description: name: octo_image - sha256: "107f3ed1330006a3bea63615e81cf637433f5135a52466c7caa0e7152bca9143" + sha256: "45b40f99622f11901238e18d48f5f12ea36426d8eced9f4cbf58479c7aa2430d" url: "https://pub.dev" source: hosted - version: "1.0.2" + version: "2.0.0" open_filex: dependency: "direct main" description: @@ -949,6 +1014,22 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.0" + package_info_plus: + dependency: transitive + description: + name: package_info_plus + sha256: "7e76fad405b3e4016cd39d08f455a4eb5199723cf594cd1b8916d47140d93017" + url: "https://pub.dev" + source: hosted + version: "4.2.0" + package_info_plus_platform_interface: + dependency: transitive + description: + name: package_info_plus_platform_interface + sha256: "9bc8ba46813a4cc42c66ab781470711781940780fd8beddd0c3da62506d3a6c6" + url: "https://pub.dev" + source: hosted + version: "2.0.1" path: dependency: transitive description: @@ -1077,6 +1158,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.4" + pointycastle: + dependency: transitive + description: + name: pointycastle + sha256: "7c1e5f0d23c9016c5bbd8b1473d0d3fb3fc851b876046039509e18e0c7485f2c" + url: "https://pub.dev" + source: hosted + version: "3.7.3" pool: dependency: transitive description: @@ -1141,22 +1230,78 @@ packages: url: "https://pub.dev" source: hosted version: "0.27.7" + safe_local_storage: + dependency: transitive + description: + name: safe_local_storage + sha256: ede4eb6cb7d88a116b3d3bf1df70790b9e2038bc37cb19112e381217c74d9440 + url: "https://pub.dev" + source: hosted + version: "1.0.2" + screen_brightness: + dependency: transitive + description: + name: screen_brightness + sha256: ed8da4a4511e79422fc1aa88138e920e4008cd312b72cdaa15ccb426c0faaedd + url: "https://pub.dev" + source: hosted + version: "0.2.2+1" + screen_brightness_android: + dependency: transitive + description: + name: screen_brightness_android + sha256: "3df10961e3a9e968a5e076fe27e7f4741fa8a1d3950bdeb48cf121ed529d0caf" + url: "https://pub.dev" + source: hosted + version: "0.1.0+2" + screen_brightness_ios: + dependency: transitive + description: + name: screen_brightness_ios + sha256: "99adc3ca5490b8294284aad5fcc87f061ad685050e03cf45d3d018fe398fd9a2" + url: "https://pub.dev" + source: hosted + version: "0.1.0" + screen_brightness_macos: + dependency: transitive + description: + name: screen_brightness_macos + sha256: "64b34e7e3f4900d7687c8e8fb514246845a73ecec05ab53483ed025bd4a899fd" + url: "https://pub.dev" + source: hosted + version: "0.1.0+1" + screen_brightness_platform_interface: + dependency: transitive + description: + name: screen_brightness_platform_interface + sha256: b211d07f0c96637a15fb06f6168617e18030d5d74ad03795dd8547a52717c171 + url: "https://pub.dev" + source: hosted + version: "0.1.0" + screen_brightness_windows: + dependency: transitive + description: + name: screen_brightness_windows + sha256: "9261bf33d0fc2707d8cf16339ce25768100a65e70af0fcabaf032fc12408ba86" + url: "https://pub.dev" + source: hosted + version: "0.1.3" share_plus: dependency: "direct main" description: name: share_plus - sha256: b1f15232d41e9701ab2f04181f21610c36c83a12ae426b79b4bd011c567934b1 + sha256: f74fc3f1cbd99f39760182e176802f693fa0ec9625c045561cfad54681ea93dd url: "https://pub.dev" source: hosted - version: "6.3.4" + version: "7.2.1" share_plus_platform_interface: dependency: transitive description: name: share_plus_platform_interface - sha256: "0c6e61471bd71b04a138b8b588fa388e66d8b005e6f2deda63371c5c505a0981" + sha256: df08bc3a07d01f5ea47b45d03ffcba1fa9cd5370fb44b3f38c70e42cced0f956 url: "https://pub.dev" source: hosted - version: "3.2.1" + version: "3.3.1" shared_preferences: dependency: "direct main" description: @@ -1426,22 +1571,22 @@ packages: url: "https://pub.dev" source: hosted version: "1.3.2" - universal_html: + universal_platform: dependency: transitive description: - name: universal_html - sha256: a5cc5a84188e5d3e58f3ed77fe3dd4575dc1f68aa7c89e51b5b4105b9aab3b9d + name: universal_platform + sha256: d315be0f6641898b280ffa34e2ddb14f3d12b1a37882557869646e0cc363d0cc url: "https://pub.dev" source: hosted - version: "2.2.3" - universal_io: + version: "1.0.0+1" + uri_parser: dependency: transitive description: - name: universal_io - sha256: "1722b2dcc462b4b2f3ee7d188dad008b6eb4c40bbd03a3de451d82c78bba9aad" + name: uri_parser + sha256: "6543c9fd86d2862fac55d800a43e67c0dcd1a41677cb69c2f8edfe73bbcf1835" url: "https://pub.dev" source: hosted - version: "2.2.2" + version: "2.0.2" url_launcher: dependency: "direct main" description: @@ -1602,46 +1747,30 @@ packages: url: "https://pub.dev" source: hosted version: "11.10.0" - wakelock: - dependency: transitive - description: - name: wakelock - sha256: "769ecf42eb2d07128407b50cb93d7c10bd2ee48f0276ef0119db1d25cc2f87db" - url: "https://pub.dev" - source: hosted - version: "0.6.2" - wakelock_macos: + volume_controller: dependency: transitive description: - name: wakelock_macos - sha256: "047c6be2f88cb6b76d02553bca5a3a3b95323b15d30867eca53a19a0a319d4cd" + name: volume_controller + sha256: "189bdc7a554f476b412e4c8b2f474562b09d74bc458c23667356bce3ca1d48c9" url: "https://pub.dev" source: hosted - version: "0.4.0" - wakelock_platform_interface: - dependency: transitive - description: - name: wakelock_platform_interface - sha256: "1f4aeb81fb592b863da83d2d0f7b8196067451e4df91046c26b54a403f9de621" - url: "https://pub.dev" - source: hosted - version: "0.3.0" - wakelock_web: + version: "2.0.7" + wakelock_plus: dependency: transitive description: - name: wakelock_web - sha256: "1b256b811ee3f0834888efddfe03da8d18d0819317f20f6193e2922b41a501b5" + name: wakelock_plus + sha256: f45a6c03aa3f8322e0a9d7f4a0482721c8789cb41d555407367650b8f9c26018 url: "https://pub.dev" source: hosted - version: "0.4.0" - wakelock_windows: + version: "1.1.3" + wakelock_plus_platform_interface: dependency: transitive description: - name: wakelock_windows - sha256: "857f77b3fe6ae82dd045455baa626bc4b93cb9bb6c86bf3f27c182167c3a5567" + name: wakelock_plus_platform_interface + sha256: "40fabed5da06caff0796dc638e1f07ee395fb18801fbff3255a2372db2d80385" url: "https://pub.dev" source: hosted - version: "0.2.1" + version: "1.1.0" watcher: dependency: transitive description: @@ -1678,10 +1807,10 @@ packages: dependency: transitive description: name: win32 - sha256: a6f0236dbda0f63aa9a25ad1ff9a9d8a4eaaa5012da0dc59d21afdb1dc361ca4 + sha256: "5a751eddf9db89b3e5f9d50c20ab8612296e4e8db69009788d6c8b060a84191c" url: "https://pub.dev" source: hosted - version: "3.1.4" + version: "4.1.4" xdg_directories: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 7005168..49b5a46 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: likeminds_feed_ss_fl description: A new Flutter package project. -version: 1.2.1 +version: 1.2.2 publish_to: none homepage: "https://likeminds.community/"