feat: refactor profile screen to support public view mode#777
feat: refactor profile screen to support public view mode#777Arunodoy18 wants to merge 1 commit intoAOSSIE-Org:masterfrom
Conversation
- Introduce isOwner boolean flag for clear semantic separation - Hide owner-only UI elements in public view: * Edit Profile button * Settings access button * Email verification prompts * AppBar notifications and friends icons * Email verification badge - Replace all widget.isCreatorProfile checks with isOwner flag - Maintain consistent UI structure without screen duplication - Preserve all navigation logic and business logic - Improve code readability with semantic naming Resolves AOSSIE-Org#749
|
🎉 Welcome @Arunodoy18!
We appreciate your contribution! 🚀 |
📝 WalkthroughWalkthroughThe profile screen is refactored to introduce an Changes
Estimated code review effort🎯 2 (Simple) | ⏱️ ~10 minutes Poem
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Pull request overview
Refactors ProfileScreen to support an “owner vs public view” mode so the same screen can be reused when viewing another user’s profile, hiding owner-only UI elements.
Changes:
- Introduced an
isOwnergetter to centralize owner/public mode detection. - Updated conditional UI rendering (app bar actions, header, buttons, stories labels/data sources) to use
isOwner. - Adjusted follow/edit/settings/friend-request button logic to switch behavior based on view mode.
Comments suppressed due to low confidence (1)
lib/views/screens/profile_screen.dart:352
- In the follow/edit
ElevatedButton, the button style setsforegroundColortoonSecondarywhen following, but theIconandTextexplicitly usecolorScheme.onPrimary. This overrides the configured foreground color and can produce incorrect contrast (especially whenbackgroundColorissecondary). Consider removing the explicitcolor:/TextStyle(color:)so theforegroundColortakes effect, or compute the icon/text color from the same state as the style.
Icon(
!isOwner
? userProfileController.isFollowingUser.value
? Icons.done
: Icons.add
: Icons.edit,
color: colorScheme.onPrimary,
),
const SizedBox(width: 8),
Text(
!isOwner
? userProfileController.isFollowingUser.value
? AppLocalizations.of(context)!.following
: AppLocalizations.of(context)!.follow
: AppLocalizations.of(context)!.editProfile,
style: TextStyle(color: colorScheme.onPrimary),
),
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| /// 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; |
There was a problem hiding this comment.
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.
| /// 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; |
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
lib/views/screens/profile_screen.dart (2)
150-155:⚠️ Potential issue | 🟠 MajorAvoid empty URL fallback in public avatar image.
Line 151 can construct
NetworkImage('')whenprofileImageUrlis null/empty, which is unsafe for image loading. Use the placeholder URL fallback in public mode too.🔧 Proposed fix
- backgroundImage: !isOwner - ? NetworkImage(widget.creator!.profileImageUrl ?? '') + backgroundImage: !isOwner + ? NetworkImage( + (widget.creator?.profileImageUrl?.isNotEmpty ?? false) + ? widget.creator!.profileImageUrl! + : themeController.userProfileImagePlaceholderUrl, + ) : controller.profileImageUrl == null || controller.profileImageUrl!.isEmpty ? NetworkImage(themeController.userProfileImagePlaceholderUrl) : NetworkImage(controller.profileImageUrl ?? ''),🤖 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 150 - 155, The avatar backgroundImage can create NetworkImage('') when widget.creator!.profileImageUrl is null/empty; update the ternary so both public (not owner) and owner branches validate strings and fall back to themeController.userProfileImagePlaceholderUrl when the URL is null or empty. Specifically check widget.creator!.profileImageUrl for null or empty (similar to controller.profileImageUrl checks) and use themeController.userProfileImagePlaceholderUrl as the NetworkImage fallback to avoid constructing NetworkImage with an empty URL.
210-214:⚠️ Potential issue | 🟠 MajorGuard rating computation when count is zero.
Line 211 divides by
authController.ratingCountwithout a zero check. For new users this can produce invalid rating output or a crash path in formatting.🔧 Proposed fix
- isOwner - ? (authController.ratingTotal / - authController.ratingCount) - .toStringAsFixed(1) - : widget.creator!.userRating!.toStringAsFixed(1), + isOwner + ? (authController.ratingCount > 0 + ? (authController.ratingTotal / + authController.ratingCount) + .toStringAsFixed(1) + : '0.0') + : (widget.creator?.userRating?.toStringAsFixed(1) ?? + '0.0'),🤖 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 210 - 214, The owner-rated display divides authController.ratingTotal by authController.ratingCount without checking for zero; update the isOwner branch in profile_screen.dart so it first checks authController.ratingCount > 0 and only then computes (authController.ratingTotal / authController.ratingCount).toStringAsFixed(1); otherwise return a safe fallback (e.g., "0.0" or another default) to avoid division by zero or formatting errors; keep the non-owner branch using widget.creator!.userRating!.toStringAsFixed(1) unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@lib/views/screens/profile_screen.dart`:
- Around line 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.
---
Outside diff comments:
In `@lib/views/screens/profile_screen.dart`:
- Around line 150-155: The avatar backgroundImage can create NetworkImage('')
when widget.creator!.profileImageUrl is null/empty; update the ternary so both
public (not owner) and owner branches validate strings and fall back to
themeController.userProfileImagePlaceholderUrl when the URL is null or empty.
Specifically check widget.creator!.profileImageUrl for null or empty (similar to
controller.profileImageUrl checks) and use
themeController.userProfileImagePlaceholderUrl as the NetworkImage fallback to
avoid constructing NetworkImage with an empty URL.
- Around line 210-214: The owner-rated display divides
authController.ratingTotal by authController.ratingCount without checking for
zero; update the isOwner branch in profile_screen.dart so it first checks
authController.ratingCount > 0 and only then computes
(authController.ratingTotal / authController.ratingCount).toStringAsFixed(1);
otherwise return a safe fallback (e.g., "0.0" or another default) to avoid
division by zero or formatting errors; keep the non-owner branch using
widget.creator!.userRating!.toStringAsFixed(1) unchanged.
| /// 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; | ||
|
|
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
# Step 1: Examine the ProfileScreen constructor and isOwner getter
sed -n '30,50p' lib/views/screens/profile_screen.dartRepository: AOSSIE-Org/Resonate
Length of output: 743
🏁 Script executed:
# Step 2: Find all ProfileScreen instantiations
rg -n 'ProfileScreen\s*\(' lib/ --type=dart -B2 -A4Repository: 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 -A2Repository: 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.dartRepository: 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.
Summary
Adds a public view mode to the Profile screen to allow users to see how their profile appears to others.
Changes
This improves clarity and ensures consistent behavior when viewing other users’ profiles.
Summary by CodeRabbit