From 845de14436ded128b55d39af57fbe503e6e3ed99 Mon Sep 17 00:00:00 2001 From: ken-morel Date: Mon, 23 Jun 2025 18:30:38 +0100 Subject: [PATCH 1/3] Working name&username&password page --- lib/appstate.dart | 1 + lib/backend.dart | 27 +- lib/models/user.dart | 26 +- lib/pages/home.dart | 19 +- lib/pages/sign/signup/namepassword.dart | 351 +++++++++++++++++------- lib/pages/welcomepage.dart | 4 +- lib/utils/username.dart | 6 + 7 files changed, 309 insertions(+), 125 deletions(-) create mode 100644 lib/utils/username.dart diff --git a/lib/appstate.dart b/lib/appstate.dart index 84c1767..feba98d 100644 --- a/lib/appstate.dart +++ b/lib/appstate.dart @@ -9,6 +9,7 @@ class AppState { final models.User? user; const AppState({this.session, this.user}); static Future load() async { + await Future.delayed(Duration(seconds: 5)); final prefs = await SharedPreferences.getInstance(); final appStateJson = prefs.getString(appStateKey); if (appStateJson != null) { diff --git a/lib/backend.dart b/lib/backend.dart index 708f06c..2041810 100644 --- a/lib/backend.dart +++ b/lib/backend.dart @@ -12,17 +12,24 @@ Future> query( Map data, models.Session? session, ) async { - final response = await http.post( - Uri.parse("${getBackendBase()}/api/$url"), - body: data, - headers: { - 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8', - if (session != null) ...{ - 'session-token': session.token, - 'session-id': session.id.toString(), + late http.Response response; + try { + response = await http.post( + Uri.parse("${getBackendBase()}/api/$url"), + body: data, + headers: { + 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8', + if (session != null) ...{ + 'session-token': session.token, + 'session-id': session.id.toString(), + }, }, - }, - ); + ); + } catch (e) { + throw Exception( + 'Could not connect to backend, check your internet connection.', + ); + } if (response.statusCode == 200) { return jsonDecode(response.body); } else { diff --git a/lib/models/user.dart b/lib/models/user.dart index d312052..6ecfb3f 100644 --- a/lib/models/user.dart +++ b/lib/models/user.dart @@ -38,10 +38,34 @@ class User extends Model { } static Future getByID(int id) async { - final data = await backend.query("user/get", {"id": id.toString()}, null); + final data = await backend.query("v1/user/get", { + "id": id.toString(), + }, null); if (data["status"] < 0) { throw Exception("Failed to get user by ID: ${data["message"]}"); } return User.fromJson(data["user"] as Map); } + + static Future usernameInfo(String name) async { + final data = await backend.query("v1/username/info", { + "username": name, + }, null); + if (data['status'] < 0) { + throw Exception("Failed to check username: ${data['message']}"); + } + return UsernameInfo.fromJson(data['info'] as Map); + } +} + +class UsernameInfo { + final bool isValid; + final bool isTaken; + const UsernameInfo({required this.isValid, required this.isTaken}); + factory UsernameInfo.fromJson(Map json) { + return UsernameInfo( + isValid: json['is_valid'] as bool, + isTaken: json['is_taken'] as bool, + ); + } } diff --git a/lib/pages/home.dart b/lib/pages/home.dart index ce40409..3476dae 100644 --- a/lib/pages/home.dart +++ b/lib/pages/home.dart @@ -8,13 +8,18 @@ Widget getPage() { future: AppState.load(), builder: (context, snapshot) { if (snapshot.connectionState == ConnectionState.waiting) { - return const LoadingWidget( - messages: [ - "Loading app state...", - "Please wait...", - "Almost there...", - ], - switchInterval: Duration(seconds: 3), + return const Scaffold( + body: LoadingWidget( + messages: [ + "Loading app state...", + "Verifying user details...", + "Getting permissions from your schools..", + "Verifying the age on your birth certificate...", + "Please wait...", + "Almost there...", + ], + switchInterval: Duration(seconds: 1), + ), ); } else if (snapshot.hasData) { final appState = snapshot.data!; diff --git a/lib/pages/sign/signup/namepassword.dart b/lib/pages/sign/signup/namepassword.dart index fd197ab..7b49445 100644 --- a/lib/pages/sign/signup/namepassword.dart +++ b/lib/pages/sign/signup/namepassword.dart @@ -1,7 +1,12 @@ +import 'dart:async'; + import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; -import 'form.dart'; +import 'package:ins/models.dart' as models; +import 'package:ins/utils/username.dart'; + import 'base.dart'; +import 'form.dart'; class NamePasswordPage extends StatefulWidget { final SignupForm form; @@ -14,152 +19,288 @@ class NamePasswordPage extends StatefulWidget { class _NamePasswordPageState extends State { final TextEditingController _nameController = TextEditingController(); + final TextEditingController _usernameController = TextEditingController(); final TextEditingController _passwordController = TextEditingController(); final TextEditingController _password2Controller = TextEditingController(); + String? _usernameCheckError; bool _obscureText = true; bool _isPasswordValid = false; bool _isNameValid = false; bool _arePasswordMatching = false; - - @override - void initState() { - super.initState(); - _nameController.addListener(verifyEntries); - _passwordController.addListener(verifyEntries); - _password2Controller.addListener(verifyEntries); - } + bool _isUserNameAvailable = false; + bool _isCheckingUsername = false; + bool _wasUsernameEdited = false; @override Widget build(BuildContext context) { return SignupAssistantBase( body: Padding( padding: const EdgeInsets.all( - 0, + 20, ), //const EdgeInsets.symmetric(horizontal: 20, vertical: 30), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const SizedBox(height: 20), - Text( - "Create Your Profile", - style: Theme.of(context).textTheme.headlineLarge, - ), - const SizedBox(height: 30), - TextField( - controller: _nameController, - decoration: const InputDecoration( - labelText: "Full Name", - hintText: 'John Doe', - border: OutlineInputBorder(), + child: SingleChildScrollView( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const SizedBox(height: 20), + Text( + "Choose a name", + style: Theme.of(context).textTheme.headlineLarge, ), - autofocus: true, - keyboardType: TextInputType.name, - textCapitalization: TextCapitalization.words, - autocorrect: false, - ), - const SizedBox(height: 20), - TextField( - controller: _passwordController, - decoration: InputDecoration( - labelText: "Password", - border: const OutlineInputBorder(), - suffixIcon: Row( - mainAxisSize: MainAxisSize.min, - children: [ - IconButton( - icon: Icon( - _obscureText ? Icons.visibility : Icons.visibility_off, - ), - onPressed: () => - setState(() => _obscureText = !_obscureText), - ), - ], + const SizedBox(height: 30), + TextField( + controller: _nameController, + decoration: const InputDecoration( + prefixIcon: Icon(Icons.person), + labelText: "Full Name", + hintText: 'Temex Vironie', + border: OutlineInputBorder(), + helperText: "Your private name, not shown to others", ), + autofocus: true, + keyboardType: TextInputType.name, + textCapitalization: TextCapitalization.words, + autocorrect: false, + onChanged: (_) { + if (!_wasUsernameEdited) generateUsername(); + }, ), - obscureText: _obscureText, - autofocus: true, - keyboardType: TextInputType.visiblePassword, - textCapitalization: TextCapitalization.none, - inputFormatters: [ - FilteringTextInputFormatter.deny(RegExp(r'\s')), - ], - ), - if (_passwordController.text.isNotEmpty) - Padding( - padding: const EdgeInsets.only(top: 8.0), - child: _buildPasswordStatus(), + const SizedBox(height: 20), + TextField( + controller: _usernameController, + decoration: InputDecoration( + prefixIcon: Icon(Icons.person_outline), + labelText: "Username", + hintText: 'temexvironie12', + border: OutlineInputBorder(), + helperText: "A short, public username for your profile", + suffixIcon: _isCheckingUsername + ? const Padding( + padding: EdgeInsets.all(8.0), + child: CircularProgressIndicator(strokeWidth: 2), + ) + : _isUserNameAvailable + ? const Padding( + padding: EdgeInsets.only(right: 10), + child: Icon(Icons.check_circle, color: Colors.green), + ) + : null, + error: _buildUsernameError(), + ), + autofocus: true, + keyboardType: TextInputType.text, + textCapitalization: TextCapitalization.none, + autocorrect: false, + inputFormatters: [ + FilteringTextInputFormatter( + " ", + replacementString: "_", + allow: false, + ), + FilteringTextInputFormatter.deny(RegExp(r'[^a-z0-9_]')), + ], + onChanged: (_) { + setState(() { + _wasUsernameEdited = true; + verifyNames(); + }); + }, ), - const SizedBox(height: 20), - TextField( - controller: _password2Controller, - decoration: InputDecoration( - labelText: "Reenter password", - border: const OutlineInputBorder(), - suffixIcon: Row( - mainAxisSize: MainAxisSize.min, - children: [ - _arePasswordMatching - ? Icon(Icons.check_circle, color: Colors.green) - : Icon(Icons.cancel_rounded, color: Colors.red), - ], + + const SizedBox(height: 40), + Text( + "And a password", + style: Theme.of(context).textTheme.headlineLarge, + ), + const SizedBox(height: 30), + TextField( + controller: _passwordController, + decoration: InputDecoration( + prefixIcon: Icon(Icons.lock), + labelText: "Password", + border: const OutlineInputBorder(), + error: _buildPasswordError(), + suffixIcon: Row( + mainAxisSize: MainAxisSize.min, + children: [ + IconButton( + icon: Icon( + !_obscureText + ? Icons.visibility + : Icons.visibility_off, + ), + onPressed: () => + setState(() => _obscureText = !_obscureText), + ), + SizedBox(width: 8), + ], + ), ), + obscureText: _obscureText, + autofocus: true, + keyboardType: TextInputType.visiblePassword, + textCapitalization: TextCapitalization.none, + inputFormatters: [ + FilteringTextInputFormatter.deny(RegExp(r'\s')), + ], ), - obscureText: _obscureText, - autofocus: true, - keyboardType: TextInputType.visiblePassword, - textCapitalization: TextCapitalization.none, - inputFormatters: [ - FilteringTextInputFormatter.deny(RegExp(r'\s')), - ], - ), - if (_password2Controller.text.isNotEmpty) - Padding( - padding: const EdgeInsets.only(top: 8.0), - child: _buildPassword2Status(), + const SizedBox(height: 20), + TextField( + controller: _password2Controller, + decoration: InputDecoration( + prefixIcon: Icon(Icons.lock), + labelText: "Reenter password", + border: const OutlineInputBorder(), + error: _password2Controller.text.isNotEmpty + ? _buildPassword2Error() + : null, + suffixIcon: Row( + mainAxisSize: MainAxisSize.min, + children: [ + if (_password2Controller.text.isNotEmpty) + if (_arePasswordMatching) + Icon(Icons.check_circle, color: Colors.green) + else + Icon(Icons.cancel_rounded, color: Colors.red), + ], + ), + ), + obscureText: _obscureText, + autofocus: true, + keyboardType: TextInputType.visiblePassword, + textCapitalization: TextCapitalization.none, + inputFormatters: [ + FilteringTextInputFormatter.deny(RegExp(r'\s')), + ], ), - ], + ], + ), ), ), title: const Text("Profile Setup"), showNextButton: true, - next: (_isNameValid && _isPasswordValid && _arePasswordMatching) - ? () => gotoNext() - : null, + next: !(_isNameValid && _isPasswordValid && _arePasswordMatching) + ? null + : () { + //Navigator.of( + // context, + //).push(MaterialPageRoute(builder: (context) => null)); + }, ); } - Widget _buildPasswordStatus() { - if (!_isPasswordValid) { + void generateUsername() { + final name = _nameController.text; + _usernameController.text = formatUsername(name); + } + + @override + void initState() { + super.initState(); + _nameController.addListener(verifyNames); + _usernameController.addListener(verifyUsername); + _passwordController.addListener(verifyPasswords); + _password2Controller.addListener(verifyPasswords); + } + + void verifyNames() { + verifyUsername(); + setState(() { + _isNameValid = _nameController.text.isNotEmpty; + _arePasswordMatching = + _passwordController.text == _password2Controller.text; + }); + } + + void verifyPasswords() { + setState(() { + _isPasswordValid = _passwordController.text.length >= 8; + _arePasswordMatching = + _passwordController.text == _password2Controller.text; + }); + } + + Future verifyUsername() async { + if (_isCheckingUsername || _usernameController.text.isEmpty) { + return; // Prevent multiple checks + } + setState(() { + _isCheckingUsername = true; + }); + await Future.delayed(const Duration(milliseconds: 2000)); + try { + final usenameInfo = await models.User.usernameInfo( + _usernameController.text, + ); + setState(() { + _isUserNameAvailable = !usenameInfo.isTaken; + _usernameCheckError = null; + _isCheckingUsername = false; + }); + } catch (e) { + setState(() { + _usernameCheckError = e.toString(); + _isUserNameAvailable = false; + _isCheckingUsername = false; + }); + } + } + + Widget? _buildPassword2Error() { + if (_password2Controller.text.isEmpty) return null; + if (!_arePasswordMatching) { return Text( - "Password must have atleast 8 characters", + "Password do not match", style: Theme.of( context, ).textTheme.bodySmall?.copyWith(color: Colors.red), ); } - return const SizedBox.shrink(); + return null; } - Widget _buildPassword2Status() { - if (!_arePasswordMatching) { + Widget? _buildPasswordError() { + if (_passwordController.text.isEmpty) return null; + if (!_isPasswordValid) { return Text( - "Password do not match", + "Password must have atleast 8 characters", style: Theme.of( context, ).textTheme.bodySmall?.copyWith(color: Colors.red), ); } - return const SizedBox.shrink(); + return null; } - void gotoNext() {} - - void verifyEntries() { - setState(() { - _isPasswordValid = _passwordController.text.length >= 8; - _isNameValid = _nameController.text.isNotEmpty; - _arePasswordMatching = - _passwordController.text == _password2Controller.text; - }); + Widget? _buildUsernameError() { + if (_usernameController.text.isEmpty) return null; + if (_usernameCheckError != null) { + return Text( + _usernameCheckError!, + style: Theme.of( + context, + ).textTheme.bodySmall?.copyWith(color: Colors.red), + ); + } + final username = _usernameController.text; + if (_wasUsernameEdited) { + if (username.length < 3 || username.length > 20) { + return Text( + "Username must be between 3 and 20 characters", + style: Theme.of( + context, + ).textTheme.bodySmall?.copyWith(color: Colors.red), + ); + } + } + if (!_isUserNameAvailable) { + return Text( + "Username is already taken", + style: Theme.of( + context, + ).textTheme.bodySmall?.copyWith(color: Colors.red), + ); + } + return null; } } diff --git a/lib/pages/welcomepage.dart b/lib/pages/welcomepage.dart index 523eaaf..43d0e2b 100644 --- a/lib/pages/welcomepage.dart +++ b/lib/pages/welcomepage.dart @@ -19,7 +19,7 @@ class WelcomePage extends StatelessWidget { children: [ CircleAvatar( backgroundImage: AssetImage('assets/icon/is.png'), - radius: 100, + radius: 150, ), ], ), @@ -35,7 +35,7 @@ class WelcomePage extends StatelessWidget { ), ], ), - SizedBox(height: 150), + SizedBox(height: 325), Row( mainAxisAlignment: MainAxisAlignment.end, children: [ diff --git a/lib/utils/username.dart b/lib/utils/username.dart new file mode 100644 index 0000000..80bffd8 --- /dev/null +++ b/lib/utils/username.dart @@ -0,0 +1,6 @@ +String formatUsername(String name) { + return name + .toLowerCase() + .replaceAll(" ", "_") + .replaceAll(RegExp("[^a-z1-9_]+"), ""); +} From da953423a3062d07e3e7ca16f39b999266156848 Mon Sep 17 00:00:00 2001 From: ken-morel Date: Tue, 24 Jun 2025 00:36:54 +0100 Subject: [PATCH 2/3] Improved design --- assets/icon/is-transparent-crop.png | Bin 0 -> 55581 bytes assets/icon/is-transparent.png | Bin 0 -> 64169 bytes lib/animations/page/slide.dart | 56 ++++++++ lib/appstate.dart | 6 +- lib/pages/sign/signup/base.dart | 129 ++++++++++++++++-- lib/pages/sign/signup/extlinked.dart | 144 ++++++++++++++++++++ lib/pages/sign/signup/form.dart | 19 +++ lib/pages/sign/signup/launcher.dart | 6 +- lib/pages/sign/signup/namepassword.dart | 28 ++-- lib/pages/sign/signup/submit.dart | 10 ++ lib/pages/welcomepage.dart | 173 ++++++++++++++++++------ lib/utils/email.dart | 15 ++ pubspec.lock | 48 +++++++ pubspec.yaml | 1 + 14 files changed, 559 insertions(+), 76 deletions(-) create mode 100644 assets/icon/is-transparent-crop.png create mode 100644 assets/icon/is-transparent.png create mode 100644 lib/animations/page/slide.dart create mode 100644 lib/pages/sign/signup/extlinked.dart create mode 100644 lib/pages/sign/signup/submit.dart create mode 100644 lib/utils/email.dart diff --git a/assets/icon/is-transparent-crop.png b/assets/icon/is-transparent-crop.png new file mode 100644 index 0000000000000000000000000000000000000000..44e8c07c1f103d9332c0bb17568cfc6f3393464e GIT binary patch literal 55581 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�ew%brKx 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 z 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%0D_p)YV==Nm`XfO0D!=qVZE09pS-Gr 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 Zv+Fa>d4iiT{x%|y^FF^eoV)U`{{#2QKK}p! literal 0 HcmV?d00001 diff --git a/lib/animations/page/slide.dart b/lib/animations/page/slide.dart new file mode 100644 index 0000000..fc93bf4 --- /dev/null +++ b/lib/animations/page/slide.dart @@ -0,0 +1,56 @@ +import 'package:flutter/material.dart'; + +class SlidePageRoute extends PageRouteBuilder { + final Widget child; + final AxisDirection direction; + final Duration duration; + + SlidePageRoute({ + super.settings, + required this.child, + this.duration = const Duration(milliseconds: 400), + this.direction = AxisDirection.left, + }) : super( + pageBuilder: + ( + BuildContext context, + Animation animation, + Animation secondaryAnimation, + ) => child, + transitionDuration: duration, // Adjust duration as needed + transitionsBuilder: + ( + BuildContext context, + Animation animation, + Animation secondaryAnimation, + Widget child, + ) { + Offset beginOffset; + switch (direction) { + case AxisDirection.up: + beginOffset = Offset(0, 1); + break; + case AxisDirection.down: + beginOffset = Offset(0, -1); + break; + case AxisDirection.left: + beginOffset = Offset(1, 0); + break; + case AxisDirection.right: + beginOffset = Offset(-1, 0); + break; + } + + final tween = Tween(begin: beginOffset, end: Offset.zero); + final curvedAnimation = CurvedAnimation( + parent: animation, + curve: Curves.easeInOut, // Choose your curve + ); + + return SlideTransition( + position: tween.animate(curvedAnimation), + child: child, + ); + }, + ); +} diff --git a/lib/appstate.dart b/lib/appstate.dart index feba98d..c98cca7 100644 --- a/lib/appstate.dart +++ b/lib/appstate.dart @@ -5,9 +5,9 @@ import 'dart:convert'; const appStateKey = "app-state"; class AppState { - final models.Session? session; - final models.User? user; - const AppState({this.session, this.user}); + models.Session? session; + models.User? user; + AppState({this.session, this.user}); static Future load() async { await Future.delayed(Duration(seconds: 5)); final prefs = await SharedPreferences.getInstance(); diff --git a/lib/pages/sign/signup/base.dart b/lib/pages/sign/signup/base.dart index 8ac70db..dd037c7 100644 --- a/lib/pages/sign/signup/base.dart +++ b/lib/pages/sign/signup/base.dart @@ -1,3 +1,4 @@ +import 'dart:ui'; import 'package:flutter/material.dart'; class SignupAssistantBase extends StatelessWidget { @@ -5,34 +6,132 @@ class SignupAssistantBase extends StatelessWidget { final Widget body; final Function()? next; final bool showNextButton; + final String nextText; + const SignupAssistantBase({ super.key, required this.title, required this.body, this.showNextButton = false, this.next, + this.nextText = "Continue >", }); + + // Define a breakpoint for wide screens + static const double _wideScreenBreakpoint = 720.0; + @override Widget build(BuildContext context) { return Scaffold( - appBar: AppBar(title: title, leading: BackButton()), - body: Center( - child: Padding( - padding: const EdgeInsets.all(16.0), - child: Column( - children: [ - body, - if (showNextButton) ...[ - const Spacer(), - SizedBox( - width: double.infinity, - child: FilledButton( + appBar: AppBar( + title: title, + leading: const BackButton(), + backgroundColor: Colors.transparent, // Make AppBar transparent + elevation: 0, // No shadow for AppBar + ), + extendBodyBehindAppBar: true, // Allow body to extend behind AppBar + body: Stack( + children: [ + // 1. Background Image + Positioned.fill( + child: Image.asset( + "assets/icon/is-transparent-crop.png", // Ensure this path is correct + fit: BoxFit.cover, + errorBuilder: (context, error, stackTrace) { + // Fallback if image fails to load + return Container( + color: Theme.of(context).colorScheme.secondary, + ); + }, + ), + ), + + // 2. Blur Overlay + Positioned.fill( + child: BackdropFilter( + filter: ImageFilter.blur(sigmaX: 10, sigmaY: 10), + child: Container( + // Add a subtle tint to the blur for better text contrast if needed + color: Colors.black.withOpacity(0.1), + ), + ), + ), + + // 3. Content Layer + SafeArea( + child: LayoutBuilder( + builder: (context, constraints) { + final bool isWideScreen = + constraints.maxWidth > _wideScreenBreakpoint; + + if (isWideScreen) { + // Wide screen layout: Two-pane + return Row( + children: [ + // Left pane (can be empty, show another graphic, or branding) + const Expanded( + flex: 1, // Adjust flex to change proportions + child: + SizedBox(), // This will show the blurred background + ), + // Right pane (form content) + Expanded( + flex: 1, // Adjust flex + child: Center( + // Center the card in this pane + child: _buildFormContentCard(context), + ), + ), + ], + ); + } else { + // Narrow screen layout: Single centered column + return Center(child: _buildFormContentCard(context)); + } + }, + ), + ), + ], + ), + ); + } + + Widget _buildFormContentCard(BuildContext context) { + return Padding( + // Add padding around the card itself for spacing from screen edges + padding: const EdgeInsets.symmetric(horizontal: 20.0, vertical: 20.0), + child: Material( + elevation: 8.0, + borderRadius: BorderRadius.circular(16.0), + // Make card background slightly transparent to blend with blurred background + color: Theme.of(context).colorScheme.surface.withOpacity(0.85), + child: SingleChildScrollView( + // Allows content to scroll if it's too long + padding: const EdgeInsets.all(24.0), + child: ConstrainedBox( + constraints: const BoxConstraints( + maxWidth: 400, // Max width for the form content itself + ), + child: Column( + mainAxisSize: + MainAxisSize.min, // So column takes minimum necessary height + crossAxisAlignment: + CrossAxisAlignment.stretch, // Button will stretch + children: [ + body, // Your main form widgets + if (showNextButton) ...[ + const SizedBox(height: 24.0), // Spacing before the button + FilledButton( onPressed: next, - child: const Text("Continue >"), + style: FilledButton.styleFrom( + padding: const EdgeInsets.symmetric(vertical: 16.0), + textStyle: Theme.of(context).textTheme.labelLarge, + ), + child: Text(nextText), ), - ), + ], ], - ], + ), ), ), ), diff --git a/lib/pages/sign/signup/extlinked.dart b/lib/pages/sign/signup/extlinked.dart new file mode 100644 index 0000000..4febbbd --- /dev/null +++ b/lib/pages/sign/signup/extlinked.dart @@ -0,0 +1,144 @@ +import 'package:flutter/material.dart'; +import 'form.dart'; +import 'base.dart'; +import 'package:ins/utils/email.dart'; +import 'package:intl_phone_number_input/intl_phone_number_input.dart'; + +class ExtraLinkedPage extends StatefulWidget { + final SignupForm form; + + const ExtraLinkedPage({super.key, required this.form}); + + @override + State createState() => _ExtraLinkedPageState(); +} + +class _ExtraLinkedPageState extends State { + final TextEditingController _emailController = TextEditingController(); + final TextEditingController _phoneController = TextEditingController(); + bool _phoneValid = true; + String? _emailError; + @override + Widget build(BuildContext context) { + return SignupAssistantBase( + body: Padding( + padding: const EdgeInsets.all( + 20, + ), //const EdgeInsets.symmetric(horizontal: 20, vertical: 30), + child: SingleChildScrollView( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const SizedBox(height: 30), + Text( + "Optional information.", + style: Theme.of(context).textTheme.headlineLarge, + ), + const SizedBox(height: 30), + TextField( + controller: _emailController, + decoration: InputDecoration( + prefixIcon: Icon(Icons.person_outline), + labelText: "Email Address", + hintText: 'temexvironie12@ama.co', + border: OutlineInputBorder(), + suffixIcon: _emailError == null + ? const Padding( + padding: EdgeInsets.only(right: 10), + child: Icon(Icons.check_circle, color: Colors.green), + ) + : const Padding( + padding: EdgeInsets.only(right: 10), + child: Icon( + Icons.cancel_rounded, + color: Colors.green, + ), + ), + error: _buildEmailError(), + ), + autofocus: true, + keyboardType: TextInputType.emailAddress, + autocorrect: false, + onChanged: (_) { + verifyEmail(); + }, + ), + const SizedBox(height: 30), + InternationalPhoneNumberInput( + onInputChanged: (PhoneNumber number) { + setState(() { + _phoneValid = + number.phoneNumber == null || + number.phoneNumber!.length == 9 + 4; + }); + }, + onInputValidated: (bool value) { + setState(() { + //_phoneValid = value; + }); + }, + ignoreBlank: true, + textFieldController: _phoneController, + formatInput: true, + keyboardType: const TextInputType.numberWithOptions( + signed: true, + decimal: true, + ), + inputDecoration: InputDecoration( + labelText: 'Phone Number', + border: OutlineInputBorder(), + error: _phoneValid + ? null + : Text( + "Phone number should be 9 digits long (without country code)", + style: Theme.of( + context, + ).textTheme.bodySmall?.copyWith(color: Colors.red), + ), + ), + countries: ["CM"], + ), + ], + ), + ), + ), + title: const Text("Add email and/or phone number"), + showNextButton: true, + next: + (_emailError == null || _emailController.text.isEmpty) && + (_phoneValid || _phoneController.text.isEmpty) + ? () => _next(context) + : null, + ); + } + + void verifyEmail() { + setState(() { + if (_emailController.text.isEmpty) { + _emailError = null; + } else { + _emailError = chechEmail(_emailController.text); + } + }); + } + + Widget? _buildEmailError() { + return _emailController.text.isNotEmpty && _emailError != null + ? Text( + _emailError!, + style: Theme.of( + context, + ).textTheme.bodySmall?.copyWith(color: Colors.red), + ) + : null; + } + + void _next(BuildContext context) { + if (_emailController.text.isNotEmpty) { + widget.form.email = _emailController.text; + } + if (_phoneController.text.isNotEmpty) { + widget.form.phone = _phoneController.text; + } + } +} diff --git a/lib/pages/sign/signup/form.dart b/lib/pages/sign/signup/form.dart index fa23859..59671f7 100644 --- a/lib/pages/sign/signup/form.dart +++ b/lib/pages/sign/signup/form.dart @@ -1,7 +1,26 @@ +import 'package:ins/models.dart' as models; +import 'package:ins/appstate.dart'; +import 'package:ins/backend.dart' as backend; + class SignupForm { String? username; String? email; String? fullname; String? password; String? phone; + Future submit() { + throw "Error signin you up"; + } +} + +class SignupFormSubmitResult { + final models.Session session; + final models.User user; + const SignupFormSubmitResult({required this.session, required this.user}); + Future saveInState() async { + AppState state = await AppState.load(); + state.session = session; + state.user = user; + state.save(); + } } diff --git a/lib/pages/sign/signup/launcher.dart b/lib/pages/sign/signup/launcher.dart index 796b87b..a5a83f0 100644 --- a/lib/pages/sign/signup/launcher.dart +++ b/lib/pages/sign/signup/launcher.dart @@ -1,12 +1,10 @@ import 'package:flutter/material.dart'; import 'namepassword.dart'; import 'form.dart'; +import 'package:ins/animations/page/slide.dart'; void launchSignupAssistant(BuildContext context) { SignupForm form = SignupForm(); - Navigator.push( - context, - MaterialPageRoute(builder: (context) => NamePasswordPage(form: form)), - ); + Navigator.push(context, SlidePageRoute(child: NamePasswordPage(form: form))); } diff --git a/lib/pages/sign/signup/namepassword.dart b/lib/pages/sign/signup/namepassword.dart index 7b49445..6636464 100644 --- a/lib/pages/sign/signup/namepassword.dart +++ b/lib/pages/sign/signup/namepassword.dart @@ -2,11 +2,13 @@ import 'dart:async'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; +import 'package:ins/animations/page/slide.dart'; import 'package:ins/models.dart' as models; import 'package:ins/utils/username.dart'; import 'base.dart'; import 'form.dart'; +import 'extlinked.dart'; class NamePasswordPage extends StatefulWidget { final SignupForm form; @@ -42,12 +44,6 @@ class _NamePasswordPageState extends State { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - const SizedBox(height: 20), - Text( - "Choose a name", - style: Theme.of(context).textTheme.headlineLarge, - ), - const SizedBox(height: 30), TextField( controller: _nameController, decoration: const InputDecoration( @@ -107,11 +103,6 @@ class _NamePasswordPageState extends State { }, ), - const SizedBox(height: 40), - Text( - "And a password", - style: Theme.of(context).textTheme.headlineLarge, - ), const SizedBox(height: 30), TextField( controller: _passwordController, @@ -181,11 +172,7 @@ class _NamePasswordPageState extends State { showNextButton: true, next: !(_isNameValid && _isPasswordValid && _arePasswordMatching) ? null - : () { - //Navigator.of( - // context, - //).push(MaterialPageRoute(builder: (context) => null)); - }, + : () => _next(context), ); } @@ -303,4 +290,13 @@ class _NamePasswordPageState extends State { } return null; } + + void _next(BuildContext context) { + widget.form.fullname = _nameController.text; + widget.form.username = _usernameController.text; + widget.form.password = _passwordController.text; + Navigator.of( + context, + ).push(SlidePageRoute(child: ExtraLinkedPage(form: widget.form))); + } } diff --git a/lib/pages/sign/signup/submit.dart b/lib/pages/sign/signup/submit.dart new file mode 100644 index 0000000..66c18b9 --- /dev/null +++ b/lib/pages/sign/signup/submit.dart @@ -0,0 +1,10 @@ +import 'package:flutter/material.dart'; +import 'base.dart'; +import 'form.dart'; + +class SubmitingPage extends StatelessWidget { + @override + Widget build(BuildContext context) { + return FutureBuilder(future: future, builder: builder) + } +} diff --git a/lib/pages/welcomepage.dart b/lib/pages/welcomepage.dart index 43d0e2b..68b91fb 100644 --- a/lib/pages/welcomepage.dart +++ b/lib/pages/welcomepage.dart @@ -6,53 +6,150 @@ class WelcomePage extends StatelessWidget { @override Widget build(BuildContext context) { + final TextTheme textTheme = Theme.of(context).textTheme; + final ColorScheme colorScheme = Theme.of(context).colorScheme; + final screenWidth = MediaQuery.of(context).size.width; + + // Responsive radius for the CircleAvatar + // Clamped between a min and max radius for better control and appearance. + final double avatarRadius = (screenWidth * 0.22).clamp(70.0, 110.0); + return Scaffold( - appBar: AppBar(title: const Text('Welcome')), - body: Center( - child: SizedBox( - width: 300, - child: Stack( - alignment: Alignment.center, + appBar: AppBar( + title: const Text('Welcome'), + // Optional: Make AppBar transparent for a more modern merged look + // backgroundColor: Colors.transparent, + // elevation: 0, + ), + body: SafeArea( + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 24.0, vertical: 16.0), + child: Column( + crossAxisAlignment: + CrossAxisAlignment.center, // Center children horizontally children: [ - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - CircleAvatar( - backgroundImage: AssetImage('assets/icon/is.png'), - radius: 150, - ), - ], + const Spacer(flex: 2), // Pushes content down from AppBar + + CircleAvatar( + // Ensure this asset path is correct and declared in pubspec.yaml + backgroundImage: const AssetImage('assets/icon/is.png'), + radius: avatarRadius, + backgroundColor: colorScheme + .secondaryContainer, // Fallback bg if image is transparent/fails + onBackgroundImageError: (exception, stackTrace) { + // You might want to log this or show a placeholder icon + print('Error loading CircleAvatar image: $exception'); + }, ), - Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.start, - children: [ - FilledButton.tonal( - onPressed: () {}, - child: Text("Connect account"), - ), - ], - ), - SizedBox(height: 325), - Row( - mainAxisAlignment: MainAxisAlignment.end, - children: [ - FilledButton.tonal( - onPressed: () { - launchSignupAssistant(context); - }, - child: Text("Create account"), - ), - ], + + const SizedBox(height: 32.0), + + Text( + "Welcome to Ins!", // Replace 'Ins' with your actual app name if different + style: textTheme.headlineMedium?.copyWith( + fontWeight: FontWeight.bold, + color: colorScheme.primary, + ), + textAlign: TextAlign.center, + ), + + const SizedBox(height: 12.0), + + Padding( + padding: const EdgeInsets.symmetric( + horizontal: 16.0, + ), // Extra padding for text block + child: Text( + "Connect an existing account or create a new one to embark on your journey with us.", + style: textTheme.bodyLarge?.copyWith( + color: colorScheme.onSurfaceVariant, ), - ], + textAlign: TextAlign.center, + ), + ), + + const Spacer( + flex: 3, + ), // Creates more space, pushing buttons towards the bottom + + _buildWelcomeButton( + context: context, + text: "Connect account", + onPressed: () { + // TODO: Implement connect account logic + // For example, navigate to a login page or OAuth flow + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: Text("Connect account tapped (Not implemented)"), + ), + ); + }, + isPrimary: false, // Visually less prominent + ), + + const SizedBox(height: 16.0), + + _buildWelcomeButton( + context: context, + text: "Create account", + onPressed: () { + launchSignupAssistant(context); + }, + isPrimary: true, // Primary call to action ), + + const Spacer(flex: 1), // Adds some breathing room at the bottom ], ), ), ), ); } + + Widget _buildWelcomeButton({ + required BuildContext context, + required String text, + required VoidCallback onPressed, + bool isPrimary = false, + }) { + // Common styling for buttons + final baseStyle = ElevatedButton.styleFrom( + padding: const EdgeInsets.symmetric(horizontal: 32, vertical: 14), + textStyle: Theme.of(context).textTheme.labelLarge?.copyWith( + fontWeight: FontWeight.w600, // Slightly bolder + fontSize: 16, // Slightly larger font + ), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(24.0), // More rounded, modern feel + ), + // Optional: If you want to ensure buttons have a minimum width + // This helps if one button has very short text and the other long text. + // Adjust the width (e.g., 200) as needed, or remove if not desired. + minimumSize: Size(MediaQuery.of(context).size.width * 0.6, 52), + ); + + if (isPrimary) { + return FilledButton( + onPressed: onPressed, + style: baseStyle, + child: Text(text), + ); + } else { + return FilledButton.tonal( + onPressed: onPressed, + style: baseStyle, + child: Text(text), + ); + // Alternative for secondary button: + // return OutlinedButton( + // onPressed: onPressed, + // style: baseStyle.copyWith( + // side: MaterialStateProperty.all( + // BorderSide(color: Theme.of(context).colorScheme.outline, width: 1.5), + // ), + // ), + // child: Text(text), + // ); + } + } } diff --git a/lib/utils/email.dart b/lib/utils/email.dart new file mode 100644 index 0000000..e9e315b --- /dev/null +++ b/lib/utils/email.dart @@ -0,0 +1,15 @@ +String? chechEmail(String email) { + final match = RegExp("[^a-zA-Z0-9@.]").firstMatch("email"); + if (match != null) return "Invalid character in email ${match[0]}"; + if (!email.contains("@")) return "Email should contain '@'"; + final parts = email.split("@"); + if (parts.length != 2) { + return "Email should contain 1 '@'"; + } + if (parts[0].length < 2) return "Email name too short"; + if (!parts[1].contains(".")) return "Invalid email domain(second part)"; + for (var element in parts[1].split(".")) { + if (element.isEmpty) return "Invalid domain component"; + } + return null; +} diff --git a/pubspec.lock b/pubspec.lock index c01733a..74f3395 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -113,6 +113,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.8" + equatable: + dependency: transitive + description: + name: equatable + sha256: "567c64b3cb4cf82397aac55f4f0cbd3ca20d77c6c03bedbc4ceaddc08904aef7" + url: "https://pub.dev" + source: hosted + version: "2.0.7" fake_async: dependency: transitive description: @@ -216,6 +224,22 @@ packages: url: "https://pub.dev" source: hosted version: "4.5.4" + intl_phone_number_input: + dependency: "direct main" + description: + name: intl_phone_number_input + sha256: "1c4328713a9503ab26a1fdbb6b00b4cada68c18aac922b35bedbc72eff1297c3" + url: "https://pub.dev" + source: hosted + version: "0.7.4" + js: + dependency: transitive + description: + name: js + sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3 + url: "https://pub.dev" + source: hosted + version: "0.6.7" json_annotation: dependency: transitive description: @@ -248,6 +272,30 @@ packages: url: "https://pub.dev" source: hosted version: "3.0.1" + libphonenumber_platform_interface: + dependency: transitive + description: + name: libphonenumber_platform_interface + sha256: f801f6c65523f56504b83f0890e6dad584ab3a7507dca65fec0eed640afea40f + url: "https://pub.dev" + source: hosted + version: "0.4.2" + libphonenumber_plugin: + dependency: transitive + description: + name: libphonenumber_plugin + sha256: c615021d9816fbda2b2587881019ed595ecdf54d999652d7e4cce0e1f026368c + url: "https://pub.dev" + source: hosted + version: "0.3.3" + libphonenumber_web: + dependency: transitive + description: + name: libphonenumber_web + sha256: "8186f420dbe97c3132283e52819daff1e55d60d6db46f7ea5ac42f42a28cc2ef" + url: "https://pub.dev" + source: hosted + version: "0.3.2" lints: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 85b781f..b0f6256 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -38,6 +38,7 @@ dependencies: flutter_launcher_icons: ^0.14.4 cached_network_image: ^3.4.1 http: ^1.4.0 + intl_phone_number_input: ^0.7.4 dev_dependencies: flutter_test: From a91b621584f9091d0f7dbe5340d0d76da6dab11c Mon Sep 17 00:00:00 2001 From: ken-morel Date: Tue, 24 Jun 2025 15:54:06 +0100 Subject: [PATCH 3/3] Added alot of models --- lib/animations/page/slide.dart | 2 + lib/backend.dart | 6 + lib/models.dart | 1 + lib/models/chatmessage.dart | 72 +++++++++++ lib/models/chatroom.dart | 62 +++++++++ lib/models/chatserver.dart | 27 ++++ lib/models/class.dart | 68 ++++++++++ lib/models/school.dart | 52 ++++++++ lib/models/school_user.dart | 70 +++++++++++ lib/models/session.dart | 8 +- lib/models/thread.dart | 54 ++++++++ lib/models/user.dart | 27 +++- lib/models/userrole.dart | 33 +++++ lib/pages/sign/signup/base.dart | 83 +++++++++--- lib/pages/sign/signup/extlinked.dart | 5 + lib/pages/sign/signup/form.dart | 19 ++- lib/pages/sign/signup/namepassword.dart | 6 - lib/pages/sign/signup/submit.dart | 72 ++++++++++- lib/pages/welcomepage.dart | 161 +++++++++++------------- lib/theme.dart | 15 ++- lib/widgets/imsg.dart | 36 ++++++ 21 files changed, 749 insertions(+), 130 deletions(-) create mode 100644 lib/models/chatmessage.dart create mode 100644 lib/models/chatroom.dart create mode 100644 lib/models/chatserver.dart create mode 100644 lib/models/class.dart create mode 100644 lib/models/school.dart create mode 100644 lib/models/school_user.dart create mode 100644 lib/models/thread.dart create mode 100644 lib/models/userrole.dart create mode 100644 lib/widgets/imsg.dart diff --git a/lib/animations/page/slide.dart b/lib/animations/page/slide.dart index fc93bf4..38f48f3 100644 --- a/lib/animations/page/slide.dart +++ b/lib/animations/page/slide.dart @@ -40,8 +40,10 @@ class SlidePageRoute extends PageRouteBuilder { beginOffset = Offset(-1, 0); break; } + final endOffset = Offset(-beginOffset.dx, -beginOffset.dy); final tween = Tween(begin: beginOffset, end: Offset.zero); + final previousTween = Tween(begin: Offset.zero, end: endOffset); final curvedAnimation = CurvedAnimation( parent: animation, curve: Curves.easeInOut, // Choose your curve diff --git a/lib/backend.dart b/lib/backend.dart index 2041810..e4760a9 100644 --- a/lib/backend.dart +++ b/lib/backend.dart @@ -36,3 +36,9 @@ Future> query( throw Exception('Failed to load data from backend(Invalid status code)'); } } + +class Status { + static const notFound = -5; + static const error = -1; + static const ok = 0; +} diff --git a/lib/models.dart b/lib/models.dart index 7253cdd..b9502e4 100644 --- a/lib/models.dart +++ b/lib/models.dart @@ -1,2 +1,3 @@ export 'models/session.dart'; export 'models/user.dart'; +export 'models/school.dart'; diff --git a/lib/models/chatmessage.dart b/lib/models/chatmessage.dart new file mode 100644 index 0000000..70b1c96 --- /dev/null +++ b/lib/models/chatmessage.dart @@ -0,0 +1,72 @@ +import 'dart:ffi'; + +import 'model.dart'; +import 'thread.dart'; +import 'user.dart'; +import 'session.dart'; +import 'package:ins/backend.dart'; + +class Chatmessage implements Model { + final int id; + final int threadId; + final int userId; + final String content; + final DateTime createdAt; + final DateTime? editedAt; + final Map reactions; + final int? repliesTo; + final int? repliesThread; + const Chatmessage({ + required this.id, + required this.threadId, + required this.userId, + required this.content, + required this.createdAt, + required this.editedAt, + required this.reactions, + required this.repliesTo, + required this.repliesThread, + }); + factory Chatmessage.fromJson(Map data) { + return Chatmessage( + id: data['id'] as int, + threadId: data['thread_id'] as int, + userId: data['user_id'] as int, + content: data['content'] as String, + createdAt: DateTime.parse(data['created_at'] as String), + editedAt: data['edited_at'] == null + ? null + : DateTime.parse(data['edited_at'] as String), + reactions: data['reactions'] as Map, + repliesTo: data['replies_to'] as int?, + repliesThread: data['replies_thread'] as int?, + ); + } + @override + Map toJson() { + return { + "id": id, + "thread_id": threadId, + "user_id": userId, + "content": content, + "created_at": createdAt.toIso8601String(), + "edited_at": editedAt?.toIso8601String(), + "reactions": reactions, + "replies_to": repliesTo, + "replies_thread": repliesThread, + }; + } + + Future getThread(Session? session) { + return Thread.getByID(session, threadId); + } + + Future getUser(Session? session) { + return User.getByID(session, userId); + } + + Future getRepliesThread(Session? session) async { + if (repliesThread == null) return null; + return await Thread.getByID(session, repliesThread!); + } +} diff --git a/lib/models/chatroom.dart b/lib/models/chatroom.dart new file mode 100644 index 0000000..4e92322 --- /dev/null +++ b/lib/models/chatroom.dart @@ -0,0 +1,62 @@ +import 'chatserver.dart'; + +import 'model.dart'; +import 'session.dart'; +import 'package:ins/backend.dart' as backend; +import 'thread.dart'; + +class Chatroom implements Model { + final int id; + final String title; + final String? description; + final int? serverId; + final int? threadId; + final DateTime createdAt; + const Chatroom({ + required this.id, + required this.title, + required this.description, + required this.serverId, + required this.threadId, + required this.createdAt, + }); + factory Chatroom.fromJson(Map data) { + return Chatroom( + id: data['id'] as int, + title: data['title'] as String, + description: data['description'] as String?, + serverId: data['server_id'] as int?, + threadId: data['thread_id'] as int?, + createdAt: DateTime.parse(data['created_at'] as String), + ); + } + @override + Map toJson() { + return { + "id": id, + "title": title, + "description": description, + "server_id": serverId, + "thread_id": threadId, + "created_at": createdAt.toIso8601String(), + }; + } + + static Future getById(Session? session, int id) async { + final data = await backend.query("v1/chatroom/get", {"id": id}, session); + if (data['status'] as int < 0) { + throw "Error getting chatroom $id: ${data['message'] as String}"; + } + return Chatroom.fromJson(data['room'] as Map); + } + + Future getServer(Session? session) async { + if (serverId == null) return null; + return Chatserver.getById(session, serverId!); + } + + Future getThread(Session? session) async { + if (threadId == null) return null; + return Thread.getByID(session, threadId!); + } +} diff --git a/lib/models/chatserver.dart b/lib/models/chatserver.dart new file mode 100644 index 0000000..e097307 --- /dev/null +++ b/lib/models/chatserver.dart @@ -0,0 +1,27 @@ +import 'model.dart'; +import 'session.dart'; +import 'package:ins/backend.dart' as backend; + +class Chatserver implements Model { + final int id; + final String fullname; + const Chatserver({required this.id, required this.fullname}); + @override + Map toJson() { + return {"id": id, "fullname": fullname}; + } + + factory Chatserver.fromJson(Map data) { + return Chatserver( + id: data['id'] as int, + fullname: data['schoolname'] as String, + ); + } + static Future getById(Session? session, int id) async { + final data = await backend.query("v1/chatserver/get", {"id": id}, session); + if (data['status'] as int < 0) { + throw "Error getting charserver $id: ${data['message'] as String}"; + } + return Chatserver.fromJson(data['server'] as Map); + } +} diff --git a/lib/models/class.dart b/lib/models/class.dart new file mode 100644 index 0000000..b4f11fc --- /dev/null +++ b/lib/models/class.dart @@ -0,0 +1,68 @@ +import 'package:ins/models.dart'; + +import 'school_user.dart'; +import 'package:ins/backend.dart' as backend; + +import 'model.dart'; + +class Class implements Model { + final int id; + final int schoolId; + final String fullname; + final int? chatserverId; + final String? description; + final DateTime createdAt; + const Class({ + required this.id, + required this.schoolId, + required this.fullname, + required this.chatserverId, + required this.description, + required this.createdAt, + }); + @override + Map toJson() { + return { + "id": id, + "school_id": schoolId, + "fullname": fullname, + "chatserver_id": chatserverId, + "description": description, + "created_at": createdAt, + }; + } + + factory Class.fromJson(Map data) { + return Class( + id: data['id'] as int, + schoolId: data['school_id'] as int, + fullname: data['schoolname'] as String, + chatserverId: data['schoolserver_id'] as int?, + description: data['description'] as String?, + createdAt: DateTime.parse(data['created_at'] as String), + ); + } + static Future getById(Session? session, int id) async { + final data = await backend.query("v1/class/get", {"id": id}, session); + if (data['status'] as int < 0) { + throw "Error fetching class with id $id: ${data['message'] as String}"; + } + return Class.fromJson(data['class']); + } + + Future> getMembers(Session? session) async { + final data = await backend.query("v1/class/getmembers", { + "class_id": id, + }, session); + if (data['status'] as int < 0) { + throw "Error getting members of '$fullname', ${data['message'] as String}"; + } + return (data["users"] as List>) + .map(SchoolUser.fromJson) + .toList(); + } + + Future getSchool(Session? session) { + return School.getByID(session, schoolId); + } +} diff --git a/lib/models/school.dart b/lib/models/school.dart new file mode 100644 index 0000000..509d6db --- /dev/null +++ b/lib/models/school.dart @@ -0,0 +1,52 @@ +import 'package:ins/models/school_user.dart'; + +import 'model.dart'; +import 'package:ins/backend.dart' as backend; +import 'session.dart'; + +class School implements Model { + final int id; + final String schoolname; + final String fullname; + final String? description; + final int? chatserverId; + const School({ + required this.id, + required this.schoolname, + required this.fullname, + required this.description, + required this.chatserverId, + }); + @override + Map toJson() { + return { + "id": id, + "schoolname": schoolname, + "fullname": fullname, + "description": description, + "chatserver_id": chatserverId, + }; + } + + factory School.fromJson(Map obj) { + return School( + id: obj["id"] as int, + schoolname: obj["schoolname"] as String, + fullname: obj["fullname"] as String, + description: obj["description"] as String?, + chatserverId: obj["chatserver_id"] as int?, + ); + } + + static Future getByID(Session? session, int id) async { + final data = await backend.query("school/get", {"id": id}, session); + if (data["status"] < 0) { + throw data["message"]; + } + return School.fromJson(data["school"] as Map); + } + + Future getUserById(Session? session, int userId) { + return SchoolUser.getFromIds(session, id, userId); + } +} diff --git a/lib/models/school_user.dart b/lib/models/school_user.dart new file mode 100644 index 0000000..074619c --- /dev/null +++ b/lib/models/school_user.dart @@ -0,0 +1,70 @@ +import 'package:ins/models/class.dart'; + +import 'school.dart'; +import 'user.dart'; +import 'session.dart'; +import 'userrole.dart'; +import 'model.dart'; +import 'package:ins/backend.dart' as backend; + +class SchoolUser implements Model { + final int schoolId; + final int userId; + final int? classId; + final UserRole role; + const SchoolUser({ + required this.schoolId, + required this.userId, + required this.classId, + required this.role, + }); + factory SchoolUser.fromJson(Map data) { + return SchoolUser( + schoolId: data["school_id"] as int, + userId: data["user_id"] as int, + classId: data["class_id"] as int?, + role: (data["role"] as String).toUserRole(), + ); + } + @override + Map toJson() { + return { + "school_id": schoolId, + "user_id": userId, + "class_id": classId, + "role": role.toJson(), + }; + } + + Future getSchool(Session? session) { + return School.getByID(session, schoolId); + } + + Future getUser(Session? session) { + return User.getByID(session, userId); + } + + static Future getFromIds( + Session? session, + int schoolId, + int userId, + ) async { + final data = await backend.query("v1/school/getuser", { + "user_id": userId, + "school_id": userId, + }, session); + if ((data["status"] as int) < 0) { + if ((data["status"] as int) == backend.Status.notFound) { + return null; + } else { + throw data["message"] as String; + } + } + return SchoolUser.fromJson(data["user"] as Map); + } + + Future getClass(Session? session) async { + if (classId == null) return null; + return await Class.getById(session, classId!); + } +} diff --git a/lib/models/session.dart b/lib/models/session.dart index 15de766..92c5fe0 100644 --- a/lib/models/session.dart +++ b/lib/models/session.dart @@ -1,12 +1,12 @@ import 'model.dart'; import 'user.dart'; -class Session extends Model { +class Session implements Model { final int id; final int userId; final DateTime createdAt; final String token; - Session({ + const Session({ required this.id, required this.userId, required this.createdAt, @@ -30,7 +30,7 @@ class Session extends Model { token: json['token'] as String, ); } - Future getUser() { - return User.getByID(userId); + Future getUser(Session? session) { + return User.getByID(session, userId); } } diff --git a/lib/models/thread.dart b/lib/models/thread.dart new file mode 100644 index 0000000..addb729 --- /dev/null +++ b/lib/models/thread.dart @@ -0,0 +1,54 @@ +import 'package:ins/models/chatmessage.dart'; + +import 'model.dart'; +import 'session.dart'; +import 'package:ins/backend.dart' as backend; + +class Thread implements Model { + final int id; + final int? parentThreadId; + const Thread({required this.id, required this.parentThreadId}); + factory Thread.fromJson(Map data) { + return Thread( + id: data['id'] as int, + parentThreadId: data['parent_thread_id'] as int?, + ); + } + @override + Map toJson() { + return {"id": id, "parent_thread_id": parentThreadId}; + } + + static Future getByID(Session? session, int id) async { + final data = await backend.query("v1/thread/get", { + "id": id.toString(), + }, session); + if (data["status"] < 0) { + throw Exception("Failed to get chat thread by ID: ${data["message"]}"); + } + return Thread.fromJson(data["thread"] as Map); + } + + Future getParent(Session? session) async { + if (parentThreadId == null) return null; + return await Thread.getByID(session, parentThreadId!); + } + + Future sendMessage( + Session? session, + String content, + int? repliesTo, + ) async { + final response = await backend.query("v1/message/send", { + "content": content, + "thread_id": id, + if (repliesTo != null) ...{"replies_to": repliesTo.toString()}, + }, session); + if (response['status'] as int < 0) { + throw Exception( + "Error sending message: ${response['message'] as String}", + ); + } + return Chatmessage.fromJson(response['message'] as Map); + } +} diff --git a/lib/models/user.dart b/lib/models/user.dart index 6ecfb3f..91b563a 100644 --- a/lib/models/user.dart +++ b/lib/models/user.dart @@ -1,14 +1,17 @@ +import 'package:ins/models/school_user.dart'; + import 'model.dart'; import 'package:ins/netimage.dart'; import 'package:ins/backend.dart' as backend; +import 'session.dart'; -class User extends Model { +class User implements Model { final int id; final String username; final String email; final String fullname; final NetImage? profile; - User({ + const User({ required this.id, required this.username, required this.email, @@ -37,10 +40,10 @@ class User extends Model { }; } - static Future getByID(int id) async { + static Future getByID(Session? session, int id) async { final data = await backend.query("v1/user/get", { "id": id.toString(), - }, null); + }, session); if (data["status"] < 0) { throw Exception("Failed to get user by ID: ${data["message"]}"); } @@ -56,6 +59,22 @@ class User extends Model { } return UsernameInfo.fromJson(data['info'] as Map); } + + Future getSchoolUserBySchoolID(Session? session, int schoolId) { + return SchoolUser.getFromIds(session, schoolId, id); + } + + Future> getSchoolUsers(Session? session) async { + final data = await backend.query("v1/user/getchoolusers", { + "user_id": id, + }, session); + if (data['status'] as int < 0) { + throw "Error getting school users ${data['message'] as String}"; + } + return (data["users"] as List>) + .map(SchoolUser.fromJson) + .toList(); + } } class UsernameInfo { diff --git a/lib/models/userrole.dart b/lib/models/userrole.dart new file mode 100644 index 0000000..39e862e --- /dev/null +++ b/lib/models/userrole.dart @@ -0,0 +1,33 @@ +enum UserRole { student, teacher, admin, staff } + +extension UserRoleExtension on UserRole { + String toJson() { + switch (this) { + case UserRole.student: + return "student"; + case UserRole.teacher: + return "teacher"; + case UserRole.admin: + return "admin"; + case UserRole.staff: + return "staff"; + } + } +} + +extension UserRoleStringExtension on String { + UserRole toUserRole() { + switch (toLowerCase()) { + case "student": + return UserRole.student; + case "teacher": + return UserRole.teacher; + case "admin": + return UserRole.admin; + case "staff": + return UserRole.staff; + default: + throw ArgumentError('Unknown role: $this'); + } + } +} diff --git a/lib/pages/sign/signup/base.dart b/lib/pages/sign/signup/base.dart index dd037c7..7b39b24 100644 --- a/lib/pages/sign/signup/base.dart +++ b/lib/pages/sign/signup/base.dart @@ -32,24 +32,28 @@ class SignupAssistantBase extends StatelessWidget { extendBodyBehindAppBar: true, // Allow body to extend behind AppBar body: Stack( children: [ - // 1. Background Image - Positioned.fill( - child: Image.asset( - "assets/icon/is-transparent-crop.png", // Ensure this path is correct - fit: BoxFit.cover, - errorBuilder: (context, error, stackTrace) { - // Fallback if image fails to load - return Container( - color: Theme.of(context).colorScheme.secondary, - ); - }, - ), + Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Padding( + padding: EdgeInsetsGeometry.all(100), + child: Image.asset( + "assets/icon/is-transparent-crop.png", // Ensure this path is correct + fit: BoxFit.cover, + errorBuilder: (context, error, stackTrace) { + // Fallback if image fails to load + return Container( + color: Theme.of(context).colorScheme.secondary, + ); + }, + ), + ), + ], ), - // 2. Blur Overlay Positioned.fill( child: BackdropFilter( - filter: ImageFilter.blur(sigmaX: 10, sigmaY: 10), + filter: ImageFilter.blur(sigmaX: 20, sigmaY: 15), child: Container( // Add a subtle tint to the blur for better text contrast if needed color: Colors.black.withOpacity(0.1), @@ -69,11 +73,7 @@ class SignupAssistantBase extends StatelessWidget { return Row( children: [ // Left pane (can be empty, show another graphic, or branding) - const Expanded( - flex: 1, // Adjust flex to change proportions - child: - SizedBox(), // This will show the blurred background - ), + Expanded(flex: 1, child: _buildLeftPane(context)), // Right pane (form content) Expanded( flex: 1, // Adjust flex @@ -137,4 +137,49 @@ class SignupAssistantBase extends StatelessWidget { ), ); } + + Widget _buildLeftPane(BuildContext context) { + return SizedBox( + height: 470, + width: 400, + child: Card( + margin: EdgeInsets.zero, + shape: RoundedSuperellipseBorder( + borderRadius: BorderRadius.only( + topRight: Radius.circular(5), + bottomRight: Radius.circular(5), + ), + ), + color: Theme.of(context).colorScheme.primaryContainer.withAlpha(200), + child: Padding( + padding: EdgeInsets.symmetric(vertical: 40, horizontal: 30), + child: Column( + children: [ + Center( + child: Column( + children: [ + Text( + "Welcome to IS", + style: Theme.of(context).textTheme.displayLarge, + ), + const SizedBox(height: 30), + Text( + " Empowering connections, empowering futures ", + textAlign: TextAlign.center, + style: Theme.of(context).textTheme.bodyLarge?.copyWith( + color: Theme.of( + context, + ).colorScheme.onSecondaryContainer.withAlpha(128), + fontStyle: FontStyle.italic, + ), + ), + ], + ), + ), + ], + ), + ), + ), + ); + } } diff --git a/lib/pages/sign/signup/extlinked.dart b/lib/pages/sign/signup/extlinked.dart index 4febbbd..b8db7c5 100644 --- a/lib/pages/sign/signup/extlinked.dart +++ b/lib/pages/sign/signup/extlinked.dart @@ -3,6 +3,8 @@ import 'form.dart'; import 'base.dart'; import 'package:ins/utils/email.dart'; import 'package:intl_phone_number_input/intl_phone_number_input.dart'; +import 'submit.dart'; +import 'package:ins/animations/page/slide.dart'; class ExtraLinkedPage extends StatefulWidget { final SignupForm form; @@ -140,5 +142,8 @@ class _ExtraLinkedPageState extends State { if (_phoneController.text.isNotEmpty) { widget.form.phone = _phoneController.text; } + Navigator.of( + context, + ).push(SlidePageRoute(child: SubmitingPage(form: widget.form))); } } diff --git a/lib/pages/sign/signup/form.dart b/lib/pages/sign/signup/form.dart index 59671f7..5a0db14 100644 --- a/lib/pages/sign/signup/form.dart +++ b/lib/pages/sign/signup/form.dart @@ -8,8 +8,23 @@ class SignupForm { String? fullname; String? password; String? phone; - Future submit() { - throw "Error signin you up"; + Future submit() async { + final result = await backend.query("signup", { + "username": username, + "email": email, + "fullname": fullname, + "password": password, + "phone": phone, + }, null); + if (result["status"] < 0) { + throw result["message"]; + } + return SignupFormSubmitResult( + session: models.Session.fromJson( + result["session"] as Map, + ), + user: models.User.fromJson(result["user"] as Map), + ); } } diff --git a/lib/pages/sign/signup/namepassword.dart b/lib/pages/sign/signup/namepassword.dart index 6636464..b975b56 100644 --- a/lib/pages/sign/signup/namepassword.dart +++ b/lib/pages/sign/signup/namepassword.dart @@ -131,9 +131,6 @@ class _NamePasswordPageState extends State { autofocus: true, keyboardType: TextInputType.visiblePassword, textCapitalization: TextCapitalization.none, - inputFormatters: [ - FilteringTextInputFormatter.deny(RegExp(r'\s')), - ], ), const SizedBox(height: 20), TextField( @@ -160,9 +157,6 @@ class _NamePasswordPageState extends State { autofocus: true, keyboardType: TextInputType.visiblePassword, textCapitalization: TextCapitalization.none, - inputFormatters: [ - FilteringTextInputFormatter.deny(RegExp(r'\s')), - ], ), ], ), diff --git a/lib/pages/sign/signup/submit.dart b/lib/pages/sign/signup/submit.dart index 66c18b9..5620bfd 100644 --- a/lib/pages/sign/signup/submit.dart +++ b/lib/pages/sign/signup/submit.dart @@ -1,10 +1,78 @@ import 'package:flutter/material.dart'; -import 'base.dart'; +import 'package:ins/widgets/imsg.dart'; import 'form.dart'; +import 'package:ins/widgets/loading.dart'; class SubmitingPage extends StatelessWidget { + final SignupForm form; + const SubmitingPage({super.key, required this.form}); @override Widget build(BuildContext context) { - return FutureBuilder(future: future, builder: builder) + return Scaffold( + appBar: AppBar(title: Text("Creating your account")), + body: FutureBuilder( + future: form.submit(), + builder: (context, snapshot) { + if (snapshot.hasError) { + return Center( + child: SizedBox( + width: 500, + child: IMsgWidget( + icon: Icon( + Icons.error, + size: 200, + color: Theme.of(context).colorScheme.error, + ), + message: Text( + snapshot.error!.toString(), + style: Theme.of(context).textTheme.headlineMedium, + textAlign: TextAlign.center, + ), + actions: FilledButton( + onPressed: () { + Navigator.of(context).pop(); + }, + child: Text("Retry"), + ), + ), + ), + ); + } else if (snapshot.hasData) { + final result = snapshot.data!; + result.saveInState(); + return Center( + child: SizedBox( + width: 400, + child: IMsgWidget( + icon: Icon( + Icons.check_circle, + size: 200, + color: Colors.greenAccent, + ), + message: Text("Account created succesfully"), + actions: OutlinedButton( + onPressed: () => _openDashboard(context), + child: const Text("Open dashboard"), + ), + ), + ), + ); + } else { + return LoadingWidget( + messages: [ + "Creating your account..", + "Adding your preferences..", + "Updating our database...", + "Putting in your contact information..", + "Looking for potential reelatives...", + "Generating your dashboard", + ], + ); + } + }, + ), + ); } + + void _openDashboard(BuildContext context) {} } diff --git a/lib/pages/welcomepage.dart b/lib/pages/welcomepage.dart index 68b91fb..49f4eef 100644 --- a/lib/pages/welcomepage.dart +++ b/lib/pages/welcomepage.dart @@ -17,89 +17,85 @@ class WelcomePage extends StatelessWidget { return Scaffold( appBar: AppBar( title: const Text('Welcome'), - // Optional: Make AppBar transparent for a more modern merged look - // backgroundColor: Colors.transparent, - // elevation: 0, + backgroundColor: Colors.transparent, + elevation: 0, ), body: SafeArea( - child: Padding( - padding: const EdgeInsets.symmetric(horizontal: 24.0, vertical: 16.0), - child: Column( - crossAxisAlignment: - CrossAxisAlignment.center, // Center children horizontally - children: [ - const Spacer(flex: 2), // Pushes content down from AppBar - - CircleAvatar( - // Ensure this asset path is correct and declared in pubspec.yaml - backgroundImage: const AssetImage('assets/icon/is.png'), - radius: avatarRadius, - backgroundColor: colorScheme - .secondaryContainer, // Fallback bg if image is transparent/fails - onBackgroundImageError: (exception, stackTrace) { - // You might want to log this or show a placeholder icon - print('Error loading CircleAvatar image: $exception'); - }, - ), - - const SizedBox(height: 32.0), - - Text( - "Welcome to Ins!", // Replace 'Ins' with your actual app name if different - style: textTheme.headlineMedium?.copyWith( - fontWeight: FontWeight.bold, - color: colorScheme.primary, + child: Center( + child: Padding( + padding: const EdgeInsets.symmetric( + horizontal: 24.0, + vertical: 16.0, + ), + child: Column( + crossAxisAlignment: + CrossAxisAlignment.center, // Center children horizontally + children: [ + const Spacer(flex: 2), // Pushes content down from AppBar + + CircleAvatar( + // Ensure this asset path is correct and declared in pubspec.yaml + backgroundImage: const AssetImage('assets/icon/is.png'), + radius: avatarRadius, + backgroundColor: colorScheme + .secondaryContainer, // Fallback bg if image is transparent/fails ), - textAlign: TextAlign.center, - ), - - const SizedBox(height: 12.0), - - Padding( - padding: const EdgeInsets.symmetric( - horizontal: 16.0, - ), // Extra padding for text block - child: Text( - "Connect an existing account or create a new one to embark on your journey with us.", - style: textTheme.bodyLarge?.copyWith( - color: colorScheme.onSurfaceVariant, + + const SizedBox(height: 32.0), + + Text( + "Welcome to IS!", + style: textTheme.headlineMedium?.copyWith( + fontWeight: FontWeight.bold, + color: colorScheme.primary, ), textAlign: TextAlign.center, ), - ), - - const Spacer( - flex: 3, - ), // Creates more space, pushing buttons towards the bottom - - _buildWelcomeButton( - context: context, - text: "Connect account", - onPressed: () { - // TODO: Implement connect account logic - // For example, navigate to a login page or OAuth flow - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text("Connect account tapped (Not implemented)"), + + const SizedBox(height: 12.0), + + Padding( + padding: const EdgeInsets.symmetric(horizontal: 16.0), + child: Text( + "Connect an existing account or create a new one to embark on your journey with us.", + style: textTheme.bodyLarge?.copyWith( + color: colorScheme.onSurfaceVariant, ), - ); - }, - isPrimary: false, // Visually less prominent - ), - - const SizedBox(height: 16.0), - - _buildWelcomeButton( - context: context, - text: "Create account", - onPressed: () { - launchSignupAssistant(context); - }, - isPrimary: true, // Primary call to action - ), - - const Spacer(flex: 1), // Adds some breathing room at the bottom - ], + textAlign: TextAlign.center, + ), + ), + + const Spacer(flex: 3), + + _buildWelcomeButton( + context: context, + text: "Connect account", + onPressed: () { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: Text( + "Connect account tapped (Not implemented)", + ), + ), + ); + }, + isPrimary: false, + ), + + const SizedBox(height: 16.0), + + _buildWelcomeButton( + context: context, + text: "Create account", + onPressed: () { + launchSignupAssistant(context); + }, + isPrimary: true, + ), + + const Spacer(flex: 1), // Adds some breathing room at the bottom + ], + ), ), ), ), @@ -122,9 +118,6 @@ class WelcomePage extends StatelessWidget { shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(24.0), // More rounded, modern feel ), - // Optional: If you want to ensure buttons have a minimum width - // This helps if one button has very short text and the other long text. - // Adjust the width (e.g., 200) as needed, or remove if not desired. minimumSize: Size(MediaQuery.of(context).size.width * 0.6, 52), ); @@ -140,16 +133,6 @@ class WelcomePage extends StatelessWidget { style: baseStyle, child: Text(text), ); - // Alternative for secondary button: - // return OutlinedButton( - // onPressed: onPressed, - // style: baseStyle.copyWith( - // side: MaterialStateProperty.all( - // BorderSide(color: Theme.of(context).colorScheme.outline, width: 1.5), - // ), - // ), - // child: Text(text), - // ); } } } diff --git a/lib/theme.dart b/lib/theme.dart index e59b3f2..148893c 100644 --- a/lib/theme.dart +++ b/lib/theme.dart @@ -220,10 +220,17 @@ ThemeData _buildHarbourHazeTheme() { style: ElevatedButton.styleFrom( backgroundColor: colorScheme.primary, foregroundColor: colorScheme.onPrimary, - textStyle: originalTextTheme.labelLarge, // Already has onPrimary color - padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 12), - shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)), elevation: 2, + padding: const EdgeInsets.symmetric(horizontal: 32, vertical: 14), + textStyle: originalTextTheme.labelLarge?.copyWith( + fontWeight: FontWeight.w600, // Slightly bolder + fontSize: 16, // Slightly larger font + ), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular( + 24.0, + ), // More rounded, modern feel + ), ), ), textButtonTheme: TextButtonThemeData( @@ -233,7 +240,7 @@ ThemeData _buildHarbourHazeTheme() { color: colorScheme.primary, fontWeight: FontWeight.w600, ), - shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)), + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(25)), ), ), outlinedButtonTheme: OutlinedButtonThemeData( diff --git a/lib/widgets/imsg.dart b/lib/widgets/imsg.dart new file mode 100644 index 0000000..381eea4 --- /dev/null +++ b/lib/widgets/imsg.dart @@ -0,0 +1,36 @@ +import 'package:flutter/material.dart'; + +class IMsgWidget extends StatelessWidget { + final Icon icon; + final Text message; + final Widget? actions; + const IMsgWidget({ + super.key, + required this.icon, + required this.message, + this.actions = const SizedBox.shrink(), + }); + @override + Widget build(BuildContext context) { + return SafeArea( + child: Padding( + padding: const EdgeInsetsGeometry.symmetric( + vertical: 10, + horizontal: 20, + ), + child: Column( + children: [ + SizedBox(height: 10), + icon, + SizedBox(height: 20), + message, + Spacer(), + if (actions != null) + SizedBox(width: double.infinity, child: actions!), + const SizedBox(height: 20), + ], + ), + ), + ); + } +}