{"id":13694339,"url":"https://github.com/FlexMonkey/Plum-O-Meter","last_synced_at":"2025-05-03T01:32:43.879Z","repository":{"id":46413214,"uuid":"44866240","full_name":"FlexMonkey/Plum-O-Meter","owner":"FlexMonkey","description":"3D Touch Application for Weighing Plums (and other small fruit!)","archived":false,"fork":false,"pushed_at":"2021-10-15T12:20:21.000Z","size":163,"stargazers_count":529,"open_issues_count":9,"forks_count":66,"subscribers_count":54,"default_branch":"master","last_synced_at":"2024-11-07T07:13:28.771Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/FlexMonkey.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2015-10-24T13:04:01.000Z","updated_at":"2024-10-10T09:42:57.000Z","dependencies_parsed_at":"2022-09-23T00:31:46.963Z","dependency_job_id":null,"html_url":"https://github.com/FlexMonkey/Plum-O-Meter","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/FlexMonkey%2FPlum-O-Meter","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/FlexMonkey%2FPlum-O-Meter/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/FlexMonkey%2FPlum-O-Meter/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/FlexMonkey%2FPlum-O-Meter/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/FlexMonkey","download_url":"https://codeload.github.com/FlexMonkey/Plum-O-Meter/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":224346551,"owners_count":17296237,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-02T17:01:29.785Z","updated_at":"2024-11-12T20:32:07.983Z","avatar_url":"https://github.com/FlexMonkey.png","language":"Swift","funding_links":[],"categories":["Misc"],"sub_categories":["Notes"],"readme":"# Plum-O-Meter\n###3D Touch Application for Weighing Plums (and other small fruit!)\n\n##### _Companion project to this blog post: http://flexmonkey.blogspot.co.uk/2015/10/the-plum-o-meter-weighing-plums-using.html_\n\nHere at FlexMonkey Towers, the ever beautiful Mrs FlexMonkey and I love to spend our Sunday mornings luxuriating in bed drinking Mimosas, listening to The Archers omnibus and eating some lovely plums. Being a generous sort of chap, whenever I pull a pair of plums from the freshly delivered Fortnum \u0026 Mason's hamper, I always try to ensure she has the larger of the two. However, this isn't always easy, especially after the third of fourth breakfast cocktail.\n\n3D Touch to the rescue! My latest app, the Plum-O-Meter, has been specifically designed to solve this problem. Simply place two delicious plums on the iPhone's screen and the heavier of the two is highlighted in yellow so you can hand it to your beloved without fear of being thought of as a greedy-guts.\n\n##Lay your plums on me\n\nPlum-O-Meter is pretty simple stuff: when its view controller's `touchesBegan` is called, it  adds a new `CircleWithLabel` to its view's layer for each touch. `CircleWithLabel` is a `CAShapeLayer` which draws a circle and has an additional `CATextLayer`. This new layer is added to a dictionary with the touch as the key. The force of the touch is used to control the new layer's radius and is displayed in the label:\n\n```swift\n    var circles = [UITouch: CircleWithLabel]()\n\n    override func touchesBegan(touches: Set\u003cUITouch\u003e, withEvent event: UIEvent?)\n    {\n        label.hidden = true\n        \n        for touch in touches\n        {\n            let circle = CircleWithLabel()\n            \n            circle.drawAtPoint(touch.locationInView(view),\n                force: touch.force / touch.maximumPossibleForce)\n            \n            circles[touch] = circle\n            view.layer.addSublayer(circle)\n        }\n        \n        highlightHeaviest()\n    }\n```\n\nWhen the touches move, that dictionary is used to update the relevant `CircleWithLabel` for the touch and update its radius and label:\n\n```swift\n    override func touchesMoved(touches: Set\u003cUITouch\u003e, withEvent event: UIEvent?)\n    {\n        for touch in touches where circles[touch] != nil\n        {\n            let circle = circles[touch]!\n            \n            circle.drawAtPoint(touch.locationInView(view),\n                force: touch.force / touch.maximumPossibleForce)\n        }\n        \n        highlightHeaviest()\n    }\n```\n\nBoth of these methods call `highlightHeaviest()`. This method loops over every touch/layer item in the circles dictionary and sets the `isMax` property on each based on a version of the dictionary sorted by touch force:\n\n```swift\n    func highlightHeaviest()\n    {\n        func getMaxTouch() -\u003e UITouch?\n        {\n            return circles.sort({\n                (a: (UITouch, CircleWithLabel), b: (UITouch, CircleWithLabel)) -\u003e Bool in\n                \n                return a.0.force \u003e b.0.force\n            }).first?.0\n        }\n        \n        circles.forEach\n        {\n            $0.1.isMax = $0.0 == getMaxTouch()\n        }\n    }\n```\n\n`isMax` sets the layer's fill colour to yellow if true.\n\nWhen a plum is removed from the screen, its `CircleWithLabel` layer is removed and the relevant entry removed from the circles dictionary. Because the heaviest needs to be recalucated, `highlightHeaviest` is also invoked:\n\n```\n    override func touchesEnded(touches: Set\u003cUITouch\u003e, withEvent event: UIEvent?)\n    {\n        for touch in touches where circles[touch] != nil\n        {\n            let circle = circles[touch]!\n            \n            circles.removeValueForKey(touch)\n            circle.removeFromSuperlayer()\n        }\n        \n        highlightHeaviest()\n    }\n```\n\n##In Conclusion\n\nThe value displayed is actually the normalised force as a percentage. It's interesting to see that it changes depending on other forces acting upon the screen which to me indicates that the 6s isn't going to replace your high precision electronic scales. What this demo does show is that the 6s can handle multiple touch points each with a decent value for their relative forces.\n\nI did originally build this app for grapes, but they're too light to activate the 3D Touch. Of course, you can also use your fingers :)\n\nOf course, for such an important piece of software, I've made the source code available at my GitHub repository here. Enjoy! \n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FFlexMonkey%2FPlum-O-Meter","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FFlexMonkey%2FPlum-O-Meter","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FFlexMonkey%2FPlum-O-Meter/lists"}