Signing, Installer, New Workflows
Some checks failed
Flutter Release / get-version (push) Successful in 7s
Flutter Release / build-windows (push) Failing after 9s
Flutter Release / create-release (push) Has been cancelled
Flutter Release / build-android (push) Has been cancelled

This commit is contained in:
2025-12-15 00:05:29 -05:00
parent 9ff0d62651
commit 110c5d99a1
25 changed files with 2647 additions and 268 deletions

View File

@@ -0,0 +1,176 @@
import 'package:flutter/material.dart';
import 'package:package_info_plus/package_info_plus.dart';
import 'package:url_launcher/url_launcher.dart';
class AppAboutDialog extends StatelessWidget {
const AppAboutDialog({super.key});
@override
Widget build(BuildContext context) {
return FutureBuilder<PackageInfo>(
future: PackageInfo.fromPlatform(),
builder: (context, snapshot) {
final packageInfo = snapshot.data;
return AlertDialog(
backgroundColor: const Color(0xFF1A1F3A),
title: Row(
children: [
Image.asset(
'assets/logo.png',
width: 32,
height: 32,
errorBuilder: (context, error, stackTrace) =>
const Icon(Icons.analytics, color: Color(0xFF50E3C2), size: 32),
),
const SizedBox(width: 12),
const Text(
'rmtPocketWatcher',
style: TextStyle(color: Colors.white),
),
],
),
content: SizedBox(
width: 400,
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Version ${packageInfo?.version ?? 'Unknown'}',
style: const TextStyle(
color: Color(0xFF50E3C2),
fontSize: 16,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 16),
const Text(
'Star Citizen AUEC Price Tracker',
style: TextStyle(color: Colors.white70, fontSize: 14),
),
const SizedBox(height: 8),
const Text(
'Bloomberg-style terminal interface for real-time RMT price monitoring',
style: TextStyle(color: Colors.white70, fontSize: 12),
),
const SizedBox(height: 16),
const Divider(color: Color(0xFF50E3C2)),
const SizedBox(height: 16),
_buildInfoRow('Developer', 'Lambda Banking Conglomerate'),
const SizedBox(height: 8),
_buildInfoRow('Platform', 'Flutter Desktop'),
const SizedBox(height: 8),
_buildInfoRow('Build', packageInfo?.buildNumber ?? 'Unknown'),
const SizedBox(height: 16),
const Text(
'Features:',
style: TextStyle(
color: Color(0xFF50E3C2),
fontSize: 14,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 8),
_buildFeatureItem('Real-time AUEC price tracking'),
_buildFeatureItem('Multiple vendor monitoring'),
_buildFeatureItem('Historical price charts'),
_buildFeatureItem('Price alerts & notifications'),
_buildFeatureItem('System tray integration'),
_buildFeatureItem('Automatic updates'),
const SizedBox(height: 16),
const Text(
'Data Sources:',
style: TextStyle(
color: Color(0xFF50E3C2),
fontSize: 14,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 8),
_buildFeatureItem('Eldorado.gg'),
_buildFeatureItem('PlayerAuctions'),
],
),
),
actions: [
TextButton(
onPressed: () => _launchUrl('https://git.hudsonriggs.systems/LambdaBankingConglomerate/rmtPocketWatcher'),
child: const Text(
'Source Code',
style: TextStyle(color: Color(0xFF50E3C2)),
),
),
TextButton(
onPressed: () => _launchUrl('https://git.hudsonriggs.systems/LambdaBankingConglomerate/rmtPocketWatcher/releases'),
child: const Text(
'Releases',
style: TextStyle(color: Color(0xFF50E3C2)),
),
),
ElevatedButton(
onPressed: () => Navigator.of(context).pop(),
style: ElevatedButton.styleFrom(
backgroundColor: const Color(0xFF50E3C2),
foregroundColor: Colors.black,
),
child: const Text('Close'),
),
],
);
},
);
}
Widget _buildInfoRow(String label, String value) {
return Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(
width: 80,
child: Text(
'$label:',
style: const TextStyle(
color: Colors.white70,
fontSize: 12,
fontWeight: FontWeight.bold,
),
),
),
Expanded(
child: Text(
value,
style: const TextStyle(color: Colors.white, fontSize: 12),
),
),
],
);
}
Widget _buildFeatureItem(String feature) {
return Padding(
padding: const EdgeInsets.only(left: 16, bottom: 4),
child: Row(
children: [
const Icon(
Icons.check_circle,
color: Color(0xFF50E3C2),
size: 12,
),
const SizedBox(width: 8),
Text(
feature,
style: const TextStyle(color: Colors.white70, fontSize: 12),
),
],
),
);
}
void _launchUrl(String url) async {
final uri = Uri.parse(url);
if (await canLaunchUrl(uri)) {
await launchUrl(uri);
}
}
}

View File

@@ -460,6 +460,12 @@ class _PriceChartState extends State<PriceChart> {
getTooltipColor: (touchedSpot) => const Color(0xFF2A2F4A),
tooltipRoundedRadius: 4,
tooltipPadding: const EdgeInsets.all(8),
tooltipMargin: 8,
fitInsideHorizontally: true,
fitInsideVertically: true,
rotateAngle: 0,
tooltipHorizontalAlignment: FLHorizontalAlignment.center,
tooltipHorizontalOffset: 0,
getTooltipItems: (List<LineBarSpot> touchedBarSpots) {
return touchedBarSpots.map((barSpot) {
final seller = sellers[barSpot.barIndex];
@@ -493,117 +499,7 @@ class _PriceChartState extends State<PriceChart> {
},
),
const SizedBox(height: 12), // Reduced from 16
// X-axis zoom controls
Consumer<PriceProvider>(
builder: (context, provider, child) {
if (provider.historyData == null || provider.historyData!.prices.isEmpty) {
return const SizedBox();
}
return Wrap(
alignment: WrapAlignment.center,
spacing: 4, // Reduced spacing
runSpacing: 8,
children: [
// Zoom out button
IconButton(
onPressed: _xZoomLevel > 1.0 ? () {
setState(() {
_xZoomLevel = (_xZoomLevel / 1.5).clamp(1.0, 10.0);
});
} : null,
icon: const Icon(Icons.zoom_out, color: Color(0xFF50E3C2), size: 18), // Smaller icon
style: IconButton.styleFrom(
backgroundColor: const Color(0xFF2A2F4A),
disabledBackgroundColor: const Color(0xFF1A1F3A),
minimumSize: const Size(32, 32), // Smaller buttons
),
),
// Left navigation
IconButton(
onPressed: _xCenterPoint > 0.1 ? () {
setState(() {
final step = 0.1 / _xZoomLevel;
_xCenterPoint = (_xCenterPoint - step).clamp(0.0, 1.0);
});
} : null,
icon: const Icon(Icons.chevron_left, color: Color(0xFF50E3C2), size: 18),
style: IconButton.styleFrom(
backgroundColor: const Color(0xFF2A2F4A),
disabledBackgroundColor: const Color(0xFF1A1F3A),
minimumSize: const Size(32, 32),
),
),
// Zoom level indicator
Container(
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), // More compact
decoration: BoxDecoration(
color: const Color(0xFF2A2F4A),
borderRadius: BorderRadius.circular(4),
),
child: Text(
'${(_xZoomLevel * 100).toInt()}%',
style: const TextStyle(
color: Color(0xFF50E3C2),
fontSize: 10, // Smaller font
fontFamily: 'monospace',
fontWeight: FontWeight.bold,
),
),
),
// Right navigation
IconButton(
onPressed: _xCenterPoint < 0.9 ? () {
setState(() {
final step = 0.1 / _xZoomLevel;
_xCenterPoint = (_xCenterPoint + step).clamp(0.0, 1.0);
});
} : null,
icon: const Icon(Icons.chevron_right, color: Color(0xFF50E3C2), size: 18),
style: IconButton.styleFrom(
backgroundColor: const Color(0xFF2A2F4A),
disabledBackgroundColor: const Color(0xFF1A1F3A),
minimumSize: const Size(32, 32),
),
),
// Zoom in button
IconButton(
onPressed: _xZoomLevel < 10.0 ? () {
setState(() {
_xZoomLevel = (_xZoomLevel * 1.5).clamp(1.0, 10.0);
});
} : null,
icon: const Icon(Icons.zoom_in, color: Color(0xFF50E3C2), size: 18),
style: IconButton.styleFrom(
backgroundColor: const Color(0xFF2A2F4A),
disabledBackgroundColor: const Color(0xFF1A1F3A),
minimumSize: const Size(32, 32),
),
),
// Reset button
ElevatedButton.icon(
onPressed: () {
setState(() {
_xZoomLevel = 1.0;
_xCenterPoint = 0.5;
_yAxisMax = _baseYAxisMax;
});
},
icon: const Icon(Icons.refresh, size: 14), // Smaller icon
label: const Text('Reset', style: TextStyle(fontSize: 10)), // Shorter text, smaller font
style: ElevatedButton.styleFrom(
backgroundColor: const Color(0xFF2A2F4A),
foregroundColor: const Color(0xFF50E3C2),
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), // More compact
minimumSize: const Size(0, 32), // Smaller height
),
),
],
);
},
),
const SizedBox(height: 12), // Reduced from 16
// Timeline scrubber (Bloomberg style)
// Timeline scrubber and controls (Bloomberg style)
Consumer<PriceProvider>(
builder: (context, provider, child) {
if (provider.historyData == null || provider.historyData!.prices.isEmpty) {
@@ -621,45 +517,155 @@ class _PriceChartState extends State<PriceChart> {
final firstDate = DateTime.fromMillisecondsSinceEpoch(sortedTimestamps.first);
final lastDate = DateTime.fromMillisecondsSinceEpoch(sortedTimestamps.last);
return Container(
height: 40,
padding: const EdgeInsets.symmetric(horizontal: 16),
decoration: BoxDecoration(
color: const Color(0xFF2A2F4A), // Lighter gray background
borderRadius: BorderRadius.circular(4),
),
child: Row(
children: [
Text(
'${firstDate.month}/${firstDate.day}',
style: const TextStyle(
color: Color(0xFF888888),
fontSize: 10,
fontFamily: 'monospace',
),
return Column(
children: [
// Timeline scrubber
Container(
height: 40,
padding: const EdgeInsets.symmetric(horizontal: 16),
decoration: BoxDecoration(
color: const Color(0xFF2A2F4A), // Lighter gray background
borderRadius: BorderRadius.circular(4),
),
Expanded(
child: Slider(
value: _xCenterPoint,
onChanged: (value) {
setState(() {
_xCenterPoint = value;
});
},
activeColor: const Color(0xFF50E3C2),
inactiveColor: const Color(0xFF1A1F3A),
),
child: Row(
children: [
Text(
'${firstDate.month}/${firstDate.day}',
style: const TextStyle(
color: Color(0xFF888888),
fontSize: 10,
fontFamily: 'monospace',
),
),
Expanded(
child: Slider(
value: _xCenterPoint,
onChanged: (value) {
setState(() {
_xCenterPoint = value;
});
},
activeColor: const Color(0xFF50E3C2),
inactiveColor: const Color(0xFF1A1F3A),
),
),
Text(
'${lastDate.month}/${lastDate.day}',
style: const TextStyle(
color: Color(0xFF888888),
fontSize: 10,
fontFamily: 'monospace',
),
),
],
),
Text(
'${lastDate.month}/${lastDate.day}',
style: const TextStyle(
color: Color(0xFF888888),
fontSize: 10,
fontFamily: 'monospace',
),
),
const SizedBox(height: 8),
// Centered X-axis zoom controls
Center(
child: Wrap(
alignment: WrapAlignment.center,
crossAxisAlignment: WrapCrossAlignment.center,
spacing: 4, // Reduced spacing
runSpacing: 8,
children: [
// Zoom out button
IconButton(
onPressed: _xZoomLevel > 1.0 ? () {
setState(() {
_xZoomLevel = (_xZoomLevel / 1.5).clamp(1.0, 10.0);
});
} : null,
icon: const Icon(Icons.zoom_out, color: Color(0xFF50E3C2), size: 18), // Smaller icon
style: IconButton.styleFrom(
backgroundColor: const Color(0xFF2A2F4A),
disabledBackgroundColor: const Color(0xFF1A1F3A),
minimumSize: const Size(32, 32), // Smaller buttons
),
),
// Left navigation
IconButton(
onPressed: _xCenterPoint > 0.1 ? () {
setState(() {
final step = 0.1 / _xZoomLevel;
_xCenterPoint = (_xCenterPoint - step).clamp(0.0, 1.0);
});
} : null,
icon: const Icon(Icons.chevron_left, color: Color(0xFF50E3C2), size: 18),
style: IconButton.styleFrom(
backgroundColor: const Color(0xFF2A2F4A),
disabledBackgroundColor: const Color(0xFF1A1F3A),
minimumSize: const Size(32, 32),
),
),
// Zoom level indicator
Container(
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), // More compact
decoration: BoxDecoration(
color: const Color(0xFF2A2F4A),
borderRadius: BorderRadius.circular(4),
),
child: Text(
'${(_xZoomLevel * 100).toInt()}%',
style: const TextStyle(
color: Color(0xFF50E3C2),
fontSize: 10, // Smaller font
fontFamily: 'monospace',
fontWeight: FontWeight.bold,
),
),
),
// Right navigation
IconButton(
onPressed: _xCenterPoint < 0.9 ? () {
setState(() {
final step = 0.1 / _xZoomLevel;
_xCenterPoint = (_xCenterPoint + step).clamp(0.0, 1.0);
});
} : null,
icon: const Icon(Icons.chevron_right, color: Color(0xFF50E3C2), size: 18),
style: IconButton.styleFrom(
backgroundColor: const Color(0xFF2A2F4A),
disabledBackgroundColor: const Color(0xFF1A1F3A),
minimumSize: const Size(32, 32),
),
),
// Zoom in button
IconButton(
onPressed: _xZoomLevel < 10.0 ? () {
setState(() {
_xZoomLevel = (_xZoomLevel * 1.5).clamp(1.0, 10.0);
});
} : null,
icon: const Icon(Icons.zoom_in, color: Color(0xFF50E3C2), size: 18),
style: IconButton.styleFrom(
backgroundColor: const Color(0xFF2A2F4A),
disabledBackgroundColor: const Color(0xFF1A1F3A),
minimumSize: const Size(32, 32),
),
),
// Reset button
ElevatedButton.icon(
onPressed: () {
setState(() {
_xZoomLevel = 1.0;
_xCenterPoint = 0.5;
_yAxisMax = _baseYAxisMax;
});
},
icon: const Icon(Icons.refresh, size: 14), // Smaller icon
label: const Text('Reset', style: TextStyle(fontSize: 10)), // Shorter text, smaller font
style: ElevatedButton.styleFrom(
backgroundColor: const Color(0xFF2A2F4A),
foregroundColor: const Color(0xFF50E3C2),
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), // More compact
minimumSize: const Size(0, 32), // Smaller height
),
),
],
),
],
),
),
],
);
},
),