feat: Add recommended tasks for next sprint to improve coding practices in mobile applications
This commit is contained in:
9
apps/mobile/NEXT_SPRINT_TASKS.md
Normal file
9
apps/mobile/NEXT_SPRINT_TASKS.md
Normal file
@@ -0,0 +1,9 @@
|
||||
## Recommended tasks for the next sprint
|
||||
|
||||
|
||||
* In the mobile applications, since the structure is now finalized (at least for the existing features), we need to **strictly follow best practices while coding**:
|
||||
|
||||
* Break down large widgets into **smaller, reusable widgets**
|
||||
* Add **doc comments** where necessary to improve readability and maintainability
|
||||
* **Remove overly complicated or unnecessary logic** introduced by AI and simplify where possible
|
||||
* **Adhere to the design system** and remove all **hard-coded colors and typography**, using shared tokens instead
|
||||
@@ -12,6 +12,7 @@ import 'package:client_hubs/client_hubs.dart' as client_hubs;
|
||||
import 'package:client_create_order/client_create_order.dart'
|
||||
as client_create_order;
|
||||
import 'package:firebase_core/firebase_core.dart';
|
||||
import 'package:krow_core/core.dart';
|
||||
|
||||
void main() async {
|
||||
WidgetsFlutterBinding.ensureInitialized();
|
||||
@@ -54,34 +55,38 @@ class AppWidget extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return BlocProvider<core_localization.LocaleBloc>(
|
||||
create: (BuildContext context) =>
|
||||
Modular.get<core_localization.LocaleBloc>(),
|
||||
child:
|
||||
BlocBuilder<
|
||||
core_localization.LocaleBloc,
|
||||
core_localization.LocaleState
|
||||
>(
|
||||
builder:
|
||||
(BuildContext context, core_localization.LocaleState state) {
|
||||
return core_localization.TranslationProvider(
|
||||
child: MaterialApp.router(
|
||||
debugShowCheckedModeBanner: false,
|
||||
title: "Krow Client",
|
||||
theme: UiTheme.light,
|
||||
routerConfig: Modular.routerConfig,
|
||||
locale: state.locale,
|
||||
supportedLocales: state.supportedLocales,
|
||||
localizationsDelegates:
|
||||
const <LocalizationsDelegate<dynamic>>[
|
||||
GlobalMaterialLocalizations.delegate,
|
||||
GlobalWidgetsLocalizations.delegate,
|
||||
GlobalCupertinoLocalizations.delegate,
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
return WebMobileFrame(
|
||||
appName: 'KROW Client\nApplication',
|
||||
logo: Image.asset('assets/logo.png'),
|
||||
child: BlocProvider<core_localization.LocaleBloc>(
|
||||
create: (BuildContext context) =>
|
||||
Modular.get<core_localization.LocaleBloc>(),
|
||||
child:
|
||||
BlocBuilder<
|
||||
core_localization.LocaleBloc,
|
||||
core_localization.LocaleState
|
||||
>(
|
||||
builder:
|
||||
(BuildContext context, core_localization.LocaleState state) {
|
||||
return core_localization.TranslationProvider(
|
||||
child: MaterialApp.router(
|
||||
debugShowCheckedModeBanner: false,
|
||||
title: "Krow Client",
|
||||
theme: UiTheme.light,
|
||||
routerConfig: Modular.routerConfig,
|
||||
locale: state.locale,
|
||||
supportedLocales: state.supportedLocales,
|
||||
localizationsDelegates:
|
||||
const <LocalizationsDelegate<dynamic>>[
|
||||
GlobalMaterialLocalizations.delegate,
|
||||
GlobalWidgetsLocalizations.delegate,
|
||||
GlobalCupertinoLocalizations.delegate,
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import 'package:flutter_modular/flutter_modular.dart';
|
||||
import 'package:staff_authentication/staff_authentication.dart'
|
||||
as staff_authentication;
|
||||
import 'package:staff_main/staff_main.dart' as staff_main;
|
||||
import 'package:krow_core/core.dart';
|
||||
|
||||
void main() async {
|
||||
WidgetsFlutterBinding.ensureInitialized();
|
||||
@@ -34,33 +35,37 @@ class AppWidget extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return BlocProvider<core_localization.LocaleBloc>(
|
||||
create: (BuildContext context) =>
|
||||
Modular.get<core_localization.LocaleBloc>(),
|
||||
child:
|
||||
BlocBuilder<
|
||||
core_localization.LocaleBloc,
|
||||
core_localization.LocaleState
|
||||
>(
|
||||
builder:
|
||||
(BuildContext context, core_localization.LocaleState state) {
|
||||
return core_localization.TranslationProvider(
|
||||
child: MaterialApp.router(
|
||||
title: "KROW Staff",
|
||||
theme: UiTheme.light,
|
||||
routerConfig: Modular.routerConfig,
|
||||
locale: state.locale,
|
||||
supportedLocales: state.supportedLocales,
|
||||
localizationsDelegates:
|
||||
const <LocalizationsDelegate<dynamic>>[
|
||||
GlobalMaterialLocalizations.delegate,
|
||||
GlobalWidgetsLocalizations.delegate,
|
||||
GlobalCupertinoLocalizations.delegate,
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
return WebMobileFrame(
|
||||
appName: 'KROW Staff\nApplication',
|
||||
logo: Image.asset('assets/logo.png'),
|
||||
child: BlocProvider<core_localization.LocaleBloc>(
|
||||
create: (BuildContext context) =>
|
||||
Modular.get<core_localization.LocaleBloc>(),
|
||||
child:
|
||||
BlocBuilder<
|
||||
core_localization.LocaleBloc,
|
||||
core_localization.LocaleState
|
||||
>(
|
||||
builder:
|
||||
(BuildContext context, core_localization.LocaleState state) {
|
||||
return core_localization.TranslationProvider(
|
||||
child: MaterialApp.router(
|
||||
title: "KROW Staff",
|
||||
theme: UiTheme.light,
|
||||
routerConfig: Modular.routerConfig,
|
||||
locale: state.locale,
|
||||
supportedLocales: state.supportedLocales,
|
||||
localizationsDelegates:
|
||||
const <LocalizationsDelegate<dynamic>>[
|
||||
GlobalMaterialLocalizations.delegate,
|
||||
GlobalWidgetsLocalizations.delegate,
|
||||
GlobalCupertinoLocalizations.delegate,
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,3 +3,4 @@ library core;
|
||||
export 'src/domain/arguments/usecase_argument.dart';
|
||||
export 'src/domain/usecases/usecase.dart';
|
||||
export 'src/utils/date_time_utils.dart';
|
||||
export 'src/presentation/widgets/web_mobile_frame.dart';
|
||||
|
||||
@@ -0,0 +1,249 @@
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
/// A wrapper widget that renders the application inside an iPhone-like frame
|
||||
/// specifically for Flutter Web. On other platforms, it simply returns the child.
|
||||
class WebMobileFrame extends StatelessWidget {
|
||||
final Widget child;
|
||||
final Widget logo;
|
||||
final String appName;
|
||||
|
||||
const WebMobileFrame({
|
||||
super.key,
|
||||
required this.child,
|
||||
required this.logo,
|
||||
required this.appName,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
if (!kIsWeb) return child;
|
||||
|
||||
return MaterialApp(
|
||||
debugShowCheckedModeBanner: false,
|
||||
theme: ThemeData.dark(),
|
||||
home: _WebFrameContent(
|
||||
logo: logo,
|
||||
appName: appName,
|
||||
child: child,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _WebFrameContent extends StatefulWidget {
|
||||
final Widget child;
|
||||
final Widget logo;
|
||||
final String appName;
|
||||
|
||||
const _WebFrameContent({
|
||||
required this.child,
|
||||
required this.logo,
|
||||
required this.appName,
|
||||
});
|
||||
|
||||
@override
|
||||
State<_WebFrameContent> createState() => _WebFrameContentState();
|
||||
}
|
||||
|
||||
class _WebFrameContentState extends State<_WebFrameContent> {
|
||||
// ignore: unused_field
|
||||
Offset _cursorPosition = Offset.zero;
|
||||
// ignore: unused_field
|
||||
bool _isHovering = false;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
// iPhone 14 Pro Max-ish dimensions (scaled for frame look)
|
||||
const double frameWidth = 390 * 1.2;
|
||||
const double frameHeight = 844 * 1.3;
|
||||
const double borderRadius = 54.0;
|
||||
const double borderThickness = 12.0;
|
||||
|
||||
return Scaffold(
|
||||
backgroundColor: const Color(0xFF121212),
|
||||
body: MouseRegion(
|
||||
cursor: SystemMouseCursors.none,
|
||||
onHover: (event) {
|
||||
setState(() {
|
||||
_cursorPosition = event.position;
|
||||
_isHovering = true;
|
||||
});
|
||||
},
|
||||
onExit: (_) => setState(() => _isHovering = false),
|
||||
child: Stack(
|
||||
children: [
|
||||
// Logo and Title on the left (Web only)
|
||||
Positioned(
|
||||
left: 60,
|
||||
top: 0,
|
||||
bottom: 0,
|
||||
child: Center(
|
||||
child: Opacity(
|
||||
opacity: 0.5,
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
SizedBox(
|
||||
width: 140,
|
||||
child: widget.logo,
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
Text(
|
||||
widget.appName,
|
||||
textAlign: TextAlign.left,
|
||||
style: const TextStyle(
|
||||
color: Colors.white,
|
||||
fontSize: 28,
|
||||
fontWeight: FontWeight.bold,
|
||||
letterSpacing: -0.5,
|
||||
fontFamily: 'Instrument Sans', // Fallback if available or system
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
Container(
|
||||
height: 2,
|
||||
width: 40,
|
||||
color: Colors.white.withOpacity(0.3),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
// Frame and Content
|
||||
Center(
|
||||
child: LayoutBuilder(
|
||||
builder: (context, constraints) {
|
||||
// Scale down if screen is too small
|
||||
double scaleX = constraints.maxWidth / (frameWidth + 80);
|
||||
double scaleY = constraints.maxHeight / (frameHeight + 80);
|
||||
double scale = (scaleX < 1 || scaleY < 1)
|
||||
? (scaleX < scaleY ? scaleX : scaleY)
|
||||
: 1.0;
|
||||
|
||||
return Transform.scale(
|
||||
scale: scale,
|
||||
child: Container(
|
||||
width: frameWidth,
|
||||
height: frameHeight,
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.black,
|
||||
borderRadius: BorderRadius.circular(borderRadius),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.black.withOpacity(0.6),
|
||||
blurRadius: 40,
|
||||
spreadRadius: 10,
|
||||
),
|
||||
],
|
||||
border: Border.all(
|
||||
color: const Color(0xFF2C2C2C),
|
||||
width: borderThickness,
|
||||
),
|
||||
),
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.circular(
|
||||
borderRadius - borderThickness,
|
||||
),
|
||||
child: Stack(
|
||||
children: [
|
||||
// The actual app + status bar
|
||||
Column(
|
||||
children: [
|
||||
// Mock iOS Status Bar
|
||||
Container(
|
||||
height: 48,
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 24,
|
||||
),
|
||||
decoration: const BoxDecoration(
|
||||
color: Color(0xFFF9F6EE),
|
||||
border: Border(
|
||||
bottom: BorderSide(
|
||||
color: Color(0xFFEEEEEE),
|
||||
width: 0.5,
|
||||
),
|
||||
),
|
||||
),
|
||||
child: Row(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
// Time side
|
||||
const SizedBox(
|
||||
width: 80,
|
||||
child: Text(
|
||||
'9:41 PM',
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
color: Colors.black54,
|
||||
fontWeight: FontWeight.w700,
|
||||
fontSize: 14,
|
||||
letterSpacing: -0.2,
|
||||
),
|
||||
),
|
||||
),
|
||||
// Status Icons side
|
||||
const SizedBox(
|
||||
width: 80,
|
||||
child: Row(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.end,
|
||||
spacing: 12,
|
||||
children: [
|
||||
Icon(
|
||||
Icons.signal_cellular_alt,
|
||||
size: 14,
|
||||
color: Colors.black54,
|
||||
),
|
||||
Icon(
|
||||
Icons.wifi,
|
||||
size: 14,
|
||||
color: Colors.black54,
|
||||
),
|
||||
Icon(
|
||||
Icons.battery_full,
|
||||
size: 14,
|
||||
color: Colors.black54,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
// The main app content content
|
||||
Expanded(child: widget.child),
|
||||
],
|
||||
),
|
||||
|
||||
// Dynamic Island / Notch Mockup
|
||||
Align(
|
||||
alignment: Alignment.topCenter,
|
||||
child: Container(
|
||||
width: 120,
|
||||
height: 35,
|
||||
margin: const EdgeInsets.only(top: 10),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.black,
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user