Skip to content
Open
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
43 changes: 23 additions & 20 deletions lib/views/screens/profile_screen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@ class ProfileScreen extends StatefulWidget {
}

class _ProfileScreenState extends State<ProfileScreen> {
/// Returns true if the current user is viewing their own profile (owner mode)
/// Returns false if viewing another user's profile (public view mode)
bool get isOwner => widget.isCreatorProfile == null;
Comment on lines +44 to +46

Copilot AI Mar 1, 2026

Copy link

Choose a reason for hiding this comment

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

isOwner is derived from widget.isCreatorProfile == null, but the widget API uses a nullable bool where only true is constrained by the constructor assert. If a caller ever passes isCreatorProfile: false (allowed by the assert), isOwner becomes false and the screen will dereference widget.creator! in multiple places and crash. Consider defining owner mode as widget.isCreatorProfile != true (or make the flag non-nullable with a default) and update the doc comment to match the actual semantics.

Suggested change
/// Returns true if the current user is viewing their own profile (owner mode)
/// Returns false if viewing another user's profile (public view mode)
bool get isOwner => widget.isCreatorProfile == null;
/// Returns true if the current user is viewing their own profile (owner mode).
/// Returns false only when explicitly in creator profile mode (`isCreatorProfile == true`).
bool get isOwner => widget.isCreatorProfile != true;

Copilot uses AI. Check for mistakes.

Comment on lines +44 to +47

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# Step 1: Examine the ProfileScreen constructor and isOwner getter
sed -n '30,50p' lib/views/screens/profile_screen.dart

Repository: AOSSIE-Org/Resonate

Length of output: 743


🏁 Script executed:

# Step 2: Find all ProfileScreen instantiations
rg -n 'ProfileScreen\s*\(' lib/ --type=dart -B2 -A4

Repository: AOSSIE-Org/Resonate

Length of output: 3572


🏁 Script executed:

# Step 3: Find specific patterns of isCreatorProfile usage
rg -n 'isCreatorProfile\s*:\s*(true|false|)' lib/ --type=dart -B2 -A2

Repository: AOSSIE-Org/Resonate

Length of output: 921


🏁 Script executed:

# Step 4: Check widget.creator! dereferences in the file
sed -n '140,220p' lib/views/screens/profile_screen.dart

Repository: AOSSIE-Org/Resonate

Length of output: 3386


Strengthen constructor assertion to prevent null-crash states in public mode.

The constructor allows isCreatorProfile: false without requiring creator, but the logic treats any non-null isCreatorProfile as public mode, which dereferences widget.creator! (lines 150, 183, 193, 214). While no current call sites exploit this, the assertion should enforce the invariant that creator is required whenever viewing another user's profile.

🔧 Proposed fix
-  ProfileScreen({super.key, this.creator, this.isCreatorProfile})
-    : assert(
-        isCreatorProfile != true || (creator != null && creator.uid != null),
-        'creator and creator.uid are required when isCreatorProfile is true',
-      );
+  ProfileScreen({super.key, this.creator, this.isCreatorProfile})
+    : assert(
+        isCreatorProfile == null || (creator != null && creator.uid != null),
+        'creator and creator.uid are required when viewing another user profile',
+      );
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@lib/views/screens/profile_screen.dart` around lines 44 - 47, Constructor
allows isCreatorProfile == false without creator, which later leads to
widget.creator! dereferences; update the ProfileScreen constructor to assert
that whenever isCreatorProfile is explicitly false (public view) then creator is
non-null (e.g. add assert(isCreatorProfile != false || creator != null, 'creator
must be provided when viewing another user\'s profile')), and keep the existing
isOwner getter logic unchanged or clarify it to match the invariant so all uses
of widget.creator! are safe.

@override
void initState() {
super.initState();
Expand Down Expand Up @@ -74,7 +78,7 @@ class _ProfileScreenState extends State<ProfileScreen> {
return Scaffold(
appBar: AppBar(
title: Text(AppLocalizations.of(context)!.profile),
actions: widget.isCreatorProfile == null
actions: isOwner
? [
IconButton(
onPressed: () {
Expand Down Expand Up @@ -143,7 +147,7 @@ class _ProfileScreenState extends State<ProfileScreen> {
SizedBox(width: UiSizes.width_20),
CircleAvatar(
backgroundColor: Theme.of(Get.context!).colorScheme.secondary,
backgroundImage: widget.isCreatorProfile != null
backgroundImage: !isOwner
? NetworkImage(widget.creator!.profileImageUrl ?? '')
: controller.profileImageUrl == null ||
controller.profileImageUrl!.isEmpty
Expand All @@ -157,8 +161,7 @@ class _ProfileScreenState extends State<ProfileScreen> {
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (widget.isCreatorProfile == null &&
controller.isEmailVerified!)
if (isOwner && controller.isEmailVerified!)
Padding(
padding: EdgeInsets.only(top: 10),
child: Row(
Expand All @@ -176,7 +179,7 @@ class _ProfileScreenState extends State<ProfileScreen> {
),
),
Text(
widget.isCreatorProfile != null
!isOwner
? widget.creator!.name ?? ''
: controller.displayName.toString(),
style: TextStyle(
Expand All @@ -187,7 +190,7 @@ class _ProfileScreenState extends State<ProfileScreen> {
),
Chip(
label: Text(
"@${widget.isCreatorProfile != null ? widget.creator!.userName : controller.userName}",
"@${!isOwner ? widget.creator!.userName : controller.userName}",
style: TextStyle(
fontSize: UiSizes.size_14,
overflow: TextOverflow.ellipsis,
Expand All @@ -204,7 +207,7 @@ class _ProfileScreenState extends State<ProfileScreen> {
Padding(
padding: const EdgeInsets.only(left: 5),
child: Text(
widget.isCreatorProfile == null
isOwner
? (authController.ratingTotal /
authController.ratingCount)
.toStringAsFixed(1)
Expand All @@ -221,7 +224,7 @@ class _ProfileScreenState extends State<ProfileScreen> {
.length ==
1 &&
userProfileController.isFollowingUser.value) &&
widget.isCreatorProfile != null) {
!isOwner) {
//Remove current user from followers list
final sanitizedFollowersList = userProfileController
.searchedUserFollowers
Expand All @@ -239,7 +242,7 @@ class _ProfileScreenState extends State<ProfileScreen> {
Icon(Icons.people),
Padding(
padding: const EdgeInsets.only(left: 5),
child: widget.isCreatorProfile == null
child: isOwner
? Text(
authController.followerDocuments.length
.toString(),
Expand Down Expand Up @@ -271,7 +274,7 @@ class _ProfileScreenState extends State<ProfileScreen> {
EmailVerifyController emailVerifyController,
AuthStateController controller,
) {
if (widget.isCreatorProfile != null || controller.isEmailVerified!) {
if (!isOwner || controller.isEmailVerified!) {
return const SizedBox.shrink();
}

Expand Down Expand Up @@ -305,7 +308,7 @@ class _ProfileScreenState extends State<ProfileScreen> {
child: Obx(() {
return ElevatedButton(
onPressed: () {
if (widget.isCreatorProfile != null) {
if (!isOwner) {
if (userProfileController.isFollowingUser.value) {
userProfileController.unfollowCreator();
} else {
Expand All @@ -331,7 +334,7 @@ class _ProfileScreenState extends State<ProfileScreen> {
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(
widget.isCreatorProfile != null
!isOwner
? userProfileController.isFollowingUser.value
? Icons.done
: Icons.add
Expand All @@ -340,7 +343,7 @@ class _ProfileScreenState extends State<ProfileScreen> {
),
const SizedBox(width: 8),
Text(
widget.isCreatorProfile != null
!isOwner
? userProfileController.isFollowingUser.value
? AppLocalizations.of(context)!.following
: AppLocalizations.of(context)!.follow
Expand All @@ -354,7 +357,7 @@ class _ProfileScreenState extends State<ProfileScreen> {
),
const SizedBox(width: 10),

widget.isCreatorProfile == null
isOwner
? SizedBox(
height: 50,
width: 50,
Expand Down Expand Up @@ -494,7 +497,7 @@ class _ProfileScreenState extends State<ProfileScreen> {
Align(
alignment: Alignment.centerLeft,
child: Text(
widget.isCreatorProfile != null
!isOwner
? AppLocalizations.of(context)!.userCreatedStories
: AppLocalizations.of(context)!.yourStories,
style: TextStyle(
Expand All @@ -508,10 +511,10 @@ class _ProfileScreenState extends State<ProfileScreen> {
Obx(
() => _buildStoriesList(
context,
widget.isCreatorProfile != null
!isOwner
? userProfileController.searchedUserStories
: exploreStoryController.userCreatedStories,
widget.isCreatorProfile != null
!isOwner
? AppLocalizations.of(context)!.userNoStories
: AppLocalizations.of(context)!.youNoStories,
),
Expand All @@ -520,7 +523,7 @@ class _ProfileScreenState extends State<ProfileScreen> {
Align(
alignment: Alignment.centerLeft,
child: Text(
widget.isCreatorProfile != null
!isOwner
? AppLocalizations.of(context)!.userLikedStories
: AppLocalizations.of(context)!.yourLikedStories,
style: TextStyle(
Expand All @@ -534,10 +537,10 @@ class _ProfileScreenState extends State<ProfileScreen> {
Obx(
() => _buildStoriesList(
context,
widget.isCreatorProfile != null
!isOwner
? userProfileController.searchedUserLikedStories
: exploreStoryController.userLikedStories,
widget.isCreatorProfile != null
!isOwner
? AppLocalizations.of(context)!.userNoLikedStories
: AppLocalizations.of(context)!.youNoLikedStories,
),
Expand Down
Loading