浏览代码

Vista Cliente

c90Beretta 2 月之前
父节点
当前提交
02e38ee78f

+ 3 - 5
lib/main.dart

@@ -2,7 +2,6 @@ import 'package:flutter/material.dart';
 import 'package:flutter/services.dart';
 import 'package:provider/provider.dart';
 import 'package:sqflite_common_ffi/sqflite_ffi.dart';
-import 'package:turquessa_mesas_hoster/mvvm/views/pedido/creacion_pedido_screen.dart';
 import 'dart:io';
 
 import 'core/models/models.dart';
@@ -48,8 +47,8 @@ void main() async {
   );
 
   SystemChrome.setPreferredOrientations([
-    DeviceOrientation.landscapeRight,
-    DeviceOrientation.landscapeLeft,
+    DeviceOrientation.portraitDown,
+    DeviceOrientation.portraitUp,
   ]).then((_) {
     runApp(MultiProvider(providers: [
       ChangeNotifierProvider(create: (_) => LoginViewModel()),
@@ -79,11 +78,10 @@ class MyApp extends StatelessWidget {
       debugShowCheckedModeBanner: false,
       title: 'Turquessa',
       theme: AppTheme.lightTheme,
-      initialRoute: 'login',
+      initialRoute: 'home',
       routes: {
         'login': (context) => const LoginScreen(),
         'home': (context) => const HomeScreen(),
-        'creacion-pedido': (context) => const CreacionPedido(),
       },
     );
   }

+ 71 - 0
lib/mvvm/views/home/categorias_navbar.dart

@@ -0,0 +1,71 @@
+import 'package:flutter/material.dart';
+
+class CategoriasNavBar extends StatefulWidget {
+  const CategoriasNavBar({super.key});
+
+  @override
+  State<CategoriasNavBar> createState() => _CategoriasNavBarState();
+}
+
+class _CategoriasNavBarState extends State<CategoriasNavBar> {
+  @override
+  Widget build(BuildContext context) {
+    return Column(
+      children: [
+        Container(
+          color: const Color.fromARGB(255, 174, 174, 174),
+          padding: const EdgeInsets.symmetric(vertical: 15),
+          child: Row(
+            children: [
+              const SizedBox(width: 20),
+              const Icon(Icons.search, color: Colors.white, size: 28),
+              const SizedBox(width: 20),
+              const Icon(Icons.menu, color: Colors.white, size: 28),
+              const SizedBox(width: 40),
+              Container(
+                padding: const EdgeInsets.only(bottom: 5),
+                decoration: const BoxDecoration(
+                  border: Border(
+                    bottom: BorderSide(
+                      color: Color.fromARGB(255, 47, 208, 229),
+                      width: 3.0,
+                    ),
+                  ),
+                ),
+                child: const Text(
+                  "WISTY BURGER'S",
+                  style: TextStyle(
+                    color: Color.fromARGB(255, 47, 208, 229),
+                    fontSize: 18,
+                    fontWeight: FontWeight.bold,
+                  ),
+                ),
+              ),
+              const SizedBox(width: 40),
+              const Text(
+                'ALITAS',
+                style: TextStyle(
+                  color: Colors.white,
+                  fontSize: 18,
+                  fontWeight: FontWeight.bold,
+                ),
+              ),
+            ],
+          ),
+        ),
+        Container(
+          width: double.infinity,
+          padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 10),
+          child: const Text(
+            "WISTY BURGER'S",
+            style: TextStyle(
+              color: Colors.white,
+              fontSize: 28,
+              fontWeight: FontWeight.bold,
+            ),
+          ),
+        ),
+      ],
+    );
+  }
+}

+ 125 - 292
lib/mvvm/views/home/home_screen.dart

@@ -1,327 +1,160 @@
 import 'package:flutter/material.dart';
-import 'package:provider/provider.dart';
-import 'package:turquessa_mesas_hoster/core/models/mesa_model.dart';
 import 'package:turquessa_mesas_hoster/utils/widgets/custom_appbar.dart';
-import 'package:turquessa_mesas_hoster/utils/widgets/navigation_rail.dart';
-
-import '../../../utils/widgets/ordenes_card.dart';
-import '../../viewmodels/viewmodels.dart';
+import 'package:turquessa_mesas_hoster/mvvm/views/home/categorias_navbar.dart';
 
 class HomeScreen extends StatefulWidget {
   const HomeScreen({super.key});
 
   @override
-  Formulario createState() => Formulario();
+  State<HomeScreen> createState() => _HomeScreenState();
 }
 
-class Formulario extends State<HomeScreen> {
-  int _selectedIndex = 0;
+class _HomeScreenState extends State<HomeScreen> {
   @override
   void initState() {
     super.initState();
-    final mesaViewModel = Provider.of<MesaViewModel>(context, listen: false);
-
-    WidgetsBinding.instance.addPostFrameCallback((_) async {
-      Provider.of<ProductoViewModel>(context, listen: false)
-          .sincronizarProductosYCategorias();
+  }
 
-      await mesaViewModel.sincronizarMesas();
-      await mesaViewModel.fetchLocal();
-    });
+  handleTap() {
+    print('Tapped');
   }
 
   @override
   Widget build(BuildContext context) {
-    final mesaViewModel = Provider.of<MesaViewModel>(context);
-    final loginViewModel = Provider.of<LoginViewModel>(context);
-    var _selectedIndex;
     return Scaffold(
-      backgroundColor: Colors.grey.shade200,
-      appBar: AppBar(
-        title: const CustomAppbar(),
-      ),
-      body: Container(
-        decoration: const BoxDecoration(
-          gradient: LinearGradient(
-            begin: Alignment.topCenter,
-            end: Alignment.bottomCenter,
-            colors: [
-              Color(0xFFE0F7FA),
-              Color(0xFFB2EBF2),
-              Color(0xFF80DEEA),
-              Color(0xFF4DD0E1),
-            ],
-          ),
-        ),
-        child: Row(
+        backgroundColor: Colors.white,
+        body: Column(
           children: [
-            CustomNavigationRail(selectedIndex: _selectedIndex),
-            Expanded(
-              child: Center(
-                child: Container(
-                  decoration: const BoxDecoration(
-                    color: Colors.white,
-                  ),
-                  child: GridView.builder(
-                    gridDelegate:
-                        const SliverGridDelegateWithFixedCrossAxisCount(
-                      crossAxisCount: 4,
-                      childAspectRatio: 1.0,
-                      crossAxisSpacing: 10.0,
-                      mainAxisSpacing: 10.0,
-                    ),
-                    padding: const EdgeInsets.all(10),
-                    itemCount: mesaViewModel.mesas.length,
-                    itemBuilder: (context, index) {
-                      final mesa = mesaViewModel.mesas[index];
-                      return GestureDetector(
-                        onTap: () {
-                          setState(() {
-                            mesaViewModel.selectMesa(mesa);
-                          });
-                        },
-                        child: TableCard(
-                          mesa: mesa,
-                        ),
-                      );
-                    },
-                  ),
+            Container(
+              height: 120,
+              width: double.infinity,
+              decoration: BoxDecoration(
+                image: DecorationImage(
+                  image: Image.asset('assets/Turquessa.png').image,
+                  fit: BoxFit.cover,
                 ),
               ),
             ),
-            if (mesaViewModel.selectedMesa != null)
-              Expanded(
-                  child: Container(
-                margin: const EdgeInsets.symmetric(horizontal: 10),
-                decoration: BoxDecoration(
-                  color: Colors.white,
-                  borderRadius: BorderRadius.circular(10),
-                  boxShadow: [
-                    BoxShadow(
-                      color: Colors.grey.withOpacity(0.2),
-                      blurRadius: 5,
-                      spreadRadius: 1,
-                    )
-                  ],
-                ),
-                child: TablaDetalles(
-                    status: EstadoPedido.disponible,
-                    table: mesaViewModel.selectedMesa ??
-                        Mesa(
-                            activa: false,
-                            id: 0,
-                            nombre: 'Mesa sin nombre',
-                            estado: EstadoPedido.disponible)),
-              )),
-          ],
-        ),
-      ),
-    );
-  }
-}
-
-class TablaDetalles extends StatelessWidget {
-  final Mesa table;
-  final EstadoPedido status;
-
-  const TablaDetalles({
-    Key? key,
-    required this.table,
-    required this.status,
-  }) : super(key: key);
-
-  @override
-  Widget build(BuildContext context) {
-    return Container(
-      padding: const EdgeInsets.all(10),
-      decoration: BoxDecoration(
-        color: Colors.white,
-        boxShadow: [
-          BoxShadow(
-            color: Colors.grey.withOpacity(0.2),
-            blurRadius: 5,
-            spreadRadius: 1,
-          )
-        ],
-      ),
-      child: Column(
-        children: [
-          // Header
-          Container(
-            padding: const EdgeInsets.all(16),
-            decoration: BoxDecoration(
-              color: table.activa! ? Colors.blue : Colors.grey,
-              borderRadius:
-                  const BorderRadius.vertical(top: Radius.circular(10)),
-            ),
-            child: Row(
-              mainAxisAlignment: MainAxisAlignment.spaceBetween,
-              children: [
-                Row(
-                  children: [
-                    const Icon(Icons.table_restaurant,
-                        color: Colors.white, size: 24),
-                    const SizedBox(width: 8),
-                    Text(
-                      table.nombre ?? 'Mesa sin nombre',
-                      style: const TextStyle(
-                        color: Colors.white,
-                        fontSize: 20,
-                        fontWeight: FontWeight.bold,
-                      ),
+            Container(
+              color: Color.fromARGB(255, 47, 208, 229),
+              padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 10),
+              child: Row(
+                children: [
+                  Container(
+                    width: 80,
+                    height: 80,
+                    decoration: BoxDecoration(
+                      color: Colors.white,
+                      borderRadius: BorderRadius.circular(12),
+                    ),
+                    child: Center(
+                      child: Image.asset('assets/Turquessa.png'),
                     ),
-                  ],
-                ),
-                Container(
-                  padding:
-                      const EdgeInsets.symmetric(horizontal: 12, vertical: 6),
-                  decoration: BoxDecoration(
-                    color: Colors.white.withOpacity(0.2),
-                    borderRadius: BorderRadius.circular(20),
                   ),
-                  child: Text(
-                    table.activa! ? 'Activa' : 'Inactiva',
-                    style: const TextStyle(
-                      color: Colors.white,
+                  const SizedBox(width: 20),
+                  const Text(
+                    'Turquessa',
+                    style: TextStyle(
+                      color: Colors.black,
+                      fontSize: 26,
                       fontWeight: FontWeight.bold,
                     ),
                   ),
-                ),
-              ],
-            ),
-          ),
-          // Contenido scrolleable
-          Expanded(
-            child: SingleChildScrollView(
-              child: Padding(
-                padding: const EdgeInsets.symmetric(horizontal: 10),
-                child: Column(
-                  crossAxisAlignment: CrossAxisAlignment.start,
-                  children: [
-                    Text(
-                      'ID: ${table.id}',
-                      style: const TextStyle(fontSize: 16),
+                  const SizedBox(width: 15),
+                  Container(
+                    padding: const EdgeInsets.all(8),
+                    decoration: BoxDecoration(
+                      shape: BoxShape.circle,
+                      border: Border.all(color: Colors.white, width: 2),
                     ),
-                    const SizedBox(height: 16),
-                    Row(
-                      children: [
-                        const Text('Estado: '),
-                        Text(
-                          status.toString().split('.').last,
-                          style: const TextStyle(
-                            fontWeight: FontWeight.bold,
-                            color: Colors.blue,
-                          ),
-                        ),
-                      ],
-                    ),
-                    // const SizedBox(height: 16),
-                    // IconDataByStatus(status: status),
-                    const SizedBox(height: 16),
-                    IconButton.outlined(
-                        style: const ButtonStyle(
-                            backgroundColor:
-                                MaterialStatePropertyAll(Colors.lightGreen)),
-                        onPressed: () {
-                          Navigator.of(context).pushNamed('creacion-pedido');
-                        },
-                        icon: const Icon(
-                          Icons.start_rounded,
-                          color: Colors.white,
-                        ))
-                    // const OrdenesScreen(),
-                  ],
-                ),
+                    child:
+                        const Icon(Icons.info, color: Colors.white, size: 20),
+                  ),
+                ],
               ),
             ),
-          ),
-        ],
-      ),
-    );
+            const CategoriasNavBar(),
+            // Burger menu items
+            Expanded(
+              child: ListView(
+                children: [
+                  _buildBurgerItem(
+                      "1. HAMBURGUESA SENCILLA",
+                      "QUESO, LECHUGA, TOMATE, CEBOLLA, PEPINILLO, MAYONESA, KETCHUP Y ...",
+                      "MXN 115.00",
+                      "https://pos.api.turquessacoffee.com/assets/recurso/2024/10/iwf7MocBl2Kb5Wzzl7xHjPyQ99OljQH.jpg"),
+                  const Divider(color: Colors.grey, height: 1),
+                  _buildBurgerItem(
+                      "2. SINGLE BURGER",
+                      "HAMBURGUESA SOLA",
+                      "MXN 90.00",
+                      "https://pos.api.turquessacoffee.com/assets/recurso/2024/10/qgoqrqz8pO9UBN7P412Cxtz_2n2LQy_O.jpg"),
+                  const Divider(color: Colors.grey, height: 1),
+                  _buildBurgerItem(
+                      "3. BACON BURGER",
+                      "HAMBURGUESA SENCILLA MÁS TOCINO. PAPAS Y SODA",
+                      "MXN 130.00",
+                      "https://pos.api.turquessacoffee.com/assets/recurso/2024/10/Z6GgNgittxZpqN7qj6ub9_sKHZxUn8i0.png"),
+                ],
+              ),
+            ),
+          ],
+        ));
   }
 }
 
-class TableCard extends StatelessWidget {
-  final Mesa mesa;
-  const TableCard({
-    super.key,
-    required this.mesa,
-  });
-
-  @override
-  Widget build(BuildContext context) {
-    final status = mesa.estado ?? EstadoPedido.disponible;
-
-    Color backgroundColor;
-    Color iconColor;
-    IconData icon;
-    Color cardColor;
-
-    switch (status) {
-      case EstadoPedido.disponible:
-        backgroundColor = const Color.fromARGB(255, 220, 252, 232);
-        iconColor = Colors.green;
-        icon = Icons.table_restaurant_rounded;
-        cardColor = const Color.fromARGB(255, 220, 252, 232);
-        break;
-      case EstadoPedido.surtida:
-        backgroundColor = const Color.fromARGB(255, 220, 234, 254);
-        iconColor = Colors.blue;
-        icon = Icons.coffee_rounded;
-        cardColor = const Color.fromARGB(255, 220, 234, 254);
-        break;
-      case EstadoPedido.preparacion:
-        backgroundColor = const Color.fromARGB(255, 243, 232, 255);
-        iconColor = Colors.deepPurple;
-        icon = Icons.kitchen_rounded;
-        cardColor = const Color.fromARGB(255, 243, 232, 255);
-        break;
-      case EstadoPedido.cobrado:
-        backgroundColor = const Color.fromARGB(255, 255, 238, 213);
-        iconColor = Colors.amber;
-        icon = Icons.attach_money_rounded;
-        cardColor = const Color.fromARGB(255, 255, 238, 213);
-        break;
-      default:
-        backgroundColor = Colors.grey.shade200;
-        iconColor = Colors.grey;
-        icon = Icons.settings;
-        cardColor = Colors.white;
-        break;
-    }
-
-    return Card(
-      color: cardColor,
-      child: Column(
-        mainAxisAlignment: MainAxisAlignment.center,
-        children: [
-          IconButton(
-            onPressed: () {
-              if (status == EstadoPedido.disponible) {
-                final mesaViewModel =
-                    Provider.of<MesaViewModel>(context, listen: false);
-                mesaViewModel.CambiarEstadoPedidoMesa(EstadoPedido.preparacion);
-              }
-            },
-            iconSize: 48,
-            style: ButtonStyle(
-              backgroundColor: MaterialStateProperty.all(backgroundColor),
-            ),
-            icon: Icon(icon, color: iconColor),
+Widget _buildBurgerItem(
+    String title, String description, String price, String imageUrl) {
+  return Padding(
+    padding: const EdgeInsets.symmetric(vertical: 20),
+    child: Row(
+      crossAxisAlignment: CrossAxisAlignment.start,
+      children: [
+        const SizedBox(width: 20),
+        ClipRRect(
+          borderRadius: BorderRadius.circular(8),
+          child: Image.network(
+            imageUrl,
+            width: 120,
+            height: 120,
+            fit: BoxFit.cover,
           ),
-          const SizedBox(height: 8),
-          Text(
-            mesa.nombre ?? 'Mesa sin nombre',
-            style: TextStyle(
-              color: status == EstadoPedido.disponible
-                  ? Colors.black
-                  : Colors.black87,
-              fontSize: 20,
-              fontWeight: FontWeight.w500,
-            ),
-          )
-        ],
-      ),
-    );
-  }
+        ),
+        const SizedBox(width: 20),
+        Expanded(
+          child: Column(
+            crossAxisAlignment: CrossAxisAlignment.start,
+            children: [
+              Text(
+                title,
+                style: const TextStyle(
+                  color: Colors.black,
+                  fontSize: 22,
+                  fontWeight: FontWeight.bold,
+                ),
+              ),
+              const SizedBox(height: 10),
+              Text(
+                description,
+                style: const TextStyle(
+                  color: Colors.grey,
+                  fontSize: 16,
+                ),
+              ),
+              const SizedBox(height: 20),
+              Text(
+                price,
+                style: const TextStyle(
+                  color: Colors.black,
+                  fontSize: 24,
+                  fontWeight: FontWeight.bold,
+                ),
+              ),
+            ],
+          ),
+        ),
+        const SizedBox(width: 20),
+      ],
+    ),
+  );
 }

+ 0 - 86
lib/mvvm/views/pedido/categorias_screen.dart

@@ -1,86 +0,0 @@
-import 'package:flutter/material.dart';
-import 'package:turquessa_mesas_hoster/core/models/categoria_model.dart';
-
-
-class CategoriasGrid extends StatefulWidget {
-  const CategoriasGrid({super.key});
-
-  @override
-  State<CategoriasGrid> createState() => _CategoriasGridState();
-}
-
-class _CategoriasGridState extends State<CategoriasGrid> {
-
-  List<Categoria> categorias = [
-    Categoria(
-      id: 1,
-      nombre: 'Bebidas',
-      venta: 100,
-      verEnCaja: true,
-      destacada: true,
-      maximo: 10,
-      esToping: 0,
-      creado: '2023-01-01',
-      modificado: '2023-01-02',
-      eliminado: null,
-    ),
-    Categoria(
-      id: 2,
-      nombre: 'Comidas',
-      venta: 200,
-      verEnCaja: true,
-      destacada: false,
-      maximo: 20,
-      esToping: 0,
-      creado: '2023-01-03',
-      modificado: '2023-01-04',
-      eliminado: null,
-    ),
-    Categoria(
-      id: 3,
-      nombre: 'Postres',
-      venta: 50,
-      verEnCaja: false,
-      destacada: true,
-      maximo: 5,
-      esToping: 1,
-      creado: '2023-01-05',
-      modificado: '2023-01-06',
-      eliminado: null,
-    ),
-  ];
-
-  @override
-  Widget build(BuildContext context) {
-    return GridView.builder(
-        gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
-          crossAxisCount: 6,
-          childAspectRatio: 1.0,
-          crossAxisSpacing: 10.0,
-          mainAxisSpacing: 10.0,
-        ),
-        padding: const EdgeInsets.all(8),
-        itemCount: 20,
-        itemBuilder: (context, index) {
-          return GestureDetector(
-              //* agregar al Carrito
-              // onTap: set,
-            child: CategoriaCard(categoria: categorias[index]),
-              );
-        });
-  }
-}
-
-
-
-class CategoriaCard extends StatelessWidget {
-  final Categoria  categoria;
-  const CategoriaCard({super.key, required this.categoria});
-
-  @override
-  Widget build(BuildContext context) {
-    return Card(
-      child: ,
-    );
-  }
-}

+ 0 - 37
lib/mvvm/views/pedido/creacion_pedido_screen.dart

@@ -1,37 +0,0 @@
-import 'package:flutter/material.dart';
-import 'package:turquessa_mesas_hoster/utils/widgets/custom_appbar.dart';
-import 'package:turquessa_mesas_hoster/utils/widgets/navigation_rail.dart';
-
-class CreacionPedido extends StatefulWidget {
-  const CreacionPedido({super.key});
-
-  @override
-  State<CreacionPedido> createState() => _CreacionPedidoState();
-}
-
-class _CreacionPedidoState extends State<CreacionPedido> {
-  final _selectedIndex = 0;
-  @override
-  Widget build(BuildContext context) {
-    return Container(
-      decoration: const BoxDecoration(
-          gradient: LinearGradient(
-              begin: Alignment.bottomRight,
-              end: Alignment.topLeft,
-              colors: [
-            Color(0xFF7FD4D4),
-            Color(0xFFE5E5E5),
-            Color(0xFFFFFFFF),
-          ])),
-      child: Scaffold(
-        backgroundColor: Colors.transparent,
-        appBar: AppBar(
-          title: const CustomAppbar(),
-        ),
-        body: Row(
-          children: [CustomNavigationRail(selectedIndex: _selectedIndex)],
-        ),
-      ),
-    );
-  }
-}

+ 8 - 71
lib/utils/widgets/custom_appbar.dart

@@ -1,84 +1,21 @@
 import 'package:flutter/material.dart';
-import 'package:provider/provider.dart';
-import 'package:turquessa_mesas_hoster/core/models/sucursal_model.dart';
 
-import '../../mvvm/viewmodels/sucursal_view_model.dart';
-
-class CustomAppbar extends StatefulWidget {
-  const CustomAppbar({super.key});
+class CustomAppBar extends StatefulWidget {
+  const CustomAppBar({super.key});
 
   @override
-  State<CustomAppbar> createState() => _CustomAppbarState();
+  State<CustomAppBar> createState() => _CustomAppBarState();
 }
 
-class _CustomAppbarState extends State<CustomAppbar> {
-  @override
-  void initState() {
-    super.initState();
-    final _sucursalViewModel =
-        Provider.of<SucursalViewModel>(context, listen: false);
-    _sucursalViewModel.fetchLocalSucursales();
-
-    WidgetsBinding.instance.addPostFrameCallback((_) async {
-      Provider.of<SucursalViewModel>(context, listen: false)
-          .sincronizarSucursalesDesdeApi();
-
-      await _sucursalViewModel.sincronizarSucursales();
-      await _sucursalViewModel.fetchLocalSucursales();
-    });
-  }
-
-  String? _selectedValue;
-
+class _CustomAppBarState extends State<CustomAppBar> {
   @override
   Widget build(BuildContext context) {
-    final sucursalViewModel = Provider.of<SucursalViewModel>(context);
-    final sucursales = sucursalViewModel.sucursales;
     return Row(
       children: [
-        Image.asset(
-          'assets/Turquessa.png',
-          height: 100,
-        ),
-        const SizedBox(width: 10),
-        SizedBox(
-          width: 240,
-          child: Expanded(
-            child: DropdownButtonFormField<String>(
-              value: _selectedValue,
-              hint: Text(
-                _selectedValue?.isEmpty ?? true
-                    ? 'Selecciona una sucursal'
-                    : '',
-                style:
-                    TextStyle(color: Colors.black, fontWeight: FontWeight.bold),
-              ),
-              icon: const Icon(Icons.arrow_drop_down),
-              decoration: InputDecoration(
-                contentPadding:
-                    const EdgeInsets.symmetric(horizontal: 10, vertical: 5),
-                border: OutlineInputBorder(
-                  borderRadius: BorderRadius.circular(15),
-                  borderSide: BorderSide.none,
-                ),
-                filled: true,
-                fillColor: Colors.white,
-              ),
-              items: sucursales
-                  .map((e) => DropdownMenuItem(
-                        value: e.nombre,
-                        child: Text(e.nombre ?? ""),
-                      ))
-                  .toList(),
-              onChanged: (value) {
-                setState(() {
-                  _selectedValue = value;
-                  // setSelectedSucursal(value as Sucursal);
-                });
-              },
-            ),
-          ),
-        )
+        GestureDetector(
+            onTap: () => Navigator.of(context).pushNamed('home'),
+            child: SizedBox(
+                height: 50, width: 50, child: Image.asset('Turquessa.png')))
       ],
     );
   }

+ 1 - 0
pubspec.yaml

@@ -76,6 +76,7 @@ flutter:
 
   # To add assets to your application, add an assets section, like this:
   assets:
+    - assets/
     - assets/Turquessa.png
     - assets/logo.png
     - assets/igLogo.png