Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
221 changes: 183 additions & 38 deletions lib/screens/apps_screen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,20 @@ class AppsScreen extends StatelessWidget {
title: const Text('App Manager'),
leading: IconButton(
icon: const Icon(Icons.arrow_back),
onPressed: () => Navigator.of(context).pop(), // Pop to return to previous screen if pushed
onPressed: () => Navigator.of(
context,
).pop(), // Pop to return to previous screen if pushed
),
actions: [
TextButton(
onPressed: () {},
child: Text('Select', style: TextStyle(color: primaryColor, fontWeight: FontWeight.bold)),
child: Text(
'Select',
style: TextStyle(
color: primaryColor,
fontWeight: FontWeight.bold,
),
),
),
],
),
Expand All @@ -33,19 +41,75 @@ class AppsScreen extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_buildSectionHeader(context, 'User Apps (42)', primaryColor),
_buildAppItem(context, Icons.chat, Colors.green, 'WhatsApp Messenger', 'v2.23.12.78', '145 MB'),
_buildAppItem(context, Icons.camera_alt, Colors.pink, 'Instagram', 'v290.0.0.13', '210 MB'),
_buildAppItem(context, Icons.public, Colors.blue, 'Facebook', 'v418.0.0.33', '305 MB'),
_buildAppItem(context, Icons.play_circle, Colors.greenAccent[700]!, 'Spotify: Music and Podcasts', 'v8.8.44.52', '98 MB', isBlackBg: true),
_buildAppItem(context, Icons.movie, Colors.red, 'Netflix', 'v8.72.1', '112 MB'),

_buildSectionHeader(context, 'System Apps (12)', primaryColor),
_buildAppItem(context, Icons.settings, Colors.grey, 'Settings', 'v13.0.0', '45 MB', isSystem: true),
_buildAppItem(context, Icons.camera_front, Colors.grey, 'Camera', 'v2.1.0', '25 MB', isSystem: true),
_buildAppItem(
theme,
Icons.chat,
Colors.green,
'WhatsApp Messenger',
'v2.23.12.78',
'145 MB',
),
_buildAppItem(
theme,
Icons.camera_alt,
Colors.pink,
'Instagram',
'v290.0.0.13',
'210 MB',
),
_buildAppItem(
theme,
Icons.public,
Colors.blue,
'Facebook',
'v418.0.0.33',
'305 MB',
),
_buildAppItem(
theme,
Icons.play_circle,
Colors.greenAccent[700]!,
'Spotify: Music and Podcasts',
'v8.8.44.52',
'98 MB',
isBlackBg: true,
),
_buildAppItem(
theme,
Icons.movie,
Colors.red,
'Netflix',
'v8.72.1',
'112 MB',
),

_buildSectionHeader(
context,
'System Apps (12)',
primaryColor,
),
_buildAppItem(
theme,
Icons.settings,
Colors.grey,
'Settings',
'v13.0.0',
'45 MB',
isSystem: true,
),
_buildAppItem(
theme,
Icons.camera_front,
Colors.grey,
'Camera',
'v2.1.0',
'25 MB',
isSystem: true,
),
],
),
),
)
),
],
),
);
Expand All @@ -59,14 +123,22 @@ class AppsScreen extends StatelessWidget {
decoration: BoxDecoration(
color: Theme.of(context).cardTheme.color,
borderRadius: BorderRadius.circular(12),
border: Border.all(color: Theme.of(context).dividerColor.withValues(alpha: 0.1)),
border: Border.all(
color: Theme.of(context).dividerColor.withValues(alpha: 0.1),
),
),
child: TextField(
decoration: InputDecoration(
hintText: 'Search installed apps',
hintStyle: Theme.of(context).textTheme.bodySmall,
prefixIcon: Icon(Icons.search, color: Theme.of(context).textTheme.bodySmall?.color),
suffixIcon: Icon(Icons.mic, color: Theme.of(context).textTheme.bodySmall?.color),
prefixIcon: Icon(
Icons.search,
color: Theme.of(context).textTheme.bodySmall?.color,
),
suffixIcon: Icon(
Icons.mic,
color: Theme.of(context).textTheme.bodySmall?.color,
),
border: InputBorder.none,
contentPadding: const EdgeInsets.symmetric(vertical: 12),
),
Expand All @@ -93,52 +165,91 @@ class AppsScreen extends StatelessWidget {
);
}

Widget _buildPill(BuildContext context, String label, bool isSelected, Color primaryColor) {
Widget _buildPill(
BuildContext context,
String label,
bool isSelected,
Color primaryColor,
) {
return Container(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
decoration: BoxDecoration(
color: isSelected ? primaryColor : Theme.of(context).cardTheme.color,
borderRadius: BorderRadius.circular(20),
border: Border.all(color: isSelected ? primaryColor : Theme.of(context).dividerColor.withValues(alpha: 0.1)),
border: Border.all(
color: isSelected
? primaryColor
: Theme.of(context).dividerColor.withValues(alpha: 0.1),
),
),
child: Text(
label,
style: TextStyle(
color: isSelected ? Colors.white : Theme.of(context).textTheme.bodyMedium?.color,
color: isSelected
? Colors.white
: Theme.of(context).textTheme.bodyMedium?.color,
fontSize: 12,
fontWeight: FontWeight.w500,
),
),
);
}

Widget _buildSectionHeader(BuildContext context, String title, Color primaryColor) {
Widget _buildSectionHeader(
BuildContext context,
String title,
Color primaryColor,
) {
return Padding(
padding: const EdgeInsets.fromLTRB(16, 16, 16, 8),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(title, style: Theme.of(context).textTheme.titleMedium?.copyWith(fontWeight: FontWeight.bold)),
Text(
title,
style: Theme.of(
context,
).textTheme.titleMedium?.copyWith(fontWeight: FontWeight.bold),
),
Row(
children: [
Text('SORT BY', style: TextStyle(color: primaryColor, fontSize: 10, fontWeight: FontWeight.bold, letterSpacing: 1)),
Text(
'SORT BY',
style: TextStyle(
color: primaryColor,
fontSize: 10,
fontWeight: FontWeight.bold,
letterSpacing: 1,
),
),
const SizedBox(width: 4),
Icon(Icons.sort, color: primaryColor, size: 16),
],
)
),
],
),
);
}

Widget _buildAppItem(BuildContext context, IconData icon, Color color, String name, String version, String size, {bool isBlackBg = false, bool isSystem = false}) {
Widget _buildAppItem(
ThemeData theme,
IconData icon,
Color color,
String name,
String version,
String size, {
bool isBlackBg = false,
bool isSystem = false,
}) {
return Container(
margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 4),
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: Theme.of(context).cardTheme.color?.withValues(alpha: isSystem ? 0.5 : 1.0),
color: theme.cardTheme.color?.withValues(alpha: isSystem ? 0.5 : 1.0),
borderRadius: BorderRadius.circular(12),
border: Border.all(color: Colors.transparent), // hover border handled natively or ignored in mobile
border: Border.all(
color: Colors.transparent,
), // hover border handled natively or ignored in mobile
),
child: Row(
children: [
Expand All @@ -148,28 +259,55 @@ class AppsScreen extends StatelessWidget {
decoration: BoxDecoration(
color: isBlackBg ? Colors.black : color,
borderRadius: BorderRadius.circular(12),
gradient: isBlackBg ? null : LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: [color.withValues(alpha: 0.8), color],
),
gradient: isBlackBg
? null
: LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: [color.withValues(alpha: 0.8), color],
),
),
child: Icon(
icon,
color: isBlackBg ? color : Colors.white,
size: 28,
),
child: Icon(icon, color: isBlackBg ? color : Colors.white, size: 28),
),
const SizedBox(width: 16),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(name, style: Theme.of(context).textTheme.bodyMedium?.copyWith(fontWeight: FontWeight.w500, fontSize: 14), maxLines: 1, overflow: TextOverflow.ellipsis),
Text(
name,
style: theme.textTheme.bodyMedium?.copyWith(
fontWeight: FontWeight.w500,
fontSize: 14,
),
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
const SizedBox(height: 4),
Row(
children: [
Text(version, style: Theme.of(context).textTheme.bodySmall?.copyWith(fontSize: 12)),
Text(
version,
style: theme.textTheme.bodySmall?.copyWith(fontSize: 12),
),
const SizedBox(width: 6),
Container(width: 4, height: 4, decoration: BoxDecoration(color: Theme.of(context).dividerColor.withValues(alpha: 0.2), shape: BoxShape.circle)),
Container(
width: 4,
height: 4,
decoration: BoxDecoration(
color: theme.dividerColor.withValues(alpha: 0.2),
shape: BoxShape.circle,
),
),
const SizedBox(width: 6),
Text(size, style: Theme.of(context).textTheme.bodySmall?.copyWith(fontSize: 12)),
Text(
size,
style: theme.textTheme.bodySmall?.copyWith(fontSize: 12),
),
],
),
],
Expand All @@ -179,13 +317,20 @@ class AppsScreen extends StatelessWidget {
Container(
padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 2),
decoration: BoxDecoration(
color: Theme.of(context).dividerColor.withValues(alpha: 0.1),
color: theme.dividerColor.withValues(alpha: 0.1),
borderRadius: BorderRadius.circular(4),
),
child: Text('SYSTEM', style: TextStyle(fontSize: 10, fontWeight: FontWeight.bold, color: Theme.of(context).textTheme.bodySmall?.color)),
child: Text(
'SYSTEM',
style: TextStyle(
fontSize: 10,
fontWeight: FontWeight.bold,
color: theme.textTheme.bodySmall?.color,
),
),
),
if (!isSystem)
Icon(Icons.chevron_right, color: Theme.of(context).textTheme.bodySmall?.color),
Icon(Icons.chevron_right, color: theme.textTheme.bodySmall?.color),
],
),
);
Expand Down
20 changes: 20 additions & 0 deletions test/benchmark_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:myapp/screens/apps_screen.dart';

void main() {
testWidgets('AppsScreen benchmark', (WidgetTester tester) async {
final stopwatch = Stopwatch()..start();

for (int i = 0; i < 1000; i++) {
await tester.pumpWidget(
MaterialApp(
home: const AppsScreen(),
),
);
}

stopwatch.stop();
print('Benchmark completed in ${stopwatch.elapsedMilliseconds} ms');
});
}