refactor: Update package and bundle identifiers to reflect new naming convention

This commit is contained in:
Vaibhav Surve 2025-10-31 15:22:05 +05:30
parent bc9fc4d6f1
commit 6568dc70c8
10 changed files with 323 additions and 169 deletions

View File

@ -15,7 +15,7 @@ if (keystorePropertiesFile.exists()) {
android {
// Define the namespace for your Android application
namespace = "com.onfieldwork.marcoaiot"
namespace = "com.marcoonfieldwork.aiot"
// Set the compile SDK version based on Flutter's configuration
compileSdk = flutter.compileSdkVersion
// Set the NDK version based on Flutter's configuration

View File

@ -1,4 +1,4 @@
package com.onfieldwork.marcoaiot
package com.marcoonfieldwork.aiot
import io.flutter.embedding.android.FlutterActivity

View File

@ -368,7 +368,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = com.onfieldwork.marcoaiot;
PRODUCT_BUNDLE_IDENTIFIER = com.marcoonfieldwork.aiot;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_VERSION = 5.0;
@ -384,7 +384,7 @@
CURRENT_PROJECT_VERSION = 1;
GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.onfieldwork.marcoaiot.RunnerTests;
PRODUCT_BUNDLE_IDENTIFIER = com.marcoonfieldwork.aiot.RunnerTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
@ -401,7 +401,7 @@
CURRENT_PROJECT_VERSION = 1;
GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.onfieldwork.marcoaiot.RunnerTests;
PRODUCT_BUNDLE_IDENTIFIER = com.marcoonfieldwork.aiot.RunnerTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
@ -416,7 +416,7 @@
CURRENT_PROJECT_VERSION = 1;
GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.onfieldwork.marcoaiot.RunnerTests;
PRODUCT_BUNDLE_IDENTIFIER = com.marcoonfieldwork.aiot.RunnerTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
@ -547,7 +547,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = com.onfieldwork.marcoaiot;
PRODUCT_BUNDLE_IDENTIFIER = com.marcoonfieldwork.aiot;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
@ -569,7 +569,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = com.onfieldwork.marcoaiot;
PRODUCT_BUNDLE_IDENTIFIER = com.marcoonfieldwork.aiot;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_VERSION = 5.0;

View File

@ -12,7 +12,7 @@ import 'package:marco/helpers/widgets/my_text.dart';
import 'package:marco/helpers/widgets/dashbaord/attendance_overview_chart.dart';
import 'package:marco/helpers/widgets/dashbaord/expense_by_status_widget.dart';
import 'package:marco/view/layouts/layout.dart';
import 'package:marco/helpers/widgets/dashbaord/expense_breakdown_chart.dart';
// import 'package:marco/helpers/widgets/dashbaord/expense_breakdown_chart.dart';
class DashboardScreen extends StatefulWidget {
const DashboardScreen({super.key});
@ -61,8 +61,8 @@ class _DashboardScreenState extends State<DashboardScreen> with UIMixin {
ExpenseByStatusWidget(controller: dashboardController),
MySpacing.height(24),
// Expense Type Report Chart
ExpenseTypeReportChart(),
// // Expense Type Report Chart
// ExpenseTypeReportChart(),
],
),
),

View File

@ -11,7 +11,6 @@ import 'package:marco/helpers/widgets/my_refresh_indicator.dart';
import 'package:marco/model/employees/add_employee_bottom_sheet.dart';
import 'package:marco/helpers/utils/mixins/ui_mixin.dart';
class EmployeeDetailPage extends StatefulWidget {
final String employeeId;
final bool fromProfile;
@ -30,7 +29,6 @@ class _EmployeeDetailPageState extends State<EmployeeDetailPage> with UIMixin {
final EmployeesScreenController controller =
Get.put(EmployeesScreenController());
@override
void initState() {
super.initState();
@ -61,124 +59,112 @@ class _EmployeeDetailPageState extends State<EmployeeDetailPage> with UIMixin {
}
}
Widget _buildLabelValueRow(String label, String value,
{bool isMultiLine = false}) {
final lowerLabel = label.toLowerCase();
final isEmail = lowerLabel == 'email';
final isPhone =
lowerLabel == 'phone number' || lowerLabel == 'emergency phone number';
void handleTap() {
if (value == 'NA') return;
if (isEmail) {
LauncherUtils.launchEmail(value);
} else if (isPhone) {
LauncherUtils.launchPhone(value);
}
}
void handleLongPress() {
if (value == 'NA') return;
LauncherUtils.copyToClipboard(value, typeLabel: label);
}
final valueWidget = GestureDetector(
onTap: (isEmail || isPhone) ? handleTap : null,
onLongPress: (isEmail || isPhone) ? handleLongPress : null,
child: Text(
value,
style: TextStyle(
fontWeight: FontWeight.normal,
color: (isEmail || isPhone) ? contentTheme.primary : Colors.black54,
fontSize: 14,
decoration: (isEmail || isPhone)
? TextDecoration.underline
: TextDecoration.none,
),
),
);
return Column(
Widget _buildDetailRow({
required IconData icon,
required String label,
required String value,
VoidCallback? onTap,
VoidCallback? onLongPress,
bool isActionable = false,
}) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 12),
child: InkWell(
onTap: isActionable && value != 'NA' ? onTap : null,
onLongPress: isActionable && value != 'NA' ? onLongPress : null,
borderRadius: BorderRadius.circular(5),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (isMultiLine) ...[
Text(
label,
style: const TextStyle(
fontWeight: FontWeight.bold,
color: Colors.black87,
fontSize: 14,
Container(
padding: const EdgeInsets.all(8),
decoration: BoxDecoration(
color: contentTheme.primary.withOpacity(0.1),
borderRadius: BorderRadius.circular(5),
),
child: Icon(
icon,
size: 20,
color: contentTheme.primary,
),
),
MySpacing.height(4),
valueWidget,
] else
GestureDetector(
onTap: (isEmail || isPhone) ? handleTap : null,
onLongPress: (isEmail || isPhone) ? handleLongPress : null,
child: RichText(
text: TextSpan(
text: "$label: ",
style: const TextStyle(
fontWeight: FontWeight.bold,
color: Colors.black87,
fontSize: 14,
),
children: [
TextSpan(
text: value,
style: TextStyle(
fontWeight: FontWeight.normal,
color:
(isEmail || isPhone) ? Colors.indigo : Colors.black54,
decoration: (isEmail || isPhone)
? TextDecoration.underline
: TextDecoration.none,
),
),
],
),
),
),
MySpacing.height(10),
Divider(color: Colors.grey[300], height: 1),
MySpacing.height(10),
],
);
}
Widget _buildInfoCard(employee) {
return Card(
elevation: 3,
shadowColor: Colors.black12,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(5)),
child: Padding(
padding: const EdgeInsets.fromLTRB(12, 16, 12, 16),
MySpacing.width(16),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
MySpacing.height(12),
_buildLabelValueRow('Email', _getDisplayValue(employee.email)),
_buildLabelValueRow(
'Phone Number', _getDisplayValue(employee.phoneNumber)),
_buildLabelValueRow('Emergency Contact Person',
_getDisplayValue(employee.emergencyContactPerson)),
_buildLabelValueRow('Emergency Phone Number',
_getDisplayValue(employee.emergencyPhoneNumber)),
_buildLabelValueRow('Gender', _getDisplayValue(employee.gender)),
_buildLabelValueRow('Birth Date', _formatDate(employee.birthDate)),
_buildLabelValueRow(
'Joining Date', _formatDate(employee.joiningDate)),
_buildLabelValueRow(
'Current Address',
_getDisplayValue(employee.currentAddress),
isMultiLine: true,
Text(
label,
style: TextStyle(
fontSize: 12,
color: Colors.grey[600],
fontWeight: FontWeight.w500,
),
_buildLabelValueRow(
'Permanent Address',
_getDisplayValue(employee.permanentAddress),
isMultiLine: true,
),
MySpacing.height(4),
Text(
value,
style: TextStyle(
fontSize: 15,
color: isActionable && value != 'NA'
? contentTheme.primary
: Colors.black87,
fontWeight: FontWeight.w500,
decoration: isActionable && value != 'NA'
? TextDecoration.underline
: TextDecoration.none,
),
),
],
),
),
if (isActionable && value != 'NA')
Icon(
Icons.chevron_right,
color: Colors.grey[400],
size: 20,
),
],
),
),
);
}
Widget _buildSectionCard({
required String title,
required IconData titleIcon,
required List<Widget> children,
}) {
return Card(
elevation: 2,
shadowColor: Colors.black12,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(5)),
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Icon(
titleIcon,
size: 20,
color: contentTheme.primary,
),
MySpacing.width(8),
Text(
title,
style: const TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
color: Colors.black87,
),
),
],
),
MySpacing.height(8),
const Divider(),
...children,
],
),
),
@ -224,14 +210,23 @@ class _EmployeeDetailPageState extends State<EmployeeDetailPage> with UIMixin {
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Row(
// Header Section
Card(
elevation: 2,
shadowColor: Colors.black12,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(5),
),
child: Padding(
padding: const EdgeInsets.all(16),
child: Row(
children: [
Avatar(
firstName: employee.firstName,
lastName: employee.lastName,
size: 45,
),
MySpacing.width(12),
MySpacing.width(16),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
@ -249,11 +244,11 @@ class _EmployeeDetailPageState extends State<EmployeeDetailPage> with UIMixin {
),
),
IconButton(
icon:
Icon(Icons.edit, size: 24, color: contentTheme.primary),
icon: Icon(Icons.edit,
size: 24, color: contentTheme.primary),
onPressed: () async {
final result =
await showModalBottomSheet<Map<String, dynamic>>(
final result = await showModalBottomSheet<
Map<String, dynamic>>(
context: context,
isScrollControlled: true,
backgroundColor: Colors.transparent,
@ -275,14 +270,159 @@ class _EmployeeDetailPageState extends State<EmployeeDetailPage> with UIMixin {
);
if (result != null) {
controller.fetchEmployeeDetails(widget.employeeId);
controller
.fetchEmployeeDetails(widget.employeeId);
}
},
),
],
),
MySpacing.height(14),
_buildInfoCard(employee),
),
),
MySpacing.height(16),
// Contact Information Section
_buildSectionCard(
title: 'Contact Information',
titleIcon: Icons.contact_phone,
children: [
_buildDetailRow(
icon: Icons.email_outlined,
label: 'Email',
value: _getDisplayValue(employee.email),
isActionable: true,
onTap: () {
if (employee.email != null &&
employee.email.toString().trim().isNotEmpty) {
LauncherUtils.launchEmail(employee.email!);
}
},
onLongPress: () {
if (employee.email != null &&
employee.email.toString().trim().isNotEmpty) {
LauncherUtils.copyToClipboard(employee.email!,
typeLabel: 'Email');
}
},
),
_buildDetailRow(
icon: Icons.phone_outlined,
label: 'Phone Number',
value: _getDisplayValue(employee.phoneNumber),
isActionable: true,
onTap: () {
if (employee.phoneNumber != null &&
employee.phoneNumber
.toString()
.trim()
.isNotEmpty) {
LauncherUtils.launchPhone(employee.phoneNumber!);
}
},
onLongPress: () {
if (employee.phoneNumber != null &&
employee.phoneNumber
.toString()
.trim()
.isNotEmpty) {
LauncherUtils.copyToClipboard(employee.phoneNumber!,
typeLabel: 'Phone Number');
}
},
),
],
),
MySpacing.height(16),
// Emergency Contact Section
_buildSectionCard(
title: 'Emergency Contact',
titleIcon: Icons.emergency,
children: [
_buildDetailRow(
icon: Icons.person_outline,
label: 'Contact Person',
value:
_getDisplayValue(employee.emergencyContactPerson),
isActionable: false,
),
_buildDetailRow(
icon: Icons.phone_in_talk_outlined,
label: 'Emergency Phone',
value: _getDisplayValue(employee.emergencyPhoneNumber),
isActionable: true,
onTap: () {
if (employee.emergencyPhoneNumber != null &&
employee.emergencyPhoneNumber
.toString()
.trim()
.isNotEmpty) {
LauncherUtils.launchPhone(
employee.emergencyPhoneNumber!);
}
},
onLongPress: () {
if (employee.emergencyPhoneNumber != null &&
employee.emergencyPhoneNumber
.toString()
.trim()
.isNotEmpty) {
LauncherUtils.copyToClipboard(
employee.emergencyPhoneNumber!,
typeLabel: 'Emergency Phone');
}
},
),
],
),
MySpacing.height(16),
// Personal Information Section
_buildSectionCard(
title: 'Personal Information',
titleIcon: Icons.person,
children: [
_buildDetailRow(
icon: Icons.wc_outlined,
label: 'Gender',
value: _getDisplayValue(employee.gender),
isActionable: false,
),
_buildDetailRow(
icon: Icons.cake_outlined,
label: 'Birth Date',
value: _formatDate(employee.birthDate),
isActionable: false,
),
_buildDetailRow(
icon: Icons.work_outline,
label: 'Joining Date',
value: _formatDate(employee.joiningDate),
isActionable: false,
),
],
),
MySpacing.height(16),
// Address Information Section
_buildSectionCard(
title: 'Address Information',
titleIcon: Icons.location_on,
children: [
_buildDetailRow(
icon: Icons.home_outlined,
label: 'Current Address',
value: _getDisplayValue(employee.currentAddress),
isActionable: false,
),
_buildDetailRow(
icon: Icons.home_work_outlined,
label: 'Permanent Address',
value: _getDisplayValue(employee.permanentAddress),
isActionable: false,
),
],
),
],
),
),

View File

@ -11,6 +11,8 @@ import 'package:marco/model/employees/employee_info.dart';
import 'package:marco/controller/auth/mpin_controller.dart';
import 'package:marco/view/employees/employee_profile_screen.dart';
import 'package:marco/helpers/theme/theme_editor_widget.dart';
import 'package:marco/view/faq/faq_screen.dart';
import 'package:marco/view/support/support_screen.dart';
class UserProfileBar extends StatefulWidget {
@ -122,6 +124,7 @@ class _UserProfileBarState extends State<UserProfileBar>
),
);
}
Widget _userProfileSection(bool condensed) {
final padding = MySpacing.fromLTRB(
condensed ? 16 : 26,
@ -206,6 +209,17 @@ class _UserProfileBarState extends State<UserProfileBar>
_menuItemRow(
icon: LucideIcons.badge_alert,
label: 'Support',
onTap: () {
Get.to(() => SupportScreen());
},
),
SizedBox(height: spacingHeight),
_menuItemRow(
icon: LucideIcons.badge_help,
label: 'FAQ',
onTap: () {
Get.to(() => FAQScreen());
},
),
SizedBox(height: spacingHeight),
_menuItemRow(

View File

@ -16,10 +16,10 @@ class _SupportScreenState extends State<SupportScreen> with UIMixin {
final List<Map<String, dynamic>> contacts = [
{
"type": "email",
"label": "info@marcoaiot.com",
"label": "support@onfieldwork.com",
"subLabel": "Email us your queries",
"icon": LucideIcons.mail,
"action": "mailto:info@marcoaiot.com?subject=Support Request"
"action": "mailto:support@onfieldwork.com?subject=Support Request"
},
{
"type": "phone",

View File

@ -7,7 +7,7 @@ project(runner LANGUAGES CXX)
set(BINARY_NAME "marco")
# The unique GTK application identifier for this application. See:
# https://wiki.gnome.org/HowDoI/ChooseApplicationID
set(APPLICATION_ID "com.onfieldwork.marcoaiot")
set(APPLICATION_ID "com.marcoonfieldwork.aiot")
# Explicitly opt in to modern CMake behaviors to avoid warnings with recent
# versions of CMake.

View File

@ -385,7 +385,7 @@
CURRENT_PROJECT_VERSION = 1;
GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.onfieldwork.marcoaiot.RunnerTests;
PRODUCT_BUNDLE_IDENTIFIER = com.marcoonfieldwork.aiot.RunnerTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/marco.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/marco";
@ -399,7 +399,7 @@
CURRENT_PROJECT_VERSION = 1;
GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.onfieldwork.marcoaiot.RunnerTests;
PRODUCT_BUNDLE_IDENTIFIER = com.marcoonfieldwork.aiot.RunnerTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/marco.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/marco";
@ -413,7 +413,7 @@
CURRENT_PROJECT_VERSION = 1;
GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.onfieldwork.marcoaiot.RunnerTests;
PRODUCT_BUNDLE_IDENTIFIER = com.marcoonfieldwork.aiot.RunnerTests;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/marco.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/marco";

View File

@ -8,7 +8,7 @@
PRODUCT_NAME = marco
// The application's bundle identifier
PRODUCT_BUNDLE_IDENTIFIER = com.onfieldwork.marcoaiot
PRODUCT_BUNDLE_IDENTIFIER = com.marcoonfieldwork.aiot
// The copyright displayed in application information
PRODUCT_COPYRIGHT = Copyright © 2024 com.example. All rights reserved.