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
119 changes: 119 additions & 0 deletions solution
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
import 'package:flutter/material.dart';
import 'home_screen.dart';
import 'package:nanoid/nanoid.dart';
import 'package:shared_preferences/shared_preferences.dart';
import '../classes/global.dart';

class Profile extends StatefulWidget {
final bool onLogin;
const Profile({Key? key, required this.onLogin}) : super(key: key);

@override
State<Profile> createState() => _ProfileState();
}

class _ProfileState extends State<Profile> {
final TextEditingController myName = TextEditingController();
final _formKey = GlobalKey<FormState>();

bool loading = true;
String customLengthId = nanoid(6);

@override
void initState() {
super.initState();
getDetails();
}

@override
void dispose() {
myName.dispose();
super.dispose();
}

Future<void> getDetails() async {
final prefs = await SharedPreferences.getInstance();
final name = prefs.getString('p_name') ?? '';
final id = prefs.getString('p_id') ?? '';

setState(() {
myName.text = name;
if (id.isNotEmpty) customLengthId = id;
loading = false;
});

// If profile already exists and we arrived here from login flow, go home
if (name.isNotEmpty && id.isNotEmpty && widget.onLogin) {
navigateToHomeScreen();
}
}
Comment on lines +34 to +49
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix: avoid setState/navigation after dispose; schedule post‑frame navigation

getDetails awaits then calls setState and may navigate immediately. If the widget unmounts meanwhile, this will throw. Add mounted checks and schedule navigation with addPostFrameCallback.

   Future<void> getDetails() async {
-    final prefs = await SharedPreferences.getInstance();
-    final name = prefs.getString('p_name') ?? '';
-    final id = prefs.getString('p_id') ?? '';
+    final prefs = await SharedPreferences.getInstance();
+    if (!mounted) return;
+    final name = prefs.getString('p_name') ?? '';
+    final id = prefs.getString('p_id') ?? '';

-    setState(() {
-      myName.text = name;
-      if (id.isNotEmpty) customLengthId = id;
-      loading = false;
-    });
+    if (!mounted) return;
+    setState(() {
+      myName.text = name;
+      if (id.isNotEmpty) customLengthId = id;
+      loading = false;
+    });

     // If profile already exists and we arrived here from login flow, go home
-    if (name.isNotEmpty && id.isNotEmpty && widget.onLogin) {
-      navigateToHomeScreen();
-    }
+    if (name.isNotEmpty && id.isNotEmpty && widget.onLogin) {
+      WidgetsBinding.instance.addPostFrameCallback((_) {
+        if (!mounted) return;
+        navigateToHomeScreen();
+      });
+    }
   }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
Future<void> getDetails() async {
final prefs = await SharedPreferences.getInstance();
final name = prefs.getString('p_name') ?? '';
final id = prefs.getString('p_id') ?? '';
setState(() {
myName.text = name;
if (id.isNotEmpty) customLengthId = id;
loading = false;
});
// If profile already exists and we arrived here from login flow, go home
if (name.isNotEmpty && id.isNotEmpty && widget.onLogin) {
navigateToHomeScreen();
}
}
Future<void> getDetails() async {
final prefs = await SharedPreferences.getInstance();
if (!mounted) return;
final name = prefs.getString('p_name') ?? '';
final id = prefs.getString('p_id') ?? '';
if (!mounted) return;
setState(() {
myName.text = name;
if (id.isNotEmpty) customLengthId = id;
loading = false;
});
// If profile already exists and we arrived here from login flow, go home
if (name.isNotEmpty && id.isNotEmpty && widget.onLogin) {
WidgetsBinding.instance.addPostFrameCallback((_) {
if (!mounted) return;
navigateToHomeScreen();
});
}
}
🤖 Prompt for AI Agents
In solution around lines 34 to 49, getDetails awaits async work then calls
setState and may immediately navigate; if the widget was disposed in the
meantime this will throw. Fix by checking mounted before calling setState (skip
updating state if not mounted), and when deciding to navigate schedule the
navigation in a post-frame callback
(WidgetsBinding.instance.addPostFrameCallback) and re-check mounted before
calling navigateToHomeScreen; ensure no setState or navigation runs when mounted
is false.


void navigateToHomeScreen() {
Global.myName = myName.text;
if (!widget.onLogin) {
Navigator.pop(context);
} else {
Navigator.pushReplacement(
context,
MaterialPageRoute(builder: (context) => const HomeScreen()),
);
}
}

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Profile')),
body: loading
? const Center(child: CircularProgressIndicator())
: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
// show what the final username will look like
Text('Your username will be: ${myName.text}$customLengthId'),
const SizedBox(height: 16),
Form(
key: _formKey,
child: TextFormField(
controller: myName,
decoration: const InputDecoration(
icon: Icon(Icons.person),
hintText: 'What do people call you?',
labelText: 'Name *',
border: OutlineInputBorder(),
),
validator: (value) {
final v = value?.trim() ?? '';
if (v.isEmpty) return 'Please enter a name';
if (v.contains('@')) return 'Do not use the @ character';
if (v.length <= 3) return 'Name should be greater than 3 characters';
return null;
Comment on lines +88 to +92
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Validation off‑by‑one vs PR objective (“minimum of 3 characters”)

Current rule enforces 4+. Adjust to 3+ and fix the message.

-                        if (v.length <= 3) return 'Name should be greater than 3 characters';
+                        if (v.length < 3) return 'Name must be at least 3 characters';
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
final v = value?.trim() ?? '';
if (v.isEmpty) return 'Please enter a name';
if (v.contains('@')) return 'Do not use the @ character';
if (v.length <= 3) return 'Name should be greater than 3 characters';
return null;
final v = value?.trim() ?? '';
if (v.isEmpty) return 'Please enter a name';
if (v.contains('@')) return 'Do not use the @ character';
if (v.length < 3) return 'Name must be at least 3 characters';
return null;
🤖 Prompt for AI Agents
In solution around lines 88 to 92, the validator currently rejects names of
length 3 (using v.length <= 3) and the message says "greater than 3 characters"
which conflicts with the PR objective of a minimum of 3; change the length check
to v.length < 3 and update the message to something like "Name should be at
least 3 characters" (keep existing trim and other checks unchanged).

},
),
),
const SizedBox(height: 16),
ElevatedButton(
onPressed: () async {
if (!(_formKey.currentState?.validate() ?? false)) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Please fix the errors')),
);
return;
}

final prefs = await SharedPreferences.getInstance();
await prefs.setString('p_name', myName.text.trim());
await prefs.setString('p_id', customLengthId);

navigateToHomeScreen();
},
child: const Text('Save'),
),
],
),
),
);
}
}