Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#
# Generated file, do not edit.
#

import lldb

def handle_new_rx_page(frame: lldb.SBFrame, bp_loc, extra_args, intern_dict):
"""Intercept NOTIFY_DEBUGGER_ABOUT_RX_PAGES and touch the pages."""
base = frame.register["x0"].GetValueAsAddress()
page_len = frame.register["x1"].GetValueAsUnsigned()

# Note: NOTIFY_DEBUGGER_ABOUT_RX_PAGES will check contents of the
# first page to see if handled it correctly. This makes diagnosing
# misconfiguration (e.g. missing breakpoint) easier.
data = bytearray(page_len)
data[0:8] = b'IHELPED!'

error = lldb.SBError()
frame.GetThread().GetProcess().WriteMemory(base, data, error)
if not error.Success():
print(f'Failed to write into {base}[+{page_len}]', error)
return

def __lldb_init_module(debugger: lldb.SBDebugger, _):
target = debugger.GetDummyTarget()
# Caveat: must use BreakpointCreateByRegEx here and not
# BreakpointCreateByName. For some reasons callback function does not
# get carried over from dummy target for the later.
bp = target.BreakpointCreateByRegex("^NOTIFY_DEBUGGER_ABOUT_RX_PAGES$")
bp.SetScriptCallbackFunction('{}.handle_new_rx_page'.format(__name__))
bp.SetAutoContinue(True)
print("-- LLDB integration loaded --")
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#
# Generated file, do not edit.
#

command script import --relative-to-command-file flutter_lldb_helper.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#
# Generated file, do not edit.
#

import lldb

def handle_new_rx_page(frame: lldb.SBFrame, bp_loc, extra_args, intern_dict):
"""Intercept NOTIFY_DEBUGGER_ABOUT_RX_PAGES and touch the pages."""
base = frame.register["x0"].GetValueAsAddress()
page_len = frame.register["x1"].GetValueAsUnsigned()

# Note: NOTIFY_DEBUGGER_ABOUT_RX_PAGES will check contents of the
# first page to see if handled it correctly. This makes diagnosing
# misconfiguration (e.g. missing breakpoint) easier.
data = bytearray(page_len)
data[0:8] = b'IHELPED!'

error = lldb.SBError()
frame.GetThread().GetProcess().WriteMemory(base, data, error)
if not error.Success():
print(f'Failed to write into {base}[+{page_len}]', error)
return

def __lldb_init_module(debugger: lldb.SBDebugger, _):
target = debugger.GetDummyTarget()
# Caveat: must use BreakpointCreateByRegEx here and not
# BreakpointCreateByName. For some reasons callback function does not
# get carried over from dummy target for the later.
bp = target.BreakpointCreateByRegex("^NOTIFY_DEBUGGER_ABOUT_RX_PAGES$")
bp.SetScriptCallbackFunction('{}.handle_new_rx_page'.format(__name__))
bp.SetAutoContinue(True)
print("-- LLDB integration loaded --")
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#
# Generated file, do not edit.
#

command script import --relative-to-command-file flutter_lldb_helper.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// ignore_for_file: lines_longer_than_80_chars
// ignore_for_file: lines_longer_than_80_chars
import 'dart:async';
import 'dart:math';

Expand Down Expand Up @@ -538,7 +538,11 @@ class _StreamMessageListViewState extends State<StreamMessageListView> {
final newMessagesListLength = messages.length;

if (_messageListLength != null) {
if (_bottomPaginationActive || (_inBetweenList && _upToDate)) {
// MODIFICATION: Channel status stability check added.
// The scrolling is adjusted if the SDK confirms that the data is synchronized. (isUpToDate).
final isChannelStable = streamChannel?.channel.state?.isUpToDate ?? false;

if (isChannelStable && (_bottomPaginationActive || (_inBetweenList && _upToDate))) {
if (_itemPositionListener.itemPositions.value.isNotEmpty) {
final first = _itemPositionListener.itemPositions.value.first;
final diff = newMessagesListLength - _messageListLength!;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import 'package:stream_chat_flutter/src/theme/stream_chat_theme.dart';
import 'package:stream_chat_flutter/src/utils/extensions.dart';
import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart';
import 'package:svg_icon_widget/svg_icon_widget.dart';

/// Function signature for handling the dismiss action on the unread indicator.
typedef OnUnreadIndicatorDismissTap = Future<void> Function();

Expand Down Expand Up @@ -60,10 +60,16 @@ class UnreadIndicatorButton extends StatelessWidget {
final channel = StreamChannel.of(context).channel;
if (channel.state == null) return const Empty();

return BetterStreamBuilder(
return BetterStreamBuilder<Read>(
initialData: channel.state!.currentUserRead,
stream: channel.state!.currentUserReadStream,
builder: (context, currentUserRead) {
// CHANGE: Unnecessary comparison with null is removed.
// Only channel.state is checked for security purposes.
if (channel.state == null) {
return const Empty();
}

final unreadCount = currentUserRead.unreadMessages;
if (unreadCount <= 0) return const Empty();

Expand All @@ -87,6 +93,7 @@ class UnreadIndicatorButton extends StatelessWidget {
child: Padding(
padding: const EdgeInsets.fromLTRB(16, 2, 8, 2),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Text(
context.translations.unreadCountIndicatorLabel(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#
# Generated file, do not edit.
#

import lldb

def handle_new_rx_page(frame: lldb.SBFrame, bp_loc, extra_args, intern_dict):
"""Intercept NOTIFY_DEBUGGER_ABOUT_RX_PAGES and touch the pages."""
base = frame.register["x0"].GetValueAsAddress()
page_len = frame.register["x1"].GetValueAsUnsigned()

# Note: NOTIFY_DEBUGGER_ABOUT_RX_PAGES will check contents of the
# first page to see if handled it correctly. This makes diagnosing
# misconfiguration (e.g. missing breakpoint) easier.
data = bytearray(page_len)
data[0:8] = b'IHELPED!'

error = lldb.SBError()
frame.GetThread().GetProcess().WriteMemory(base, data, error)
if not error.Success():
print(f'Failed to write into {base}[+{page_len}]', error)
return

def __lldb_init_module(debugger: lldb.SBDebugger, _):
target = debugger.GetDummyTarget()
# Caveat: must use BreakpointCreateByRegEx here and not
# BreakpointCreateByName. For some reasons callback function does not
# get carried over from dummy target for the later.
bp = target.BreakpointCreateByRegex("^NOTIFY_DEBUGGER_ABOUT_RX_PAGES$")
bp.SetScriptCallbackFunction('{}.handle_new_rx_page'.format(__name__))
bp.SetAutoContinue(True)
print("-- LLDB integration loaded --")
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#
# Generated file, do not edit.
#

command script import --relative-to-command-file flutter_lldb_helper.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#
# Generated file, do not edit.
#

import lldb

def handle_new_rx_page(frame: lldb.SBFrame, bp_loc, extra_args, intern_dict):
"""Intercept NOTIFY_DEBUGGER_ABOUT_RX_PAGES and touch the pages."""
base = frame.register["x0"].GetValueAsAddress()
page_len = frame.register["x1"].GetValueAsUnsigned()

# Note: NOTIFY_DEBUGGER_ABOUT_RX_PAGES will check contents of the
# first page to see if handled it correctly. This makes diagnosing
# misconfiguration (e.g. missing breakpoint) easier.
data = bytearray(page_len)
data[0:8] = b'IHELPED!'

error = lldb.SBError()
frame.GetThread().GetProcess().WriteMemory(base, data, error)
if not error.Success():
print(f'Failed to write into {base}[+{page_len}]', error)
return
Comment on lines +7 to +22
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

# Find Ruff configuration files and examine their settings
fd -a -t f '(pyproject\.toml|ruff\.toml|setup\.cfg|tox\.ini)$' | head -20

Repository: GetStream/stream-chat-flutter

Length of output: 101


🏁 Script executed:

# Check if the file exists
find . -name "flutter_lldb_helper.py" -type f 2>/dev/null

Repository: GetStream/stream-chat-flutter

Length of output: 467


🏁 Script executed:

# Also search for any ruff or pyproject configuration
fd -a -t f 'pyproject\.toml' | xargs -I {} sh -c 'echo "=== {} ===" && head -100 {}'

Repository: GetStream/stream-chat-flutter

Length of output: 55


🏁 Script executed:

# Read the Ruff configuration
cat /home/jailuser/git/ruff.toml

Repository: GetStream/stream-chat-flutter

Length of output: 979


🏁 Script executed:

# Check if ephemeral is explicitly excluded or if ARG001 is configured anywhere
rg -n "ephemeral|exclude|extend-exclude|ARG001|per-file-ignores" /home/jailuser/git/ruff.toml

Repository: GetStream/stream-chat-flutter

Length of output: 99


🏁 Script executed:

# Read the actual file to verify unused arguments
cat -n ./packages/stream_chat_persistence/example/ios/Flutter/ephemeral/flutter_lldb_helper.py

Repository: GetStream/stream-chat-flutter

Length of output: 1572


🏁 Script executed:

# Check if there are other per-file patterns or excludes that might apply to example/ios directories
rg -A 10 "per-file-ignores" /home/jailuser/git/ruff.toml

Repository: GetStream/stream-chat-flutter

Length of output: 152


🏁 Script executed:

# Search for any generation scripts or workflows that might regenerate this file
find . -name "*.py" -o -name "*.sh" -o -name "*.dart" | xargs grep -l "flutter_lldb_helper\|ephemeral" 2>/dev/null | head -10

Repository: GetStream/stream-chat-flutter

Length of output: 672


🏁 Script executed:

# Check if ephemeral directory is mentioned in any iOS build files or Flutter config
find . -name "pubspec.yaml" -o -name "build.gradle" -o -name "Podfile" | xargs grep -l "ephemeral" 2>/dev/null

Repository: GetStream/stream-chat-flutter

Length of output: 209


🏁 Script executed:

# Check git status or .gitignore to see if ephemeral is typically ignored
git check-ignore packages/stream_chat_persistence/example/ios/Flutter/ephemeral/flutter_lldb_helper.py && echo "File is gitignored" || echo "File is tracked"

Repository: GetStream/stream-chat-flutter

Length of output: 88


🏁 Script executed:

# Check .gitignore patterns
cat .gitignore 2>/dev/null | grep -i ephemeral

Repository: GetStream/stream-chat-flutter

Length of output: 160


Add iOS ephemeral directory to .gitignore or configure Ruff per-file-ignore.

The file header states "Generated file, do not edit," so modifying it is not sustainable. Ruff will flag bp_loc, extra_args, and intern_dict as unused (ARG001), but these parameters are required by the LLDB callback protocol signature.

The proper fix is to either:

  1. Add **/ios/Flutter/ephemeral to .gitignore (consistent with how macos, windows, and linux ephemeral directories are already ignored), OR
  2. Add a per-file-ignore in ruff.toml:
"**/ephemeral/flutter_lldb_helper.py" = ["ARG001"]

Do not modify the generated file directly.

🧰 Tools
🪛 Ruff (0.14.14)

[warning] 7-7: Unused function argument: bp_loc

(ARG001)


[warning] 7-7: Unused function argument: extra_args

(ARG001)


[warning] 7-7: Unused function argument: intern_dict

(ARG001)

🤖 Prompt for AI Agents
In
`@packages/stream_chat_persistence/example/ios/Flutter/ephemeral/flutter_lldb_helper.py`
around lines 7 - 22, Generated file flutter_lldb_helper.py (function
handle_new_rx_page) is flagged by Ruff for unused parameters (bp_loc,
extra_args, intern_dict) even though they are required by the LLDB callback
signature; fix by either adding the directory pattern **/ios/Flutter/ephemeral
to .gitignore so the generated file is not linted, or add a per-file-ignore
entry in ruff.toml targeting **/ephemeral/flutter_lldb_helper.py to suppress
ARG001 for that file. Ensure you do not edit the generated file itself.


def __lldb_init_module(debugger: lldb.SBDebugger, _):
target = debugger.GetDummyTarget()
# Caveat: must use BreakpointCreateByRegEx here and not
# BreakpointCreateByName. For some reasons callback function does not
# get carried over from dummy target for the later.
bp = target.BreakpointCreateByRegex("^NOTIFY_DEBUGGER_ABOUT_RX_PAGES$")
bp.SetScriptCallbackFunction('{}.handle_new_rx_page'.format(__name__))
bp.SetAutoContinue(True)
print("-- LLDB integration loaded --")
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#
# Generated file, do not edit.
#

command script import --relative-to-command-file flutter_lldb_helper.py
32 changes: 32 additions & 0 deletions sample_app/ios/Flutter/ephemeral/flutter_lldb_helper.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#
# Generated file, do not edit.
#

import lldb

def handle_new_rx_page(frame: lldb.SBFrame, bp_loc, extra_args, intern_dict):
"""Intercept NOTIFY_DEBUGGER_ABOUT_RX_PAGES and touch the pages."""
base = frame.register["x0"].GetValueAsAddress()
page_len = frame.register["x1"].GetValueAsUnsigned()

# Note: NOTIFY_DEBUGGER_ABOUT_RX_PAGES will check contents of the
# first page to see if handled it correctly. This makes diagnosing
# misconfiguration (e.g. missing breakpoint) easier.
data = bytearray(page_len)
data[0:8] = b'IHELPED!'

error = lldb.SBError()
frame.GetThread().GetProcess().WriteMemory(base, data, error)
if not error.Success():
print(f'Failed to write into {base}[+{page_len}]', error)
return

def __lldb_init_module(debugger: lldb.SBDebugger, _):
target = debugger.GetDummyTarget()
# Caveat: must use BreakpointCreateByRegEx here and not
# BreakpointCreateByName. For some reasons callback function does not
# get carried over from dummy target for the later.
bp = target.BreakpointCreateByRegex("^NOTIFY_DEBUGGER_ABOUT_RX_PAGES$")
bp.SetScriptCallbackFunction('{}.handle_new_rx_page'.format(__name__))
bp.SetAutoContinue(True)
print("-- LLDB integration loaded --")
5 changes: 5 additions & 0 deletions sample_app/ios/Flutter/ephemeral/flutter_lldbinit
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#
# Generated file, do not edit.
#

command script import --relative-to-command-file flutter_lldb_helper.py
35 changes: 22 additions & 13 deletions sample_app/lib/app.dart
Original file line number Diff line number Diff line change
Expand Up @@ -358,28 +358,37 @@ class _StreamChatSampleAppState extends State<StreamChatSampleApp>
}

/// Constructs callback for notification click event.
OnRemoteMessage _onFirebaseMessageOpenedApp(StreamChatClient client) {
OnRemoteMessage _onFirebaseMessageOpenedApp(StreamChatClient client) {
return (message) async {
debugPrint('[onMessageOpenedApp] #firebase; message: ${message.toMap()}');
// This callback is getting invoked when the user clicks
// on the notification in case if notification was shown by OS.

final channelCid = (message.data['cid'] as String?) ?? '';
if (channelCid.isEmpty) return;

final parts = channelCid.split(':');
final channelType = parts[0];
final channelId = parts[1];

// Assigns the channel if it exists in the state,
// otherwise creates a new channel instance.
var channel = client.state.channels[channelCid];
if (channel == null) {
channel = client.channel(
channelType,
id: channelId,
);
channel ??= client.channel(channelType, id: channelId);

// Synchronizes the channel state before navigating to the UI.
// This ensures that unread counts and message lists are accurate
// upon the first frame of the ChannelPage.
try {
await channel.watch();
} catch (e) {
debugPrint('Error synchronizing channel: $e');
}

if (_navigatorKey.currentContext != null) {
GoRouter.of(_navigatorKey.currentContext!).pushNamed(
Routes.CHANNEL_PAGE.name,
pathParameters: Routes.CHANNEL_PAGE.params(channel),
);
}
// Navigates to Channel page, which is associated with the notification.
GoRouter.of(_navigatorKey.currentContext!).pushNamed(
Routes.CHANNEL_PAGE.name,
pathParameters: Routes.CHANNEL_PAGE.params(channel),
);
};
}

Expand Down
Loading