カテゴリー: プログラム

  • PowerApps Launchを触ってみました

    自作アプリから別の自作アプリへ移動する時Launch関数を使います。

    Launch("url")

    urlにparameter &web=1をつけるとブラウザーで開くことができます。

    Launch("url&web=1")

    Teams内のPowerAppsで作成されたアプリを参照する場合、一度チャネルのタグに登録し、チャネルに認識させないと、アプリオーナー以外のチームメンバーが参照できません。タグ登録した後、タグを削除し、Teams上にアプリ登録し、そのurlを取得し、Launchのparameterとして設定すればアプリオーナー以外のチームメンバーも参照できます。

  • PowerApps Patchを触ってみました

    PowerAppsでJSONデータをテーブルにして、レコードの内容を変更して、テーブルに反映させる。

    まずはJSONの簡単なサンプルを変数_JSONtextにセットします。

    Set(_JSONtext,"[{""A"": ""A1""},{""A"": ""A2""}]")

    ParseJSON関数を使いコレクション_tableにセットします。この時ClearCollectionを使うのが味噌です。Patch関数の第一引数はコレクションなので、単純にSet関数を使ってしまうと、_tableを参照できませんでした。

    ClearCollect(_table,ForAll(ParseJSON(TextBoxJSONSample.Value),{A:Text(ThisRecord.A)}))

    _tableをGallary1のItemsにセットします。

    Gallary1でレコードをSelectされたらレコードの内容を反映させるFormを作成します。FormのDataSourceに_tableをセット、ItemにGallary1.Selectedをセット、DataCardを追加し、その中にTextBox2をセットし、ValueにThisItem.Aをセットします。これでGallary1で選択したレコードのAがTextBox2に表示されます。

    TextBos2の内容を変更し、その変更を_tableに反映させるのにPatch関数を使います。

    Patch(_table,First(Filter(_table,A = Gallery1.Selected.A)),{A: TextBox2.Value})

    この第二引数First(Filter(_table,A = Gallery1.Selected.A))でわかるように、レコードを特定する必要があります。JSONデータを作成するときには重複しないデータをもつプロパティを設定する必要があります。

    コレクションをJSONデータにします。

    Set(_JSONtext,JSON(_table))
  • Swift PencilKitを触ってみました

    下記はPencilKitのSampleソースからの引用である。

    struct DataModel および class DataModelControllerはデータ保存・読込用structおよびclassである。このclass DataModelControllerを実装することで、キャンバスの描画を保存・読込できる。

    /*
    See LICENSE folder for this sample’s licensing information.
    
    Abstract:
    The app's data model for storing drawings, thumbnails, and signatures.
    */
    
    /// Underlying the app's data model is a cross-platform `PKDrawing` object. `PKDrawing` adheres to `Codable`
    /// in Swift, or you can fetch its data representation as a `Data` object through its `dataRepresentation()`
    /// method. `PKDrawing` is the only PencilKit type supported on non-iOS platforms.
    
    /// From `PKDrawing`'s `image(from:scale:)` method, you can get an image to save, or you can transform a
    /// `PKDrawing` and append it to another drawing.
    
    /// If you already have some saved `PKDrawing`s, you can make them available in this sample app by adding them
    /// to the project's "Assets" catalog, and adding their asset names to the `defaultDrawingNames` array below.
    
    import UIKit
    import PencilKit
    import os
    
    /// `DataModel` contains the drawings that make up the data model, including multiple image drawings and a signature drawing.
    struct DataModel: Codable {
        
        /// Names of the drawing assets to be used to initialize the data model the first time.
        static let defaultDrawingNames: [String] = ["Notes"]
        
        /// The width used for drawing canvases.
        static let canvasWidth: CGFloat = 768
        
        /// The drawings that make up the current data model.
        var drawings: [PKDrawing] = []
        var signature = PKDrawing()
    }
    
    /// `DataModelControllerObserver` is the behavior of an observer of data model changes.
    protocol DataModelControllerObserver {
        /// Invoked when the data model changes.
        func dataModelChanged()
    }
    
    /// `DataModelController` coordinates changes to the data  model.
    class DataModelController {
        
        /// The underlying data model.
        var dataModel = DataModel()
        
        /// Thumbnail images representing the drawings in the data model.
        var thumbnails = [UIImage]()
        var thumbnailTraitCollection = UITraitCollection() {
            didSet {
                // If the user interface style changed, regenerate all thumbnails.
                if oldValue.userInterfaceStyle != thumbnailTraitCollection.userInterfaceStyle {
                    generateAllThumbnails()
                }
            }
        }
        
        /// Dispatch queues for the background operations done by this controller.
        private let thumbnailQueue = DispatchQueue(label: "ThumbnailQueue", qos: .background)
        private let serializationQueue = DispatchQueue(label: "SerializationQueue", qos: .background)
        
        /// Observers add themselves to this array to start being informed of data model changes.
        var observers = [DataModelControllerObserver]()
        
        /// The size to use for thumbnail images.
        static let thumbnailSize = CGSize(width: 192, height: 256)
        
        /// Computed property providing access to the drawings in the data model.
        var drawings: [PKDrawing] {
            get { dataModel.drawings }
            set { dataModel.drawings = newValue }
        }
        /// Computed property providing access to the signature in the data model.
        var signature: PKDrawing {
            get { dataModel.signature }
            set { dataModel.signature = newValue }
        }
        
        /// Initialize a new data model.
        init() {
            loadDataModel()
        }
        
        /// Update a drawing at `index` and generate a new thumbnail.
        func updateDrawing(_ drawing: PKDrawing, at index: Int) {
            dataModel.drawings[index] = drawing
            generateThumbnail(index)
            saveDataModel()
        }
        
        /// Helper method to cause regeneration of all thumbnails.
        private func generateAllThumbnails() {
            for index in drawings.indices {
                generateThumbnail(index)
            }
        }
        
        /// Helper method to cause regeneration of a specific thumbnail, using the current user interface style
        /// of the thumbnail view controller.
        private func generateThumbnail(_ index: Int) {
            let drawing = drawings[index]
            let aspectRatio = DataModelController.thumbnailSize.width / DataModelController.thumbnailSize.height
            let thumbnailRect = CGRect(x: 0, y: 0, width: DataModel.canvasWidth, height: DataModel.canvasWidth / aspectRatio)
            let thumbnailScale = UIScreen.main.scale * DataModelController.thumbnailSize.width / DataModel.canvasWidth
            let traitCollection = thumbnailTraitCollection
            
            thumbnailQueue.async {
                traitCollection.performAsCurrent {
                    let image = drawing.image(from: thumbnailRect, scale: thumbnailScale)
                    DispatchQueue.main.async {
                        self.updateThumbnail(image, at: index)
                    }
                }
            }
        }
        
        /// Helper method to replace a thumbnail at a given index.
        private func updateThumbnail(_ image: UIImage, at index: Int) {
            thumbnails[index] = image
            didChange()
        }
        
        /// Helper method to notify observer that the data model changed.
        private func didChange() {
            for observer in self.observers {
                observer.dataModelChanged()
            }
        }
        
        /// The URL of the file in which the current data model is saved.
        private var saveURL: URL {
            let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
            let documentsDirectory = paths.first!
            return documentsDirectory.appendingPathComponent("PencilKitDraw.data")
        }
        
        /// Save the data model to persistent storage.
        func saveDataModel() {
            let savingDataModel = dataModel
            let url = saveURL
            serializationQueue.async {
                do {
                    let encoder = PropertyListEncoder()
                    let data = try encoder.encode(savingDataModel)
                    try data.write(to: url)
                } catch {
                    os_log("Could not save data model: %s", type: .error, error.localizedDescription)
                }
            }
        }
        
        /// Load the data model from persistent storage
        private func loadDataModel() {
            let url = saveURL
            serializationQueue.async {
                // Load the data model, or the initial test data.
                let dataModel: DataModel
                
                if FileManager.default.fileExists(atPath: url.path) {
                    do {
                        let decoder = PropertyListDecoder()
                        let data = try Data(contentsOf: url)
                        dataModel = try decoder.decode(DataModel.self, from: data)
                    } catch {
                        os_log("Could not load data model: %s", type: .error, error.localizedDescription)
                        dataModel = self.loadDefaultDrawings()
                    }
                } else {
                    dataModel = self.loadDefaultDrawings()
                }
                
                DispatchQueue.main.async {
                    self.setLoadedDataModel(dataModel)
                }
            }
        }
        
        /// Construct an initial data model when no data model already exists.
        private func loadDefaultDrawings() -> DataModel {
            var testDataModel = DataModel()
            for sampleDataName in DataModel.defaultDrawingNames {
                guard let data = NSDataAsset(name: sampleDataName)?.data else { continue }
                if let drawing = try? PKDrawing(data: data) {
                    testDataModel.drawings.append(drawing)
                }
            }
            return testDataModel
        }
        
        /// Helper method to set the current data model to a data model created on a background queue.
        private func setLoadedDataModel(_ dataModel: DataModel) {
            self.dataModel = dataModel
            thumbnails = Array(repeating: UIImage(), count: dataModel.drawings.count)
            generateAllThumbnails()
        }
        
        /// Create a new drawing in the data model.
        func newDrawing() {
            let newDrawing = PKDrawing()
            dataModel.drawings.append(newDrawing)
            thumbnails.append(UIImage())
            updateDrawing(newDrawing, at: dataModel.drawings.count - 1)
        }
    }
    

    下記ソースは上記を実装した、キャンバスを実装した描画ビューである。

    /*
    See LICENSE folder for this sample’s licensing information.
    
    Abstract:
    `DrawingViewController` is the primary view controller for showing drawings.
    */
    
    ///`PKCanvasView` is the main drawing view that you will add to your view hierarchy.
    /// The drawingPolicy dictates whether drawing with a finger is allowed.  If it's set to default and if the tool picker is visible,
    /// then it will respect the global finger pencil toggle in Settings or as set in the tool picker.  Otherwise, only drawing with
    /// a pencil is allowed.
    
    /// You can add your own class as a delegate of PKCanvasView to receive notifications after a user
    /// has drawn or the drawing was updated. You can also set the tool or toggle the ruler on the canvas.
    
    /// There is a shared tool picker for each window. The tool picker floats above everything, similar
    /// to the keyboard. The tool picker is moveable in a regular size class window, and fixed to the bottom
    /// in compact size class. To listen to tool picker notifications, add yourself as an observer.
    
    /// Tool picker visibility is based on first responders. To make the tool picker appear, you need to
    /// associate the tool picker with a `UIResponder` object, such as a view, by invoking the method
    /// `UIToolpicker.setVisible(_:forResponder:)`, and then by making that responder become the first
    
    /// Best practices:
    ///
    /// -- Because the tool picker palette is floating and moveable for regular size classes, but fixed to the
    /// bottom in compact size classes, make sure to listen to the tool picker's obscured frame and adjust your UI accordingly.
    
    /// -- For regular size classes, the palette has undo and redo buttons, but not for compact size classes.
    /// Make sure to provide your own undo and redo buttons when in a compact size class.
    
    import UIKit
    import PencilKit
    
    class DrawingViewController: UIViewController, PKCanvasViewDelegate, PKToolPickerObserver, UIScreenshotServiceDelegate {
        
        @IBOutlet weak var canvasView: PKCanvasView!
        @IBOutlet var undoBarButtonitem: UIBarButtonItem!
        @IBOutlet var redoBarButtonItem: UIBarButtonItem!
        @IBOutlet var backLayerButton: UIBarButtonItem!
        @IBOutlet var drawBarButtoniitem: UIBarButtonItem!
    
        var toolPicker: PKToolPicker!
        var signDrawingItem: UIBarButtonItem!
        
        /// On iOS 14.0, this is no longer necessary as the finger vs pencil toggle is a global setting in the toolpicker
        var pencilFingerBarButtonItem: UIBarButtonItem!
    
        /// Standard amount of overscroll allowed in the canvas.
        static let canvasOverscrollHeight: CGFloat = 500
        
        /// Data model for the drawing displayed by this view controller.
        var dataModelController: DataModelController!
        
        /// Private drawing state.
        var drawingIndex: Int = 0
        var hasModifiedDrawing = false
        
    
        
        // MARK: View Life Cycle
        
        /// Set up the drawing initially.
        override func viewWillAppear(_ animated: Bool) {
            super.viewWillAppear(animated)
            
            // Set up the canvas view with the first drawing from the data model.
            canvasView.delegate = self
            canvasView.drawing = dataModelController.drawings[drawingIndex]
            canvasView.alwaysBounceVertical = true
            
    
            // Set up the tool picker
            if #available(iOS 14.0, *) {
                toolPicker = PKToolPicker()
            } else {
                // Set up the tool picker, using the window of our parent because our view has not
                // been added to a window yet.
                let window = parent?.view.window
                toolPicker = PKToolPicker.shared(for: window!)
            }
            
            toolPicker.setVisible(true, forFirstResponder: canvasView)
            toolPicker.addObserver(canvasView)
            toolPicker.addObserver(self)
            updateLayout(for: toolPicker)
            canvasView.becomeFirstResponder()
            
            // Add a button to sign the drawing in the bottom right hand corner of the page
            signDrawingItem = UIBarButtonItem(title: "Sign Drawing", style: .plain, target: self, action: #selector(signDrawing(sender:)))
            navigationItem.rightBarButtonItems?.append(signDrawingItem)
            
            // Before iOS 14, add a button to toggle finger drawing.
            if #available(iOS 14.0, *) { } else {
                pencilFingerBarButtonItem = UIBarButtonItem(title: "Enable Finger Drawing",
                                                            style: .plain,
                                                            target: self,
                                                            action: #selector(toggleFingerPencilDrawing(_:)))
                navigationItem.rightBarButtonItems?.append(pencilFingerBarButtonItem)
                canvasView.allowsFingerDrawing = false
            }
            
            // Always show a back button.
            navigationItem.leftItemsSupplementBackButton = true
            
            // Set this view controller as the delegate for creating full screenshots.
            parent?.view.window?.windowScene?.screenshotService?.delegate = self
        }
        
        /// When the view is resized, adjust the canvas scale so that it is zoomed to the default `canvasWidth`.
        override func viewDidLayoutSubviews() {
            super.viewDidLayoutSubviews()
            
            let canvasScale = canvasView.bounds.width / DataModel.canvasWidth
            canvasView.minimumZoomScale = canvasScale
            canvasView.maximumZoomScale = canvasScale
            canvasView.zoomScale = canvasScale
            
            // Scroll to the top.
            updateContentSizeForDrawing()
            canvasView.contentOffset = CGPoint(x: 0, y: -canvasView.adjustedContentInset.top)
        }
        
        /// When the view is removed, save the modified drawing, if any.
        override func viewWillDisappear(_ animated: Bool) {
            super.viewWillDisappear(animated)
            
            // Update the drawing in the data model, if it has changed.
            if hasModifiedDrawing {
                dataModelController.updateDrawing(canvasView.drawing, at: drawingIndex)
            }
            
            // Remove this view controller as the screenshot delegate.
            view.window?.windowScene?.screenshotService?.delegate = nil
        }
        
        /// Hide the home indicator, as it will affect latency.
        override var prefersHomeIndicatorAutoHidden: Bool {
            return true
        }
        
        // MARK: Actions
        
        /// Action method: Turn finger drawing on or off, but only on devices before iOS 14.0
        @IBAction func toggleFingerPencilDrawing(_ sender: Any) {
            if #available(iOS 14.0, *) { } else {
                canvasView.allowsFingerDrawing.toggle()
                let title = canvasView.allowsFingerDrawing ? "Disable Finger Drawing" : "Enable Finger Drawing"
                pencilFingerBarButtonItem.title = title
            }
        }
        
        /// Helper method to set a new drawing, with an undo action to go back to the old one.
        func setNewDrawingUndoable(_ newDrawing: PKDrawing) {
            let oldDrawing = canvasView.drawing
            undoManager?.registerUndo(withTarget: self) {
                $0.setNewDrawingUndoable(oldDrawing)
            }
            canvasView.drawing = newDrawing
        }
        
        /// Action method: Add a signature to the current drawing.
        @IBAction func signDrawing(sender: UIBarButtonItem) {
            
            // Get the signature drawing at the canvas scale.
            var signature = dataModelController.signature
            let signatureBounds = signature.bounds
            let loc = CGPoint(x: canvasView.bounds.maxX, y: canvasView.bounds.maxY)
            let scaledLoc = CGPoint(x: loc.x / canvasView.zoomScale, y: loc.y / canvasView.zoomScale)
            signature.transform(using: CGAffineTransform(translationX: scaledLoc.x - signatureBounds.maxX, y: scaledLoc.y - signatureBounds.maxY))
    
            // Add the signature drawing to the current canvas drawing.
            setNewDrawingUndoable(canvasView.drawing.appending(signature))
        }
        
        // MARK: Navigation
        
        /// Set up the signature view controller.
        override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
            (segue.destination as? SignatureViewController)?.dataModelController = dataModelController
        }
        
        // MARK: Canvas View Delegate
        
        /// Delegate method: Note that the drawing has changed.
        func canvasViewDrawingDidChange(_ canvasView: PKCanvasView) {
            hasModifiedDrawing = true
            updateContentSizeForDrawing()
        }
        
        /// Helper method to set a suitable content size for the canvas view.
        func updateContentSizeForDrawing() {
            // Update the content size to match the drawing.
            let drawing = canvasView.drawing
            let contentHeight: CGFloat
            
            // Adjust the content size to always be bigger than the drawing height.
            if !drawing.bounds.isNull {
                contentHeight = max(canvasView.bounds.height, (drawing.bounds.maxY + DrawingViewController.canvasOverscrollHeight) * canvasView.zoomScale)
            } else {
                contentHeight = canvasView.bounds.height
            }
            canvasView.contentSize = CGSize(width: DataModel.canvasWidth * canvasView.zoomScale, height: contentHeight)
        }
        
        // MARK: Tool Picker Observer
        
        /// Delegate method: Note that the tool picker has changed which part of the canvas view
        /// it obscures, if any.
        func toolPickerFramesObscuredDidChange(_ toolPicker: PKToolPicker) {
            updateLayout(for: toolPicker)
        }
        
        /// Delegate method: Note that the tool picker has become visible or hidden.
        func toolPickerVisibilityDidChange(_ toolPicker: PKToolPicker) {
            updateLayout(for: toolPicker)
        }
        
        /// Helper method to adjust the canvas view size when the tool picker changes which part
        /// of the canvas view it obscures, if any.
        ///
        /// Note that the tool picker floats over the canvas in regular size classes, but docks to
        /// the canvas in compact size classes, occupying a part of the screen that the canvas
        /// could otherwise use.
        func updateLayout(for toolPicker: PKToolPicker) {
            let obscuredFrame = toolPicker.frameObscured(in: view)
            
            // If the tool picker is floating over the canvas, it also contains
            // undo and redo buttons.
            if obscuredFrame.isNull {
                canvasView.contentInset = .zero
                navigationItem.leftBarButtonItems = []
            }
            
            // Otherwise, the bottom of the canvas should be inset to the top of the
            // tool picker, and the tool picker no longer displays its own undo and
            // redo buttons.
            else {
                canvasView.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: view.bounds.maxY - obscuredFrame.minY, right: 0)
                navigationItem.leftBarButtonItems = [undoBarButtonitem, redoBarButtonItem]
            }
            canvasView.scrollIndicatorInsets = canvasView.contentInset
        }
        
        // MARK: Screenshot Service Delegate
        
        /// Delegate method: Generate a screenshot as a PDF.
        func screenshotService(
            _ screenshotService: UIScreenshotService,
            generatePDFRepresentationWithCompletion completion:
            @escaping (_ PDFData: Data?, _ indexOfCurrentPage: Int, _ rectInCurrentPage: CGRect) -> Void) {
            
            // Find out which part of the drawing is actually visible.
            let drawing = canvasView.drawing
            let visibleRect = canvasView.bounds
            
            // Convert to PDF coordinates, with (0, 0) at the bottom left hand corner,
            // making the height a bit bigger than the current drawing.
            let pdfWidth = DataModel.canvasWidth
            let pdfHeight = drawing.bounds.maxY + 100
            let canvasContentSize = canvasView.contentSize.height - DrawingViewController.canvasOverscrollHeight
            
            let xOffsetInPDF = pdfWidth - (pdfWidth * visibleRect.minX / canvasView.contentSize.width)
            let yOffsetInPDF = pdfHeight - (pdfHeight * visibleRect.maxY / canvasContentSize)
            let rectWidthInPDF = pdfWidth * visibleRect.width / canvasView.contentSize.width
            let rectHeightInPDF = pdfHeight * visibleRect.height / canvasContentSize
            
            let visibleRectInPDF = CGRect(
                x: xOffsetInPDF,
                y: yOffsetInPDF,
                width: rectWidthInPDF,
                height: rectHeightInPDF)
            
            // Generate the PDF on a background thread.
            DispatchQueue.global(qos: .background).async {
                
                // Generate a PDF.
                let bounds = CGRect(x: 0, y: 0, width: pdfWidth, height: pdfHeight)
                let mutableData = NSMutableData()
                UIGraphicsBeginPDFContextToData(mutableData, bounds, nil)
                UIGraphicsBeginPDFPage()
                
                // Generate images in the PDF, strip by strip.
                var yOrigin: CGFloat = 0
                let imageHeight: CGFloat = 1024
                while yOrigin < bounds.maxY {
                    let imgBounds = CGRect(x: 0, y: yOrigin, width: DataModel.canvasWidth, height: min(imageHeight, bounds.maxY - yOrigin))
                    let img = drawing.image(from: imgBounds, scale: 2)
                    img.draw(in: imgBounds)
                    yOrigin += imageHeight
                }
                
                UIGraphicsEndPDFContext()
                
                // Invoke the completion handler with the generated PDF data.
                completion(mutableData as Data, 0, visibleRectInPDF)
            }
        }
        @IBAction func backLayer(_ Sender: Any){
    
        }
    }