Modified build.yaml, added logo, made profile screen float
All checks were successful
Build Flutter Web and Docker Image for Local Registry / Build Flutter Web App (push) Successful in 3m7s
All checks were successful
Build Flutter Web and Docker Image for Local Registry / Build Flutter Web App (push) Successful in 3m7s
This commit is contained in:
parent
2817b75f2e
commit
996c294153
@ -44,8 +44,8 @@ jobs:
|
||||
|
||||
- name: Build Docker Image
|
||||
run: |
|
||||
docker build -t localhost:5000/pogdark:latest .
|
||||
docker build -t localhost:5000/pogdark-app:latest .
|
||||
|
||||
- name: Push Docker Image to Local Registry
|
||||
run: |
|
||||
docker push localhost:5000/pogdark:latest
|
||||
docker push localhost:5000/pogdark-app:latest
|
Before Width: | Height: | Size: 167 KiB After Width: | Height: | Size: 167 KiB |
BIN
assets/pogdark_logo.png
Normal file
BIN
assets/pogdark_logo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 157 KiB |
@ -1,4 +1,5 @@
|
||||
import 'dart:async';
|
||||
import 'dart:ui';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
@ -25,12 +26,36 @@ class MyApp extends StatefulWidget {
|
||||
|
||||
class MyAppState extends State<MyApp> {
|
||||
Future<void>? _prefsReady;
|
||||
bool isProfileActive = false;
|
||||
bool showProfileInitially = false;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_prefsReady =
|
||||
Provider.of<SharedPreferencesProvider>(context, listen: false).ready;
|
||||
_prefsReady!.then((_) {
|
||||
final prefsProvider =
|
||||
Provider.of<SharedPreferencesProvider>(context, listen: false);
|
||||
// Check if username is not set; if so, show ProfileScreen initially
|
||||
if (prefsProvider.getUserName().isEmpty) {
|
||||
setState(() {
|
||||
showProfileInitially = true;
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void toggleProfileScreen() {
|
||||
setState(() {
|
||||
isProfileActive = !isProfileActive;
|
||||
});
|
||||
}
|
||||
|
||||
void closeInitialProfileScreen() {
|
||||
setState(() {
|
||||
showProfileInitially = false;
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
@ -53,12 +78,38 @@ class MyAppState extends State<MyApp> {
|
||||
future: _prefsReady,
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.connectionState == ConnectionState.done) {
|
||||
if (Provider.of<SharedPreferencesProvider>(context).getUserName() !=
|
||||
'') {
|
||||
return const StatusPage();
|
||||
} else {
|
||||
return const ProfileScreen(isEditing: false);
|
||||
}
|
||||
return Stack(
|
||||
children: [
|
||||
StatusPage(toggleProfile: toggleProfileScreen),
|
||||
if (showProfileInitially)
|
||||
BackdropFilter(
|
||||
filter: ImageFilter.blur(sigmaX: 5, sigmaY: 5),
|
||||
child: Container(
|
||||
color: Colors.black.withOpacity(0.3),
|
||||
child: Center(
|
||||
child: ProfileScreen(
|
||||
isEditing: false,
|
||||
onClose:
|
||||
closeInitialProfileScreen, // Close after setup
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
if (isProfileActive && !showProfileInitially)
|
||||
BackdropFilter(
|
||||
filter: ImageFilter.blur(sigmaX: 5, sigmaY: 5),
|
||||
child: Container(
|
||||
color: Colors.black.withOpacity(0.3),
|
||||
child: Center(
|
||||
child: ProfileScreen(
|
||||
isEditing: true,
|
||||
onClose: toggleProfileScreen, // Toggle on edit
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
} else {
|
||||
return const Center(child: CircularProgressIndicator());
|
||||
}
|
||||
|
@ -8,12 +8,13 @@ import 'package:image_picker/image_picker.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
import 'shared_preferences_provider.dart';
|
||||
import 'status_page.dart';
|
||||
|
||||
class ProfileScreen extends StatefulWidget {
|
||||
final bool isEditing;
|
||||
final VoidCallback onClose;
|
||||
|
||||
const ProfileScreen({super.key, required this.isEditing});
|
||||
const ProfileScreen(
|
||||
{super.key, required this.isEditing, required this.onClose});
|
||||
|
||||
@override
|
||||
ProfileScreenState createState() => ProfileScreenState();
|
||||
@ -22,6 +23,7 @@ class ProfileScreen extends StatefulWidget {
|
||||
class ProfileScreenState extends State<ProfileScreen> {
|
||||
final TextEditingController _nameController = TextEditingController();
|
||||
late String? imageData;
|
||||
bool isNameEmpty = true;
|
||||
final ImagePicker _picker = ImagePicker();
|
||||
|
||||
@override
|
||||
@ -31,6 +33,16 @@ class ProfileScreenState extends State<ProfileScreen> {
|
||||
Provider.of<SharedPreferencesProvider>(context, listen: false);
|
||||
_nameController.text = prefsProvider.getUserName();
|
||||
imageData = prefsProvider.getUserLogo();
|
||||
|
||||
// Check initial state of the name field and add listener
|
||||
_nameController.addListener(_checkNameField);
|
||||
isNameEmpty = _nameController.text.trim().isEmpty;
|
||||
}
|
||||
|
||||
void _checkNameField() {
|
||||
setState(() {
|
||||
isNameEmpty = _nameController.text.trim().isEmpty;
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> _pickImage() async {
|
||||
@ -62,13 +74,8 @@ class ProfileScreenState extends State<ProfileScreen> {
|
||||
await prefsProvider.setUserName(name);
|
||||
await prefsProvider.setUserLogo(imageData);
|
||||
|
||||
if (widget.isEditing) {
|
||||
if (mounted) {
|
||||
Navigator.pop(context); // Go back to the Status screen if editing
|
||||
}
|
||||
} else {
|
||||
_navigateToStatusScreen(); // Go to Status screen if this is the initial entry
|
||||
}
|
||||
// Close the screen after saving if the name is valid
|
||||
widget.onClose();
|
||||
} else {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(content: Text('Name cannot be empty!')),
|
||||
@ -77,15 +84,9 @@ class ProfileScreenState extends State<ProfileScreen> {
|
||||
}
|
||||
}
|
||||
|
||||
void _navigateToStatusScreen() {
|
||||
Navigator.pushReplacement(
|
||||
context,
|
||||
MaterialPageRoute(builder: (context) => const StatusPage()),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_nameController.removeListener(_checkNameField);
|
||||
_nameController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
@ -103,43 +104,60 @@ class ProfileScreenState extends State<ProfileScreen> {
|
||||
final prefsProvider = Provider.of<SharedPreferencesProvider>(context);
|
||||
final userLogo = prefsProvider.getUserLogo();
|
||||
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text(
|
||||
widget.isEditing ? 'Edit Profile' : 'Enter Your Name and Logo'),
|
||||
backgroundColor: Colors.blueAccent,
|
||||
),
|
||||
body: Padding(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
// Profile Image Display
|
||||
Center(
|
||||
child: CircleAvatar(
|
||||
return Center(
|
||||
child: Material(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(20.0),
|
||||
elevation: 10.0,
|
||||
child: Container(
|
||||
width: MediaQuery.of(context).size.width * 0.8,
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Align(
|
||||
alignment: Alignment.topRight,
|
||||
child: IconButton(
|
||||
icon: const Icon(Icons.close),
|
||||
onPressed: isNameEmpty ? null : widget.onClose,
|
||||
color: isNameEmpty ? Colors.grey : Colors.black,
|
||||
),
|
||||
),
|
||||
Text(
|
||||
widget.isEditing
|
||||
? 'Edit Your Information'
|
||||
: 'Tell Us About Yourself',
|
||||
style: const TextStyle(
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
CircleAvatar(
|
||||
radius: 50,
|
||||
backgroundImage: getLogoImage(userLogo).image,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
TextField(
|
||||
controller: _nameController,
|
||||
decoration: const InputDecoration(
|
||||
labelText: 'Name',
|
||||
border: OutlineInputBorder(),
|
||||
const SizedBox(height: 20),
|
||||
TextField(
|
||||
controller: _nameController,
|
||||
decoration: const InputDecoration(
|
||||
labelText: 'Your Pet\'s Name',
|
||||
border: OutlineInputBorder(),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
ElevatedButton(
|
||||
onPressed: _pickImage,
|
||||
child: const Text('Upload Logo'),
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
ElevatedButton(
|
||||
onPressed: _saveProfile,
|
||||
child: Text(widget.isEditing ? 'Save Changes' : 'Continue'),
|
||||
),
|
||||
],
|
||||
const SizedBox(height: 20),
|
||||
ElevatedButton(
|
||||
onPressed: _pickImage,
|
||||
child: const Text('Upload Profile Image'),
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
ElevatedButton(
|
||||
onPressed: _saveProfile,
|
||||
child: Text(widget.isEditing ? 'Save Changes' : 'Continue'),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
@ -16,7 +16,8 @@ class SharedPreferencesProvider extends ChangeNotifier {
|
||||
Future<void> _initPrefs() async {
|
||||
prefs = await SharedPreferences.getInstance();
|
||||
if (prefs.getString('userLogo') == null) {
|
||||
ByteData bytes = await rootBundle.load('assets/default_logo.png');
|
||||
ByteData bytes =
|
||||
await rootBundle.load('assets/default_profile_image.png');
|
||||
List<int> imageBytes = bytes.buffer.asUint8List();
|
||||
prefs.setString('userLogo', base64Encode(imageBytes));
|
||||
prefs.setString('id', const Uuid().v4());
|
||||
|
@ -5,11 +5,12 @@ import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:web_socket_channel/web_socket_channel.dart';
|
||||
|
||||
import 'profile_screen.dart';
|
||||
import 'shared_preferences_provider.dart';
|
||||
|
||||
class StatusPage extends StatefulWidget {
|
||||
const StatusPage({super.key});
|
||||
final VoidCallback toggleProfile;
|
||||
|
||||
const StatusPage({super.key, required this.toggleProfile});
|
||||
|
||||
@override
|
||||
StatusPageState createState() => StatusPageState();
|
||||
@ -20,12 +21,10 @@ class StatusPageState extends State<StatusPage> {
|
||||
Uri.parse('wss://api.pogdark.com:8889/ws'),
|
||||
);
|
||||
|
||||
// Convert the stream to a broadcast stream
|
||||
late final Stream<dynamic> broadcastStream;
|
||||
late StreamController<dynamic> controller;
|
||||
|
||||
List<Map<String, dynamic>> messages =
|
||||
[]; // To hold user messages with names and timestamps
|
||||
List<Map<String, dynamic>> messages = []; // To hold user messages
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
@ -39,14 +38,6 @@ class StatusPageState extends State<StatusPage> {
|
||||
return messages.where((message) => message['Status'] == status).toList();
|
||||
}
|
||||
|
||||
void _navigateToEditProfile() {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (context) => const ProfileScreen(isEditing: true)),
|
||||
);
|
||||
}
|
||||
|
||||
void _sendStatus(String id, String name, String? image, String status) {
|
||||
final message = jsonEncode({
|
||||
'Id': id,
|
||||
@ -81,7 +72,7 @@ class StatusPageState extends State<StatusPage> {
|
||||
radius: 20,
|
||||
backgroundImage: message['Image'] != null
|
||||
? Image.memory(base64Decode(message['Image'])).image
|
||||
: const AssetImage('assets/default_logo.png'),
|
||||
: const AssetImage('assets/default_profile_image.png'),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Text(
|
||||
@ -112,12 +103,15 @@ class StatusPageState extends State<StatusPage> {
|
||||
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: const Text('Pogdark'),
|
||||
title: Image.asset(
|
||||
'assets/pogdark_logo.png',
|
||||
height: 40,
|
||||
),
|
||||
backgroundColor: Colors.blueAccent,
|
||||
actions: [
|
||||
IconButton(
|
||||
icon: const Icon(Icons.edit),
|
||||
onPressed: _navigateToEditProfile,
|
||||
onPressed: widget.toggleProfile, // Open ProfileScreen overlay
|
||||
),
|
||||
],
|
||||
),
|
||||
@ -128,16 +122,14 @@ class StatusPageState extends State<StatusPage> {
|
||||
final newMessage =
|
||||
jsonDecode(snapshot.data as String) as Map<String, dynamic>;
|
||||
|
||||
// Update messages only if new or modified
|
||||
final incomingId = newMessage['Id'];
|
||||
messages.removeWhere((msg) => msg['Id'] == incomingId);
|
||||
if (newMessage['Status'] != 'expired' ||
|
||||
if (newMessage['Status'] != 'expired' &&
|
||||
newMessage['Status'] != "is leaving") {
|
||||
messages.add(newMessage);
|
||||
}
|
||||
}
|
||||
|
||||
// Separate messages by status
|
||||
final onTheWayMessages = _getMessagesByStatus('is on the way');
|
||||
final arrivedMessages = _getMessagesByStatus('has arrived');
|
||||
|
||||
@ -148,7 +140,6 @@ class StatusPageState extends State<StatusPage> {
|
||||
Expanded(
|
||||
child: Row(
|
||||
children: [
|
||||
// Column for "On the way" messages
|
||||
Expanded(
|
||||
child: Column(
|
||||
children: [
|
||||
@ -169,7 +160,6 @@ class StatusPageState extends State<StatusPage> {
|
||||
],
|
||||
),
|
||||
),
|
||||
// Column for "Arrived" messages
|
||||
Expanded(
|
||||
child: Column(
|
||||
children: [
|
||||
|
@ -70,7 +70,8 @@ flutter:
|
||||
|
||||
# To add assets to your application, add an assets section, like this:
|
||||
assets:
|
||||
- assets/default_logo.png
|
||||
- assets/default_profile_image.png
|
||||
- assets/pogdark_logo.png
|
||||
# - images/a_dot_burr.jpeg
|
||||
# - images/a_dot_ham.jpeg
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user