From c72351594431759766fd78baa730344d66049b2c Mon Sep 17 00:00:00 2001 From: Michael R Sweet Date: Mon, 6 May 2024 21:24:15 -0400 Subject: [PATCH] Merge changes from flutter branch to master. --- ippevetool/images/default-icon.png | Bin 0 -> 29982 bytes ippevetool/images/missing-icon.png | Bin 0 -> 5427 bytes ippevetool/ios/Podfile.lock | 28 + .../ios/Runner.xcodeproj/project.pbxproj | 88 +-- ippevetool/lib/ipptool.dart | 22 +- ippevetool/lib/main.dart | 595 +++++++++++------- ippevetool/pubspec.yaml | 5 +- 7 files changed, 443 insertions(+), 295 deletions(-) create mode 100644 ippevetool/images/default-icon.png create mode 100644 ippevetool/images/missing-icon.png create mode 100644 ippevetool/ios/Podfile.lock diff --git a/ippevetool/images/default-icon.png b/ippevetool/images/default-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..f4435484a133808462fb7a385dedaf3154158c61 GIT binary patch literal 29982 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�PRLc#aAP`>u?LPuelHRw!FM2V3xnU0k(^R#^0U9nYw*J2lrecOgmrOj#mdRIA$9xDs z1d0DSeIL1Rjh+Pur8Mm`fh?o17S=Pn_6LfkvGER0V*Oq5lKGlNZzn%Ph8KPlfGXVu zT@=ELzHOcHFQ+Epb{5HWE{6T1PhSQfg|A)&-^71NQ^go4dF$2QYHs`~?OS05j4}TYr z{Ux|616`YeAd#CRrJ`WD_s4G7)bXFJ*lvz4e|r3*%@mBK;^fZnxEWS|tDBO0?-6RE z+-IVa*vp{xDDPJ1LCn!(u`JUA)%l9OO8V!KDUZv z!~lA->sRw6I7DKPZ^{(-CT1wYjY?-uhnqV8m0boRy0s zvz|I|I=4Vm+e1o&LtsHHaaZSHY^)I;`LKPUnVirG4D!7YLq)Puy-F!I5_Y4I&e!^Q zF~+WEbXPcAKY$$G4(HTv`narAGmCyW#2zV3qocDLZ!OnJ;K1n_!jQg^h#|Yg_&w0s zts#X5Wgdp=7R=M$l*(V9R~*SAltg>{A;7L$vrmvDxM<+sy({T!r9^fo<4&kr1>w;w z7;C-TrGOG30fhaz93tY{$WAFmZQ?Ok4im$Wa69({MX`0KYu!&f+sN*}6kj)o!PuA? zO@+9k=WEL4${(q5uT4%Etx#=kEH0`i{N4|MPmJ_RR@~WzCV}&7lW* zLc+*N?4Th22i^U(0fsRZI}K*?7Hc)QA%Qm-!49)tky`=JM8fU!m#iyx4=*UvMUrFa z1w#UeCWn9*4Ffil|LgPep5{tfeZ=goFaqOC%TUgI?-#2WdiY^Dc?y-%Ovgt+M7$hO z^cN9hi)gzuGKbh5^EsD_=al`+DrRA`6j_8?luc;pdGvp5u6vez!(#WE158gL5Ci<> P1OQPyQ>jpT_3nQG*G6FO literal 0 HcmV?d00001 diff --git a/ippevetool/images/missing-icon.png b/ippevetool/images/missing-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..941c33be3f3e82a66fc6530432814ccd86e76c1d GIT binary patch literal 5427 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 J7g#aF{|i}?sy+Y! literal 0 HcmV?d00001 diff --git a/ippevetool/ios/Podfile.lock b/ippevetool/ios/Podfile.lock new file mode 100644 index 0000000..a815b42 --- /dev/null +++ b/ippevetool/ios/Podfile.lock @@ -0,0 +1,28 @@ +PODS: + - Flutter (1.0.0) + - nsd_ios (0.0.1): + - Flutter + - url_launcher_ios (0.0.1): + - Flutter + +DEPENDENCIES: + - Flutter (from `Flutter`) + - nsd_ios (from `.symlinks/plugins/nsd_ios/ios`) + - url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`) + +EXTERNAL SOURCES: + Flutter: + :path: Flutter + nsd_ios: + :path: ".symlinks/plugins/nsd_ios/ios" + url_launcher_ios: + :path: ".symlinks/plugins/url_launcher_ios/ios" + +SPEC CHECKSUMS: + Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7 + nsd_ios: 8c37babdc6538e3350dbed3a52674d2edde98173 + url_launcher_ios: 6116280ddcfe98ab8820085d8d76ae7449447586 + +PODFILE CHECKSUM: 4e8f8b2be68aeea4c0d5beb6ff1e79fface1d048 + +COCOAPODS: 1.11.3 diff --git a/ippevetool/ios/Runner.xcodeproj/project.pbxproj b/ippevetool/ios/Runner.xcodeproj/project.pbxproj index 78bf25e..d383ffc 100644 --- a/ippevetool/ios/Runner.xcodeproj/project.pbxproj +++ b/ippevetool/ios/Runner.xcodeproj/project.pbxproj @@ -8,8 +8,8 @@ /* Begin PBXBuildFile section */ 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; + 397FE4DD88782CAF0CC41D73 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0403A1EA6F858123B72BA360 /* Pods_Runner.framework */; }; 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; - 6D31E54F80760CEF04EA28BB /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 55A58647BE0354792F66A4E9 /* Pods_Runner.framework */; }; 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; @@ -30,16 +30,14 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ + 0403A1EA6F858123B72BA360 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; + 16B9A82208C1AC0D3D7FD372 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; - 55A58647BE0354792F66A4E9 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 5BA66091D22CA2FA3B736B6F /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; - 657987B5FD9A103860CED496 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; - 96F2A5109C9D557BDB232624 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -47,6 +45,8 @@ 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + A1734E00AB82CF25054362C9 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; + F83C84EEB56E7149D2DBF3AD /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -54,13 +54,32 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 6D31E54F80760CEF04EA28BB /* Pods_Runner.framework in Frameworks */, + 397FE4DD88782CAF0CC41D73 /* Pods_Runner.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 6C127CA3C58D973B330CFE5E /* Pods */ = { + isa = PBXGroup; + children = ( + 16B9A82208C1AC0D3D7FD372 /* Pods-Runner.debug.xcconfig */, + A1734E00AB82CF25054362C9 /* Pods-Runner.release.xcconfig */, + F83C84EEB56E7149D2DBF3AD /* Pods-Runner.profile.xcconfig */, + ); + name = Pods; + path = Pods; + sourceTree = ""; + }; + 906FECEBDA7E6E9E4A94A6F7 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 0403A1EA6F858123B72BA360 /* Pods_Runner.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; 9740EEB11CF90186004384FC /* Flutter */ = { isa = PBXGroup; children = ( @@ -78,8 +97,8 @@ 9740EEB11CF90186004384FC /* Flutter */, 97C146F01CF9000F007C117D /* Runner */, 97C146EF1CF9000F007C117D /* Products */, - B6125DA08609227B36A6C3F7 /* Pods */, - E4D9A3228420C29FE0215475 /* Frameworks */, + 6C127CA3C58D973B330CFE5E /* Pods */, + 906FECEBDA7E6E9E4A94A6F7 /* Frameworks */, ); sourceTree = ""; }; @@ -106,25 +125,6 @@ path = Runner; sourceTree = ""; }; - B6125DA08609227B36A6C3F7 /* Pods */ = { - isa = PBXGroup; - children = ( - 96F2A5109C9D557BDB232624 /* Pods-Runner.debug.xcconfig */, - 657987B5FD9A103860CED496 /* Pods-Runner.release.xcconfig */, - 5BA66091D22CA2FA3B736B6F /* Pods-Runner.profile.xcconfig */, - ); - name = Pods; - path = Pods; - sourceTree = ""; - }; - E4D9A3228420C29FE0215475 /* Frameworks */ = { - isa = PBXGroup; - children = ( - 55A58647BE0354792F66A4E9 /* Pods_Runner.framework */, - ); - name = Frameworks; - sourceTree = ""; - }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -132,14 +132,14 @@ isa = PBXNativeTarget; buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; buildPhases = ( - 7B5F914E0E3F3C73D9648421 /* [CP] Check Pods Manifest.lock */, + E794F00F453635415E8006A7 /* [CP] Check Pods Manifest.lock */, 9740EEB61CF901F6004384FC /* Run Script */, 97C146EA1CF9000F007C117D /* Sources */, 97C146EB1CF9000F007C117D /* Frameworks */, 97C146EC1CF9000F007C117D /* Resources */, 9705A1C41CF9048500538489 /* Embed Frameworks */, 3B06AD1E1E4923F5004D2608 /* Thin Binary */, - D6B65FE002AC44307B4C9D57 /* [CP] Embed Pods Frameworks */, + 90BB2752E01D58CF153883E3 /* [CP] Embed Pods Frameworks */, ); buildRules = ( ); @@ -214,26 +214,21 @@ shellPath = /bin/sh; shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; }; - 7B5F914E0E3F3C73D9648421 /* [CP] Check Pods Manifest.lock */ = { + 90BB2752E01D58CF153883E3 /* [CP] Embed Pods Frameworks */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", ); - inputPaths = ( - "${PODS_PODFILE_DIR_PATH}/Podfile.lock", - "${PODS_ROOT}/Manifest.lock", - ); - name = "[CP] Check Pods Manifest.lock"; + name = "[CP] Embed Pods Frameworks"; outputFileListPaths = ( - ); - outputPaths = ( - "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; showEnvVarsInLog = 0; }; 9740EEB61CF901F6004384FC /* Run Script */ = { @@ -251,21 +246,26 @@ shellPath = /bin/sh; shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; }; - D6B65FE002AC44307B4C9D57 /* [CP] Embed Pods Frameworks */ = { + E794F00F453635415E8006A7 /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", ); - name = "[CP] Embed Pods Frameworks"; + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; outputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; showEnvVarsInLog = 0; }; /* End PBXShellScriptBuildPhase section */ diff --git a/ippevetool/lib/ipptool.dart b/ippevetool/lib/ipptool.dart index 2371c8b..e9db505 100644 --- a/ippevetool/lib/ipptool.dart +++ b/ippevetool/lib/ipptool.dart @@ -1,5 +1,5 @@ // -// ipptool support functions. +// IPP Everywhere Tool (ippevetool) support functions. // // Copyright © 2024 by the IEEE-ISTO Printer Working Group. // @@ -17,17 +17,27 @@ import 'package:xml/xml.dart'; Future> ipptoolGetAttributes({required String printerUri}) async { var process = await Process.start("ipptool", ["-j", printerUri, "get-printer-attributes.test"]); var json = ""; - process.stderr.pipe(stderr); + var error = ""; await process.stdout .transform(utf8.decoder) .forEach((text) { json = json + text; }); - var result = process.exitCode; + await process.stderr + .transform(utf8.decoder) + .forEach((text) { + error = error + text.replaceAll("\n", " "); + }); + //var result = process.exitCode; //print("result=$result\n"); //print("json=$json\n"); + //print("error=$error\n"); + if (json == "") { + json = "[{},{\"ipptool-error\":\"$error\"}]"; + } + const JsonDecoder decoder = JsonDecoder(); return (decoder.convert(json)[1]); @@ -59,10 +69,10 @@ Future ipptoolRunTest({required String printerUri, required String .forEach((text) { plist = plist + text; }); - var result = process.exitCode; +// var result = process.exitCode; - print("result=$result\n"); - print("plist=$plist\n"); +// print("result=$result\n"); +// print("plist=$plist\n"); return (XmlDocument.parse(plist)); } diff --git a/ippevetool/lib/main.dart b/ippevetool/lib/main.dart index 26d0a68..1fadb29 100644 --- a/ippevetool/lib/main.dart +++ b/ippevetool/lib/main.dart @@ -1,5 +1,16 @@ +// +// IPP Everywhere Tool (ippevetool) main UI. +// +// Copyright © 2022-2024 by the ISTO Printer Working Group. +// +// Licensed under Apache License v2.0. See the file "LICENSE" for more +// information. +// + import 'dart:async'; +import 'dart:collection'; import 'dart:convert'; +import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:nsd/nsd.dart'; @@ -7,291 +18,391 @@ import 'package:url_launcher/url_launcher.dart'; //import 'package:xml/xml.dart'; import 'ipptool.dart'; + +// Main entry - run the main application window... void main() { - runApp(const IppEveToolApp()); + runApp(const IppEveToolApp()); } +void _showAlert(BuildContext context, String message) { + // set up the button + Widget okButton = TextButton( + child: const Text("OK"), + onPressed: () { Navigator.of(context).pop(); }, + ); + + // set up the AlertDialog + AlertDialog alert = AlertDialog( + title: const Text("Alert"), + content: Text(message), + actions: [ + okButton, + ], + ); + + // show the dialog + showDialog( + context: context, + builder: (BuildContext context) { + return alert; + }, + ); +} + + +// Tap handler - copy to the clipboard and open URLs... void _tapValue(BuildContext context, String value) { - if (value.startsWith("http://") || value.startsWith("https://")) { - // Open URL... - launchUrl(Uri.parse(value)); - } - - // Copy to clipboard and let the user know what happened... - Clipboard.setData(ClipboardData(text: value)); - ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text('Copied "$value" to clipboard.'), duration: const Duration(seconds: 1))); + if (value.startsWith("http://") || value.startsWith("https://")) { + // Open URL... + launchUrl(Uri.parse(value)); + } + + // Copy to clipboard and let the user know what happened... + Clipboard.setData(ClipboardData(text: value)); + ScaffoldMessenger.of(context).showSnackBar( + SnackBar(content: + Text('Copied "$value" to clipboard.'), + duration: const Duration(seconds: 1), + ) + ); } +// Main application window... class IppEveToolApp extends StatelessWidget { - const IppEveToolApp({super.key}); - - // This widget is the root of your application. - @override - Widget build(BuildContext context) { - return MaterialApp( - title: 'IPP Everywhere™ Tool', - theme: ThemeData( - // Theme colors are based on the PWG logo colors, which are also used on the PWG web page... - primarySwatch: const MaterialColor(0xff4b5aa8, { - 50: Color(0xff181814), - 100: Color(0xff262d54), - 200: Color(0xff2B397F), - 300: Color(0xff394ba8), - 400: Color(0xff445299), - 500: Color(0xff4b5aa8), - 600: Color(0xff626CA8), - 700: Color(0xff94a4ff), - 800: Color(0xffb8c3ff), - 900: Color(0xffccccc0), - }), - ), - debugShowCheckedModeBanner: false, - home: const IppEveHomePage(title: 'IPP Everywhere™ Tool'), - ); - } + const IppEveToolApp({super.key}); + + @override + Widget build(BuildContext context) { + return MaterialApp( + title: 'IPP Everywhere™ Tool', + theme: ThemeData( + // Theme colors are based on the PWG logo colors, which are also used on the PWG web page... + primarySwatch: const MaterialColor(0xff4b5aa8, { + 50: Color(0xff181814), + 100: Color(0xff262d54), + 200: Color(0xff2B397F), + 300: Color(0xff394ba8), + 400: Color(0xff445299), + 500: Color(0xff4b5aa8), + 600: Color(0xff626CA8), + 700: Color(0xff94a4ff), + 800: Color(0xffb8c3ff), + 900: Color(0xffccccc0), + }), + ), + debugShowCheckedModeBanner: false, + home: const IppEveHomePage(title: 'IPP Everywhere™ Tool'), + ); + } } // Home page with list of printers... class IppEveHomePage extends StatefulWidget { - const IppEveHomePage({super.key, required this.title}); + const IppEveHomePage({super.key, required this.title}); - final String title; + final String title; - @override - State createState() => _IppEveHomePageState(); + @override + State createState() => _IppEveHomePageState(); } class _IppEveHomePageState extends State { - final printers = []; - - Future _startDiscovery() async { - final discovery = await startDiscovery("_ipp._tcp.", autoResolve: true); - discovery.addServiceListener((service, status) { - // print("${service.name} => ${status}"); - if (status == ServiceStatus.found) { - setState((){ printers.add(service); }); - } - }); - return; - } - - @override - void initState() { - super.initState(); - - _startDiscovery(); - } - - @override - Widget build(BuildContext context) { - // This method is rerun every time setState is called, for instance as done - // by the _incrementCounter method above. - // - // The Flutter framework has been optimized to make rerunning build methods - // fast, so that you can just rebuild anything that needs updating rather - // than having to individually change instances of widgets. - return Scaffold( - appBar: AppBar( - // Here we take the value from the IppEveHomePage object that was created by - // the App.build method, and use it to set our appbar title. - title: Text(widget.title), - ), - body: _buildList(context), - ); - } - - _buildList(BuildContext context) { - if (printers.isEmpty) { - return const Center( - child: CircularProgressIndicator(), - ); - } else { - return ListView.builder( - itemBuilder: (context_, index) => GestureDetector( - onTap: () => _onPrinterTap(context, printers[index]), - child: ListTile( - leading: const Icon(Icons.print), - title: Text(printers[index].name ?? "Invalid printer name"), - ), - ), - itemCount: printers.length, - ); + final printers = []; + + Future _startDiscovery() async { + final discovery = await startDiscovery("_ipp._tcp.", autoResolve: true); + discovery.addServiceListener((service, status) { + // print("${service.name} => ${status}"); + if (status == ServiceStatus.found) { + setState((){ + printers.add(service); + printers.sort((a, b) => a.name!.compareTo(b.name!)); + }); + } + }); + return; } - } - _onPrinterTap(BuildContext context, Service printer) { -// print(printer.name); - Navigator.push( - context, - MaterialPageRoute(builder: (context) => IppEveDetailsPage(printer: printer,)), - ); - } + @override + void initState() { + super.initState(); + + _startDiscovery(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + // Here we take the value from the IppEveHomePage object that was created by + // the App.build method, and use it to set our appbar title. + title: Text(widget.title), + ), + body: _buildList(context), + ); + } + + _buildList(BuildContext context) { + if (printers.isEmpty) { + return const Center( + child: CircularProgressIndicator(), + ); + } else { + return ListView.builder( + itemBuilder: (context_, index) => GestureDetector( + onTap: () => _onPrinterTap(context, printers[index]), + child: ListTile( + leading: const Icon(Icons.print), + title: Text(printers[index].name ?? "Invalid printer name"), + ), + ), + itemCount: printers.length, + ); + } + } + + _onPrinterTap(BuildContext context, Service printer) { + Navigator.push( + context, + MaterialPageRoute(builder: (context) => IppEveDetailsPage(printer: printer,)), + ); + } } // Details page for printers... class IppEveDetailsPage extends StatefulWidget { - const IppEveDetailsPage({super.key, required this.printer}); + const IppEveDetailsPage({super.key, required this.printer}); - final Service printer; + final Service printer; - @override - State createState() => _IppEveDetailsPageState(); + @override + State createState() => _IppEveDetailsPageState(); } class _IppEveDetailsPageState extends State { - var attrList = []; - - @override - void initState() { - super.initState(); - - _getAttrList(widget.printer); - } - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - title: Text(widget.printer.name ?? "Unknown"), - ), - body: SingleChildScrollView( - child: Expanded(child: Column( - children: [ - Row(children: [ - Image.network("http://www.pwg.org/ipp/ipp-everywhere.png", - width: 160, - ), - const Text( - "idle, accepting jobs\n'printer state message'\nmedia-empty, toner-low, cover-open", - textScaleFactor: 1.5, - ), - ]), - const Row(children: [ - Text(" TXT Record:", textAlign: TextAlign.left, style: TextStyle(fontWeight: FontWeight.bold)), - ]), - Row(children: [ - DataTable(columns: const [ - DataColumn(label: SizedBox(width: 100,child: Text("Key"),)), - DataColumn(label: Expanded(child: Text("Value"))), - ], - rows: _buildTxtRows(widget.printer.txt), - ), - ]), - - // IPP Attributes - const Row(children: [ - Text(" IPP Attributes:", textAlign: TextAlign.left, style: TextStyle(fontWeight: FontWeight.bold)), - ]), - Row(children: [ - DataTable(columns: const [ - DataColumn(label: SizedBox(width: 100,child: Text("Name"),)), - DataColumn(label: Expanded(child: Text("Value"))), + Map printerAttrs = {}; + var printerIcon = Image.asset("images/default-icon.png", width:160); + var printerState = "Unknown"; + var printerUri = "unknown"; + TextEditingController txtController = TextEditingController(); + String txtSearch = ""; + TextEditingController ippController = TextEditingController(); + String ippSearch = ""; + + @override + void initState() { + super.initState(); + + _getAttrList(widget.printer); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text(widget.printer.name ?? "Unknown"), + actions: [ + TextButton( + onPressed: () { + _showAlert(context, "Print File UI"); + }, + child: const Text('Print File'), + ), + TextButton( + onPressed: () { + _showAlert(context, "Run Test UI"); + }, + child: const Text('Run Test'), + ), + TextButton( + onPressed: () { + _showAlert(context, "Run Self-Cert UI"); + }, + child: const Text('Run Self-Cert'), + ), ], - rows: attrList, - ), - ]), - -// ListView(// Print File -// children: [ -// ], -// ), -// ListView(// Self-Certification -// children: [ -// ], -// ), -// ], -// ), - ]), - ), - ), - bottomNavigationBar: BottomNavigationBar( - items: const [ - BottomNavigationBarItem( - icon: Icon(Icons.home), - label: "Overview", - ), - BottomNavigationBarItem( - icon: Icon(Icons.list), - label: "IPP", - tooltip: "IPP Attributes", - ), - BottomNavigationBarItem( - icon: Icon(Icons.print), - label: "Print", - tooltip: "Print File", - ), - BottomNavigationBarItem( - icon: Icon(Icons.run_circle), - label: "Self-Cert", - tooltip: "Self-Certification", - ), - ], - currentIndex: 0, - selectedItemColor: const Color(0xff4b5aa8), - unselectedItemColor: const Color(0xff94a4ff), - ), - ); - } - - // Build a list of attribute name and value data rows - Future _getAttrList(Service printer) async { - if (printer.host != null && printer.port != null && printer.txt != null) { - // Have a hostname, port, and TXT record... - var rp = "/ipp/print"; - - if (printer.txt!["rp"] != null) { - // Use the "rp" value from the TXT record... - Uint8List rpraw = printer.txt!["rp"]!; - rp = const Utf8Decoder().convert(rpraw); - if (rp[0] != '/') { - rp = "/$rp"; - } - } + ), + body: SingleChildScrollView(child: Column(children: [ + Row(children: [ + const Spacer(), + printerIcon, + const Spacer(), + ]), + Row(children: [ + const Spacer(), + const Text("State: ", style: TextStyle(fontWeight: FontWeight.bold)), + Text(printerState), + const Spacer(), + ]), + Row(children: [ + const Spacer(), + const Text("URI: ", style: TextStyle(fontWeight: FontWeight.bold)), + GestureDetector( + child: Text(printerUri, style: const TextStyle(color: Color(0xff4b5aa8))), + onTap: (){ _tapValue(context, printerUri); }, + ), + const Spacer(), + ]), + + // Divider between sections... + const Divider(color: Color(0xff4b5aa8), height: 20.0, thickness: 2.0), + + Row(children: [ + const Spacer(), + const Text("TXT Record: ", style: TextStyle(fontWeight: FontWeight.bold)), + SizedBox( + width: 400, + child: CupertinoSearchTextField( + controller: txtController, + onChanged: (String value) async { + setState(() { + txtSearch = value; + }); + }, + ), + ), + const Spacer(), + ]), + DataTable( + columns: const [ + DataColumn(label: SizedBox(width: 100,child: Text("Key"),)), + DataColumn(label: Expanded(child: Text("Value"))), + ], + rows: _buildTxtRows(widget.printer.txt, txtSearch), + ), + + // Divider between sections... + const Divider(color: Color(0xff4b5aa8), height: 20.0, thickness: 2.0), + + // IPP Attributes + Row(children: [ + const Spacer(), + const Text("IPP Attributes: ", style: TextStyle(fontWeight: FontWeight.bold)), + SizedBox( + width: 400, + child: CupertinoSearchTextField( + controller: ippController, + onChanged: (String value) async { + setState(() { + ippSearch = value; + }); + }, + ), + ), + const Spacer(), + ]), + DataTable( + columns: const [ + DataColumn(label: SizedBox(width: 100,child: Text("Name"),)), + DataColumn(label: Expanded(child: Text("Value"))), + ], + rows: _buildAttrRows(printerAttrs, ippSearch), + ), + ])), + ); + } - // Build the printer URI... - var uri = "ipp://${printer.host}:${printer.port}$rp"; - //print("printer URI = $uri\n"); - // Get the attributes as a JSON object - ipptoolGetAttributes(printerUri: uri).then((attrs){ + // Build the filtered rows of attributes + List _buildAttrRows(Map attrs, String search) { var list = []; - attrs.forEach((key,value){ - //print("'$key' = '$value'\n"); + var sortedAttrs = SplayTreeMap.from(attrs, (k1, k2) => k1.compareTo(k2)); + + sortedAttrs.forEach((key,value){ + if (key != "group-tag" && (search == "" || key.contains(search) || "$value".contains(search))) { + list.add(DataRow(cells: [ + DataCell(Text(key)), + DataCell(Expanded(child: Text("$value", softWrap: true)), onTap:(){ _tapValue(context, "$value"); }), + ])); + } + }); - if (key != "group-tag") { + return (list); + } + + + // Build the filtered rows of TXT record keys/values + List _buildTxtRows(Map? txt, String search) { + var list = [ ]; + + if (txt != null) { + var sortedTxt = SplayTreeMap.from(txt, (k1, k2) => k1.compareTo(k2)); + sortedTxt.forEach((key,value){ + var svalue = ""; + if (value != null) { + svalue = const Utf8Decoder().convert(value); + } + + // Filter using search string + if (search == "" || key.contains(search) || svalue.contains(search)) { list.add(DataRow(cells: [ - DataCell(Text(key)), - DataCell(Expanded(child: Text("$value", softWrap: true)), onTap:(){ _tapValue(context, "$value"); }), + DataCell(Text(key)), + DataCell(Expanded(child: Text(svalue, softWrap: true)), onTap:(){ _tapValue(context, svalue); }), ])); } }); + } - setState((){ - attrList = list; - }); - }); + return (list); } - } - List _buildTxtRows(Map? txt) { - var list = [ ]; - if (txt != null) { - txt.forEach((key,value){ - var svalue = ""; - if (value != null) { - svalue = const Utf8Decoder().convert(value); + // Get a list of attribute name and value data rows + Future _getAttrList(Service printer) async { + if (printer.host != null && printer.port != null && printer.txt != null) { + // Have a hostname, port, and TXT record... + var rp = "/ipp/print"; + + if (printer.txt!["rp"] != null) { + // Use the "rp" value from the TXT record... + Uint8List rpraw = printer.txt!["rp"]!; + rp = const Utf8Decoder().convert(rpraw); + if (rp[0] != '/') { + rp = "/$rp"; + } } - list.add(DataRow(cells: [ - DataCell(Text(key)), - DataCell(Expanded(child: Text(svalue, softWrap: true)), onTap:(){ _tapValue(context, svalue); }), - ])); - }); + // Build the printer URI... + var uri = "ipp://${printer.host}:${printer.port}$rp"; + //print("printer URI = $uri\n"); + + // Get the attributes as a JSON object + ipptoolGetAttributes(printerUri: uri).then((attrs){ + var icon = ""; + var state = "Unknown"; + var stateReasons = ""; + + attrs.forEach((key,value){ + //print("'$key' = '$value'\n"); + + if (key == "printer-icons") { + icon = value.last; + } else if (key == "printer-state") { + if (value == 3) { + state = "Idle"; + } else if (value == 4) { + state = "Processing"; + } else { + state = "Stopped"; + } + } else if (key == "printer-state-reasons" && value != "none") { + stateReasons = ", $value"; + } + }); + + setState((){ + printerAttrs = attrs; + if (icon != "") { + printerIcon = Image.network(icon, width: 160); + } else { + printerIcon = Image.asset("images/missing-icon.png", width: 160); + } + printerState = "$state$stateReasons"; + printerUri = uri; + }); + }); + } } - - return (list); - } } diff --git a/ippevetool/pubspec.yaml b/ippevetool/pubspec.yaml index 889f59f..0af2b37 100644 --- a/ippevetool/pubspec.yaml +++ b/ippevetool/pubspec.yaml @@ -71,9 +71,8 @@ flutter: uses-material-design: true assets: - - ../libcups/tools/printer.png - - ../libcups/tools/printer-lg.png - - ../libcups/tools/printer-sm.png + - images/default-icon.png + - images/missing-icon.png # To add assets to your application, add an assets section, like this: # assets: