Skip to content
Merged
89 changes: 71 additions & 18 deletions lib/core/app_theme.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';

class AppTheme {
// Color Definitions
// Original colors
static const Color grey = Color(0xFFCCCCCC);
static const Color mostroGreen = Color(0xFF8CC541);
static const Color dark1 = Color(0xFF1D212C);
Expand All @@ -14,7 +14,34 @@ class AppTheme {
static const Color red2 = Color(0xFFE45A5A);
static const Color green2 = Color(0xFF739C3D);

// Padding and Margin Constants
// New colors

// Colors for backgrounds
static const Color backgroundDark =
Color(0xFF171A23); // Main dark background
static const Color backgroundCard = Color(0xFF1E2230);
static const Color backgroundInput = Color(0xFF252A3A);
static const Color backgroundInactive = Color(0xFF2A3042);
static const Color backgroundNavBar = Color(0xFF1A1F2C);

// Colors for text
static const Color textPrimary = Colors.white;
static const Color textSecondary = Color(0xFFCCCCCC);
static const Color textInactive = Color(0xFF8A8D98);
static const Color textSubtle = Colors.white60;

// Colors for actions
static const Color buyColor = Color(0xFF8CC63F);
static const Color sellColor = Color(0xFFEA384C);
static const Color activeColor = Color(0xFF8CC541);

// Colors for states
static const Color statusSuccess = Color(0xFF8CC541);
static const Color statusWarning = Color(0xFFF3CA29);
static const Color statusError = Color(0xFFE45A5A);
static const Color statusActive = Color(0xFF8CC541);

// Padding and margin constants
static const EdgeInsets smallPadding = EdgeInsets.all(8.0);
static const EdgeInsets mediumPadding =
EdgeInsets.symmetric(horizontal: 16.0, vertical: 12.0);
Expand All @@ -29,7 +56,7 @@ class AppTheme {
return ThemeData(
hoverColor: dark1,
primaryColor: mostroGreen,
scaffoldBackgroundColor: dark1,
scaffoldBackgroundColor: backgroundDark,
appBarTheme: const AppBarTheme(
backgroundColor: Colors.transparent,
elevation: 0,
Expand All @@ -53,7 +80,7 @@ class AppTheme {
textTheme: _buildTextTheme(),
elevatedButtonTheme: ElevatedButtonThemeData(
style: ElevatedButton.styleFrom(
foregroundColor: AppTheme.cream1,
foregroundColor: cream1,
backgroundColor: mostroGreen,
textStyle: GoogleFonts.robotoCondensed(
fontWeight: FontWeight.w500,
Expand Down Expand Up @@ -103,10 +130,11 @@ class AppTheme {
size: 24.0,
),
listTileTheme: ListTileThemeData(
titleTextStyle: TextStyle(
color: grey,
fontFamily: GoogleFonts.robotoCondensed().fontFamily,
)),
titleTextStyle: TextStyle(
color: grey,
fontFamily: GoogleFonts.robotoCondensed().fontFamily,
),
),
);
}

Expand All @@ -115,47 +143,72 @@ class AppTheme {
const TextTheme(
displayLarge: TextStyle(
fontSize: 24.0,
), // For larger titles
),
displayMedium: TextStyle(
fontWeight: FontWeight.w700,
fontSize: 20.0,
), // For medium titles
),
displaySmall: TextStyle(
fontWeight: FontWeight.w700,
fontSize: 16.0,
), // For smaller titles
),
headlineMedium: TextStyle(
fontWeight: FontWeight.w700,
fontSize: 16.0,
), // For subtitles
),
headlineSmall: TextStyle(
fontWeight: FontWeight.w500,
fontSize: 14.0,
), // For secondary text
),
titleMedium: TextStyle(
fontWeight: FontWeight.w500,
fontSize: 16.0,
), // For form labels
),
titleLarge: TextStyle(
fontWeight: FontWeight.w500,
fontSize: 18.0,
), // For form labels
),
bodyLarge: TextStyle(
fontWeight: FontWeight.w400,
fontSize: 16.0,
), // For body text
),
bodyMedium: TextStyle(
fontWeight: FontWeight.w400,
fontSize: 14.0,
), // For smaller body text
),
labelLarge: TextStyle(
fontWeight: FontWeight.w500,
fontSize: 14.0,
), // For buttons and labels
),
),
).apply(
bodyColor: cream1,
displayColor: cream1,
);
}

// helpers for shadows
static List<BoxShadow> get cardShadow => [
BoxShadow(
color: Colors.black.withOpacity(0.7),
blurRadius: 15,
offset: const Offset(0, 5),
spreadRadius: -3,
),
BoxShadow(
color: Colors.white.withOpacity(0.07),
blurRadius: 1,
offset: const Offset(0, -1),
spreadRadius: 0,
),
];

static List<BoxShadow> get buttonShadow => [
BoxShadow(
color: Colors.black.withOpacity(0.4),
blurRadius: 6,
offset: const Offset(0, 3),
spreadRadius: -2,
),
];
}
79 changes: 65 additions & 14 deletions lib/data/models/rating.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,15 @@ class Rating {
final int lastRating;
final int maxRate;
final int minRate;
final int days;

const Rating({
required this.totalReviews,
required this.totalRating,
required this.lastRating,
required this.maxRate,
required this.minRate,
required this.days,
});

factory Rating.deserialized(String data) {
Expand All @@ -26,49 +28,98 @@ class Rating {

try {
final json = jsonDecode(data);
if (json is Map<String, dynamic>) {

if (json is List &&
json.length > 1 &&
json[0] == 'rating' &&
json[1] is Map) {
final Map<String, dynamic> ratingData = json[1] as Map<String, dynamic>;
return Rating(
totalReviews: _parseIntFromNestedJson(ratingData, 'total_reviews'),
totalRating: _parseDoubleFromNestedJson(ratingData, 'total_rating'),
days: _parseIntFromNestedJson(ratingData, 'days'),
lastRating: 0,
maxRate: 5,
minRate: 1,
);
Comment on lines +32 to +44
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Parse all available fields in the list-based JSON to avoid silent data loss

In the "rating" list format you parse only totalReviews, totalRating, and days while hard-coding lastRating, maxRate, and minRate.
If those keys are present in the payload they are ignored, causing the app to under-represent the seller’s reputation information.

-          days: _parseIntFromNestedJson(ratingData, 'days'),
-          lastRating: 0,
-          maxRate: 5,
-          minRate: 1,
+          days: _parseIntFromNestedJson(ratingData, 'days'),
+          lastRating: _parseIntFromNestedJson(
+            ratingData,
+            'last_rating',
+            defaultValue: 0,
+          ),
+          maxRate: _parseIntFromNestedJson(
+            ratingData,
+            'max_rate',
+            defaultValue: 5,
+          ),
+          minRate: _parseIntFromNestedJson(
+            ratingData,
+            'min_rate',
+            defaultValue: 1,
+          ),

This keeps the two code paths feature-parity and prevents accidental regressions if the server starts sending these fields.

📝 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
if (json is List &&
json.length > 1 &&
json[0] == 'rating' &&
json[1] is Map) {
final Map<String, dynamic> ratingData = json[1] as Map<String, dynamic>;
return Rating(
totalReviews: _parseIntFromNestedJson(ratingData, 'total_reviews'),
totalRating: _parseDoubleFromNestedJson(ratingData, 'total_rating'),
days: _parseIntFromNestedJson(ratingData, 'days'),
lastRating: 0,
maxRate: 5,
minRate: 1,
);
if (json is List &&
json.length > 1 &&
json[0] == 'rating' &&
json[1] is Map) {
final Map<String, dynamic> ratingData = json[1] as Map<String, dynamic>;
return Rating(
totalReviews: _parseIntFromNestedJson(ratingData, 'total_reviews'),
totalRating: _parseDoubleFromNestedJson(ratingData, 'total_rating'),
days: _parseIntFromNestedJson(ratingData, 'days'),
lastRating: _parseIntFromNestedJson(
ratingData,
'last_rating',
defaultValue: 0,
),
maxRate: _parseIntFromNestedJson(
ratingData,
'max_rate',
defaultValue: 5,
),
minRate: _parseIntFromNestedJson(
ratingData,
'min_rate',
defaultValue: 1,
),
);
}
🤖 Prompt for AI Agents
In lib/data/models/rating.dart between lines 32 and 44, the code parses only
totalReviews, totalRating, and days from the list-based JSON while hardcoding
lastRating, maxRate, and minRate. To fix this, update the parsing logic to
extract lastRating, maxRate, and minRate from the ratingData map if they exist,
using the appropriate parsing functions, instead of hardcoding their values.
This ensures all available fields are captured and prevents data loss or
under-representation of the seller's reputation.

} else if (json is Map<String, dynamic>) {
return Rating(
totalReviews: _parseInt(json, 'total_reviews'),
totalRating: _parseDouble(json, 'total_rating'),
lastRating: _parseInt(json, 'last_rating'),
maxRate: _parseInt(json, 'max_rate'),
minRate: _parseInt(json, 'min_rate'),
days: _parseInt(json, 'days', defaultValue: 0),
);
} else {
return Rating(
totalReviews: 0,
totalRating: (json[1]['total_reviews'] as int).toDouble(),
lastRating: 0,
maxRate: 0,
minRate: 0,
);
return Rating.empty();
}
} catch (e) {
return Rating.empty();
}
}

static int _parseInt(Map<String, dynamic> json, String field) {
static int _parseInt(Map<String, dynamic> json, String field,
{int defaultValue = 0}) {
final value = json[field];
if (value == null) return defaultValue;
if (value is int) return value;
if (value is double) return value.toInt();
throw FormatException('Invalid value for $field: $value');
try {
return int.parse(value.toString());
} catch (_) {
return defaultValue;
}
}

static double _parseDouble(Map<String, dynamic> json, String field) {
static int _parseIntFromNestedJson(Map<String, dynamic> json, String field,
{int defaultValue = 0}) {
final value = json[field];
if (value == null) return defaultValue;
if (value is int) return value;
if (value is double) return value.toInt();
try {
return int.parse(value.toString());
} catch (_) {
return defaultValue;
}
}

static double _parseDouble(Map<String, dynamic> json, String field,
{double defaultValue = 0.0}) {
final value = json[field];
if (value == null) return defaultValue;
if (value is double) return value;
if (value is int) return value.toDouble();
try {
return double.parse(value.toString());
} catch (_) {
return defaultValue;
}
}

static double _parseDoubleFromNestedJson(
Map<String, dynamic> json, String field,
{double defaultValue = 0.0}) {
final value = json[field];
if (value == null) return defaultValue;
if (value is double) return value;
if (value is int) return value.toDouble();
throw FormatException('Invalid value for $field: $value');
try {
return double.parse(value.toString());
} catch (_) {
return defaultValue;
}
}

static Rating empty() {
return const Rating(
totalReviews: 0,
totalRating: 0.0,
lastRating: 0,
maxRate: 0,
minRate: 0,
maxRate: 5,
minRate: 1,
days: 0,
);
}
}
Loading
Loading