diff --git a/packages/stream_chat_v1/android/app/build.gradle b/packages/stream_chat_v1/android/app/build.gradle index fb84de7..f82941f 100644 --- a/packages/stream_chat_v1/android/app/build.gradle +++ b/packages/stream_chat_v1/android/app/build.gradle @@ -1,3 +1,9 @@ +plugins { + id "com.android.application" + id "kotlin-android" + id "dev.flutter.flutter-gradle-plugin" +} + def localProperties = new Properties() def localPropertiesFile = rootProject.file('local.properties') if (localPropertiesFile.exists()) { @@ -6,10 +12,6 @@ if (localPropertiesFile.exists()) { } } -def flutterRoot = localProperties.getProperty('flutter.sdk') -if (flutterRoot == null) { - throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") -} def flutterVersionCode = localProperties.getProperty('flutter.versionCode') if (flutterVersionCode == null) { @@ -21,17 +23,15 @@ if (flutterVersionName == null) { flutterVersionName = '1.0' } -apply plugin: 'com.android.application' -apply plugin: 'kotlin-android' -apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" - android { + namespace "com.example.example" + compileSdkVersion 34 - ndkVersion '21.4.7075529' sourceSets { main.java.srcDirs += 'src/main/kotlin' } + lintOptions { disable 'InvalidPackage' checkReleaseBuilds false @@ -44,7 +44,23 @@ android { targetSdkVersion 34 versionCode flutterVersionCode.toInteger() versionName flutterVersionName - testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + multiDexEnabled true + } + + compileOptions { + // Flag to enable support for the new language APIs + coreLibraryDesugaringEnabled true + } + + // Added this block: + afterEvaluate { project -> + if (project.hasProperty("kotlin")) { + project.tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).all { + kotlinOptions { + jvmTarget = "1.8" + } + } + } } signingConfigs { @@ -70,11 +86,5 @@ flutter { } dependencies { - implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" - testImplementation 'junit:junit:4.12' - androidTestImplementation 'androidx.test:runner:1.1.1' - androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1' - implementation 'com.google.firebase:firebase-messaging:20.1.2' + coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.2.2' } - -apply plugin: 'com.google.gms.google-services' diff --git a/packages/stream_chat_v1/android/build.gradle b/packages/stream_chat_v1/android/build.gradle index 35057b0..0ef75c8 100644 --- a/packages/stream_chat_v1/android/build.gradle +++ b/packages/stream_chat_v1/android/build.gradle @@ -1,27 +1,23 @@ -buildscript { - ext.kotlin_version = '1.9.22' - repositories { - google() - jcenter() - } - - dependencies { - classpath 'com.android.tools.build:gradle:7.2.1' - classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" - classpath 'com.google.gms:google-services:4.3.2' - } -} - allprojects { repositories { google() - jcenter() + mavenCentral() } } rootProject.buildDir = '../build' subprojects { project.buildDir = "${rootProject.buildDir}/${project.name}" + + afterEvaluate { + // check if `android` block is available and namespace isn't set + if(it.hasProperty('android') && it.android.namespace == null){ + def manifest = new XmlSlurper().parse(file(it.android.sourceSets.main.manifest.srcFile)) + def packageName = manifest.@package.text() + android.namespace= packageName + } + } + } subprojects { project.evaluationDependsOn(':app') diff --git a/packages/stream_chat_v1/android/gradle/wrapper/gradle-wrapper.properties b/packages/stream_chat_v1/android/gradle/wrapper/gradle-wrapper.properties index 75b9065..ed0d5cd 100644 --- a/packages/stream_chat_v1/android/gradle/wrapper/gradle-wrapper.properties +++ b/packages/stream_chat_v1/android/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-all.zip diff --git a/packages/stream_chat_v1/android/settings.gradle b/packages/stream_chat_v1/android/settings.gradle index 5a2f14f..bcc097f 100644 --- a/packages/stream_chat_v1/android/settings.gradle +++ b/packages/stream_chat_v1/android/settings.gradle @@ -1,15 +1,25 @@ -include ':app' +pluginManagement { + def flutterSdkPath = { + def properties = new Properties() + file("local.properties").withInputStream { properties.load(it) } + def flutterSdkPath = properties.getProperty("flutter.sdk") + assert flutterSdkPath != null, "flutter.sdk not set in local.properties" + return flutterSdkPath + }() -def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() + includeBuild("$flutterSdkPath/packages/flutter_tools/gradle") -def plugins = new Properties() -def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') -if (pluginsFile.exists()) { - pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } + repositories { + google() + mavenCentral() + gradlePluginPortal() + } } -plugins.each { name, path -> - def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() - include ":$name" - project(":$name").projectDir = pluginDirectory +plugins { + id "dev.flutter.flutter-plugin-loader" version "1.0.0" + id "com.android.application" version '8.3.2' apply false + id "org.jetbrains.kotlin.android" version "1.9.24" apply false } + +include ":app" \ No newline at end of file diff --git a/packages/stream_chat_v1/ios/Runner.xcodeproj/project.pbxproj b/packages/stream_chat_v1/ios/Runner.xcodeproj/project.pbxproj index 74b7202..2ec0f4e 100644 --- a/packages/stream_chat_v1/ios/Runner.xcodeproj/project.pbxproj +++ b/packages/stream_chat_v1/ios/Runner.xcodeproj/project.pbxproj @@ -163,7 +163,7 @@ 3B06AD1E1E4923F5004D2608 /* Thin Binary */, 0BC14C55242B5A7A0028DE94 /* Embed App Extensions */, 5468FC796DAC9C565B3989B4 /* [CP] Embed Pods Frameworks */, - 98FF9499337F40CD1C913E4B /* [CP] Copy Pods Resources */, + 8519A78E4BDC9820D507B557 /* [CP] Copy Pods Resources */, ); buildRules = ( ); @@ -266,7 +266,8 @@ "${BUILT_PRODUCTS_DIR}/flutter_app_badger/flutter_app_badger.framework", "${BUILT_PRODUCTS_DIR}/flutter_local_notifications/flutter_local_notifications.framework", "${BUILT_PRODUCTS_DIR}/flutter_secure_storage/flutter_secure_storage.framework", - "${BUILT_PRODUCTS_DIR}/image_gallery_saver/image_gallery_saver.framework", + "${BUILT_PRODUCTS_DIR}/get_thumbnail_video/get_thumbnail_video.framework", + "${BUILT_PRODUCTS_DIR}/image_gallery_saver_plus/image_gallery_saver_plus.framework", "${BUILT_PRODUCTS_DIR}/image_picker_ios/image_picker_ios.framework", "${BUILT_PRODUCTS_DIR}/just_audio/just_audio.framework", "${BUILT_PRODUCTS_DIR}/libwebp/libwebp.framework", @@ -279,12 +280,11 @@ "${BUILT_PRODUCTS_DIR}/sentry_flutter/sentry_flutter.framework", "${BUILT_PRODUCTS_DIR}/share_plus/share_plus.framework", "${BUILT_PRODUCTS_DIR}/shared_preferences_foundation/shared_preferences_foundation.framework", - "${BUILT_PRODUCTS_DIR}/sqflite/sqflite.framework", + "${BUILT_PRODUCTS_DIR}/sqflite_darwin/sqflite_darwin.framework", "${BUILT_PRODUCTS_DIR}/sqlite3/sqlite3.framework", "${BUILT_PRODUCTS_DIR}/sqlite3_flutter_libs/sqlite3_flutter_libs.framework", "${BUILT_PRODUCTS_DIR}/url_launcher_ios/url_launcher_ios.framework", "${BUILT_PRODUCTS_DIR}/video_player_avfoundation/video_player_avfoundation.framework", - "${BUILT_PRODUCTS_DIR}/video_thumbnail/video_thumbnail.framework", "${BUILT_PRODUCTS_DIR}/volume_controller/volume_controller.framework", "${BUILT_PRODUCTS_DIR}/wakelock_plus/wakelock_plus.framework", ); @@ -309,7 +309,8 @@ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/flutter_app_badger.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/flutter_local_notifications.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/flutter_secure_storage.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/image_gallery_saver.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/get_thumbnail_video.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/image_gallery_saver_plus.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/image_picker_ios.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/just_audio.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/libwebp.framework", @@ -322,12 +323,11 @@ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/sentry_flutter.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/share_plus.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/shared_preferences_foundation.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/sqflite.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/sqflite_darwin.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/sqlite3.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/sqlite3_flutter_libs.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/url_launcher_ios.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/video_player_avfoundation.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/video_thumbnail.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/volume_controller.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/wakelock_plus.framework", ); @@ -336,38 +336,38 @@ shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; showEnvVarsInLog = 0; }; - 9740EEB61CF901F6004384FC /* Run Script */ = { + 8519A78E4BDC9820D507B557 /* [CP] Copy Pods Resources */ = { isa = PBXShellScriptBuildPhase; - alwaysOutOfDate = 1; buildActionMask = 2147483647; files = ( ); inputPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh", + "${PODS_CONFIGURATION_BUILD_DIR}/firebase_messaging/firebase_messaging_Privacy.bundle", ); - name = "Run Script"; + name = "[CP] Copy Pods Resources"; outputPaths = ( + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/firebase_messaging_Privacy.bundle", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n"; + showEnvVarsInLog = 0; }; - 98FF9499337F40CD1C913E4B /* [CP] Copy Pods Resources */ = { + 9740EEB61CF901F6004384FC /* Run Script */ = { isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; buildActionMask = 2147483647; files = ( ); inputPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh", - "${PODS_CONFIGURATION_BUILD_DIR}/firebase_messaging/firebase_messaging_Privacy.bundle", ); - name = "[CP] Copy Pods Resources"; + name = "Run Script"; outputPaths = ( - "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/firebase_messaging_Privacy.bundle", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n"; - showEnvVarsInLog = 0; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; }; A83A30E8FF0298FDB3189FB1 /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; diff --git a/packages/stream_chat_v1/ios/Runner/AppDelegate.swift b/packages/stream_chat_v1/ios/Runner/AppDelegate.swift index e024c1e..0f470ec 100644 --- a/packages/stream_chat_v1/ios/Runner/AppDelegate.swift +++ b/packages/stream_chat_v1/ios/Runner/AppDelegate.swift @@ -1,7 +1,7 @@ import UIKit import Flutter -@UIApplicationMain +@main @objc class AppDelegate: FlutterAppDelegate { let sharedDefaults = UserDefaults(suiteName: "group.io.getstream.flutter") diff --git a/packages/stream_chat_v1/lib/pages/channel_list_page.dart b/packages/stream_chat_v1/lib/pages/channel_list_page.dart index d6aea78..c4384ec 100644 --- a/packages/stream_chat_v1/lib/pages/channel_list_page.dart +++ b/packages/stream_chat_v1/lib/pages/channel_list_page.dart @@ -1,6 +1,7 @@ import 'dart:async'; import 'package:example/app.dart'; +import 'package:example/pages/thread_list_page.dart'; import 'package:example/pages/user_mentions_page.dart'; import 'package:example/routes/routes.dart'; import 'package:example/state/init_data.dart'; @@ -41,27 +42,40 @@ class _ChannelListPageState extends State { ? StreamChatTheme.of(context).colorTheme.textHighEmphasis : Colors.grey, ), - const Positioned( - top: -3, - right: -16, + PositionedDirectional( + top: -4, + start: 12, child: StreamUnreadIndicator(), ), ], ), label: AppLocalizations.of(context).chats, ), + BottomNavigationBarItem( + icon: StreamSvgIcon.mentions( + color: _isSelected(1) + ? StreamChatTheme.of(context).colorTheme.textHighEmphasis + : Colors.grey, + ), + label: AppLocalizations.of(context).mentions, + ), BottomNavigationBarItem( icon: Stack( clipBehavior: Clip.none, children: [ - StreamSvgIcon.mentions( - color: _isSelected(1) + Icon(Icons.message_outlined, + color: _isSelected(2) ? StreamChatTheme.of(context).colorTheme.textHighEmphasis : Colors.grey, ), + PositionedDirectional( + top: -4, + start: 12, + child: StreamUnreadIndicator.threads(), + ), ], ), - label: AppLocalizations.of(context).mentions, + label: 'Threads', ), ]; } @@ -105,6 +119,7 @@ class _ChannelListPageState extends State { children: const [ ChannelList(), UserMentionsPage(), + ThreadListPage(), ], ), ); diff --git a/packages/stream_chat_v1/lib/pages/thread_list_page.dart b/packages/stream_chat_v1/lib/pages/thread_list_page.dart new file mode 100644 index 0000000..7c88f95 --- /dev/null +++ b/packages/stream_chat_v1/lib/pages/thread_list_page.dart @@ -0,0 +1,63 @@ +import 'package:example/pages/thread_page.dart'; +import 'package:flutter/material.dart'; +import 'package:stream_chat_flutter/stream_chat_flutter.dart'; + +class ThreadListPage extends StatefulWidget { + const ThreadListPage({super.key}); + + @override + State createState() => _ThreadListPageState(); +} + +class _ThreadListPageState extends State { + late final controller = StreamThreadListController( + client: StreamChat.of(context).client, + ); + + @override + void dispose() { + controller.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Column( + children: [ + ValueListenableBuilder( + valueListenable: controller.unseenThreadIds, + builder: (_, unreadThreads, __) => StreamUnreadThreadsBanner( + unreadThreads: unreadThreads, + onTap: () => controller + .refresh(resetValue: false) + .then((_) => controller.clearUnseenThreadIds()), + ), + ), + Expanded( + child: StreamThreadListView( + controller: controller, + onThreadTap: (thread) async { + final channelCid = thread.channelCid; + + final channel = StreamChat.of(context).client.channel( + channelCid.split(':')[0], + id: channelCid.split(':')[1], + ); + + Navigator.of(context).push( + MaterialPageRoute( + builder: (context) { + return StreamChannel( + channel: channel, + child: ThreadPage(parent: thread.parentMessage!), + ); + }, + ), + ); + }, + ), + ), + ], + ); + } +} diff --git a/packages/stream_chat_v1/lib/pages/thread_page.dart b/packages/stream_chat_v1/lib/pages/thread_page.dart index 5c47730..da536bb 100644 --- a/packages/stream_chat_v1/lib/pages/thread_page.dart +++ b/packages/stream_chat_v1/lib/pages/thread_page.dart @@ -56,6 +56,7 @@ class _ThreadPageState extends State { parentMessage: widget.parent, initialScrollIndex: widget.initialScrollIndex, initialAlignment: widget.initialAlignment, + markReadWhenAtTheBottom: true, //onMessageSwiped: _reply, messageFilter: defaultFilter, showScrollToBottom: false, diff --git a/packages/stream_chat_v1/pubspec.yaml b/packages/stream_chat_v1/pubspec.yaml index c02887c..cf3d450 100644 --- a/packages/stream_chat_v1/pubspec.yaml +++ b/packages/stream_chat_v1/pubspec.yaml @@ -11,28 +11,28 @@ dependencies: flutter_app_badger: ^1.5.0 flutter: sdk: flutter - stream_chat_flutter: ^8.0.0 - stream_chat_persistence: ^8.0.0 - stream_chat_localizations: ^8.0.0 - flutter_local_notifications: ^15.1.0+1 + stream_chat_flutter: ^9.1.0 + stream_chat_persistence: ^9.1.0 + stream_chat_localizations: ^9.1.0 + flutter_local_notifications: ^18.0.1 flutter_svg: ^2.0.7 - flutter_secure_storage: ^8.0.0 + flutter_secure_storage: ^9.2.2 yaml: ^3.1.2 uuid: ^4.4.2 streaming_shared_preferences: ^2.0.0 lottie: ^3.1.2 collection: ^1.17.1 - sentry_flutter: ^7.9.0 + sentry_flutter: ^8.3.0 flutter_slidable: ^3.1.1 - go_router: ^10.1.0 + go_router: ^14.6.2 provider: ^6.0.5 video_player: ^2.7.0 - firebase_core: ^2.15.1 - firebase_messaging: ^14.6.6 + firebase_core: ^3.0.0 + firebase_messaging: ^15.0.0 dev_dependencies: - flutter_launcher_icons: ^0.13.1 - flutter_lints: ^2.0.2 + flutter_launcher_icons: ^0.14.2 + flutter_lints: ^5.0.0 flutter: uses-material-design: true