[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"navigation":3,"url-settings":86,"blog-\u002Fblog\u002Fusing-mvvm-architecture-in-flutter":671,"blog-author-\u002Fblog\u002Fusing-mvvm-architecture-in-flutter":2271,"i-material-symbols:arrow-back-rounded":2286},{"id":4,"extension":5,"footer":6,"header":73,"meta":83,"stem":84,"__hash__":85},"navigation\u002Fdata\u002Fshared\u002Fnavigation.yml","yml",{"brand":7,"columns":13,"legal":63},{"name":8,"tagline":9,"downloadCta":10},"Pieces","The memory layer for modern work.",{"label":11,"href":12},"All downloads","\u002Fdownloads",[14,26,39,51],{"title":15,"links":16},"Product",[17,20,23],{"label":18,"href":19},"Pieces Desktop","\u002F",{"label":21,"href":22},"Pieces Enterprise","\u002Fenterprise",{"label":24,"href":25},"Pieces MCP","\u002Fmcp",{"title":27,"links":28},"Resources",[29,33,36],{"label":30,"href":31,"external":32},"Documentation","url:docs.home",true,{"label":34,"href":35},"Blog","\u002Fblog",{"label":37,"href":38,"external":32},"GitHub","url:github.org",{"title":40,"links":41},"Community",[42,45,48],{"label":43,"href":44,"external":32},"Discord","url:social.discord",{"label":46,"href":47,"external":32},"X \u002F Twitter","url:social.x",{"label":49,"href":50,"external":32},"LinkedIn","url:social.linkedin",{"title":52,"links":53},"Company",[54,57,60],{"label":55,"href":56},"About","\u002Fabout",{"label":58,"href":59},"Updates","\u002Fupdates",{"label":61,"href":62},"Contact","\u002Fcontact",[64,67,70],{"label":65,"href":66},"Privacy Policy","\u002Flegal\u002Fprivacy",{"label":68,"href":69},"Refund Policy","\u002Flegal\u002Frefund",{"label":71,"href":72},"Terms of Service","\u002Flegal\u002Fterms",{"links":74,"signIn":75,"contact":78,"cta":80},[],{"label":76,"href":77},"Manage account","url:portal.home",{"label":79,"href":62},"Get in touch",{"label":81,"href":82},"Download","url:routes.downloads",{},"data\u002Fshared\u002Fnavigation","XlSALC7vYCXHcmcXnjJViwIZKsqnQWF4bn4o9RrcSBE",{"id":87,"extension":5,"links":88,"meta":668,"stem":669,"__hash__":670},"urlSettings\u002Fdata\u002Fshared\u002Furls.yml",[89,93,97,101,105,109,113,117,121,125,129,133,137,141,145,149,153,157,161,165,169,173,177,181,185,189,192,196,200,204,208,212,216,220,224,228,232,236,240,244,248,252,256,260,264,268,272,276,280,284,288,292,296,300,303,307,311,314,318,322,326,330,334,338,342,346,350,354,358,362,366,370,374,378,382,386,390,394,398,402,406,410,414,418,422,426,430,434,438,442,446,450,454,458,461,465,469,473,477,481,485,488,491,494,497,501,505,508,512,516,520,524,528,532,536,540,544,548,552,556,559,563,567,571,575,579,582,585,588,592,595,599,603,607,611,614,618,622,625,628,631,635,639,643,646,649,652,656,660,664],{"key":90,"label":91,"href":92},"downloads.desktop","Desktop download page","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fdesktop\u002Fdownload",{"key":94,"label":95,"href":96},"downloads.macOS.dmgArm64","macOS DMG Apple Silicon","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fpieces_for_x\u002Fdmg-arm64\u002Fdownload",{"key":98,"label":99,"href":100},"downloads.macOS.dmgIntel","macOS DMG Intel","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fpieces_for_x\u002Fdmg\u002Fdownload",{"key":102,"label":103,"href":104},"downloads.macOS.pkg","macOS PKG","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fmacos_packaging\u002Fpkg\u002Fdownload",{"key":106,"label":107,"href":108},"downloads.macOS.universal","Desktop macOS Universal","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fpieces_for_x\u002Fmacos-universal\u002Fdownload",{"key":110,"label":111,"href":112},"downloads.macOS.pkgArm64","Desktop macOS PKG Apple Silicon","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fmacos_packaging\u002Fpkg-pfd-arm64\u002Fdownload",{"key":114,"label":115,"href":116},"downloads.macOS.pkgIntel","Desktop macOS PKG Intel","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fmacos_packaging\u002Fpkg-pfd\u002Fdownload",{"key":118,"label":119,"href":120},"downloads.windows.appinstaller","Windows App Installer","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fappinstaller\u002Fpieces_for_x.appinstaller",{"key":122,"label":123,"href":124},"downloads.windows.exe","Windows EXE","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fpieces_for_x\u002Fwindows-exe\u002Fdownload",{"key":126,"label":127,"href":128},"downloads.windows.msix","Windows MSIX","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fpieces_for_x\u002Fwindows-msix\u002Fdownload",{"key":130,"label":131,"href":132},"downloads.windows.suiteManager","Windows Suite Manager","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fpieces_suite_windows\u002Fappinstaller\u002Fdownload",{"key":134,"label":135,"href":136},"downloads.linux.flatpakRepo","Linux Flatpak repository","https:\u002F\u002Fbuilds.pieces.app\u002Fpieces-flatpak-repo\u002Fpieces-flatpak.flatpakrepo",{"key":138,"label":139,"href":140},"downloads.linux.snapDesktop","Linux Snap Desktop","https:\u002F\u002Fsnapcraft.io\u002Fpieces-for-developers",{"key":142,"label":143,"href":144},"downloads.linux.snapPiecesOS","Linux Snap PiecesOS","https:\u002F\u002Fsnapcraft.io\u002Fpieces-os",{"key":146,"label":147,"href":148},"downloads.linux.snap","Desktop Linux Snap package","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fpieces_for_x\u002Fsnap\u002Fdownload",{"key":150,"label":151,"href":152},"downloads.piecesOS.macOS.dmgArm64","PiecesOS macOS DMG Apple Silicon","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fos_server\u002Fdmg-arm64\u002Fdownload",{"key":154,"label":155,"href":156},"downloads.piecesOS.macOS.dmgIntel","PiecesOS macOS DMG Intel","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fos_server\u002Fdmg\u002Fdownload",{"key":158,"label":159,"href":160},"downloads.piecesOS.macOS.universal","PiecesOS macOS Universal","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fos_server\u002Fmacos-universal\u002Fdownload",{"key":162,"label":163,"href":164},"downloads.piecesOS.macOS.pkgArm64","PiecesOS macOS PKG Apple Silicon","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fmacos_packaging\u002Fpkg-pos-launch-only-arm64\u002Fdownload",{"key":166,"label":167,"href":168},"downloads.piecesOS.macOS.pkgIntel","PiecesOS macOS PKG Intel","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fmacos_packaging\u002Fpkg-pos-launch-only\u002Fdownload",{"key":170,"label":171,"href":172},"downloads.piecesOS.windows.appinstaller","PiecesOS Windows App Installer","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fappinstaller\u002Fos_server.appinstaller",{"key":174,"label":175,"href":176},"downloads.piecesOS.windows.exe","PiecesOS Windows EXE","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fos_server\u002Fwindows-exe\u002Fdownload",{"key":178,"label":179,"href":180},"downloads.piecesOS.windows.msix","PiecesOS Windows MSIX","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fos_server\u002Fwindows-msix\u002Fdownload",{"key":182,"label":183,"href":184},"downloads.piecesOS.linux.snap","PiecesOS Linux Snap package","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fos_server\u002Fsnap\u002Fdownload",{"key":186,"label":187,"href":188},"downloads.combined.macOS.appleSilicon","Combined macOS installer Apple Silicon","https:\u002F\u002Fbuilds.pieces.app\u002Fstages\u002Fproduction\u002Fmacos_packaging\u002Fpkg-arm64\u002Fdownload",{"key":190,"label":191,"href":104},"downloads.combined.macOS.intel","Combined macOS installer Intel",{"key":193,"label":194,"href":195},"downloads.guides.macOS","macOS installation guide","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmeet-pieces\u002Fmacos-installation-guide",{"key":197,"label":198,"href":199},"downloads.guides.windows","Windows installation guide","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmeet-pieces\u002Fwindows-installation-guide",{"key":201,"label":202,"href":203},"downloads.guides.linux","Linux installation guide","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmeet-pieces\u002Flinux-installation-guide",{"key":205,"label":206,"href":207},"downloads.guides.linuxFlatpak","Linux Flatpak installation guide","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmeet-pieces\u002Flinux-installation-guide\u002Fflatpak",{"key":209,"label":210,"href":211},"downloads.guides.linuxSnap","Linux Snap installation guide","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmeet-pieces\u002Flinux-installation-guide\u002Fsnap",{"key":213,"label":214,"href":215},"downloads.guides.piecesOS","PiecesOS manual installation","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fcore-dependencies\u002Fpieces-os\u002Fmanual-installation",{"key":217,"label":218,"href":219},"extensions.chrome","Chrome extension","https:\u002F\u002Fchrome.google.com\u002Fwebstore\u002Fdetail\u002Fpieces-save-code-snippets\u002Figbgibhbfonhmjlechmeefimncpekepm",{"key":221,"label":222,"href":223},"extensions.firefox","Firefox add-on","https:\u002F\u002Faddons.mozilla.org\u002Fen-US\u002Ffirefox\u002Faddon\u002Fpieces-save-code-from-the-web\u002F",{"key":225,"label":226,"href":227},"extensions.edge","Edge add-on","https:\u002F\u002Fmicrosoftedge.microsoft.com\u002Faddons\u002Fdetail\u002Fpieces-save-code-snippet\u002Fhglfimcdgonaeeobjckfdabcldfidmim",{"key":229,"label":230,"href":231},"extensions.vscode","VS Code extension","https:\u002F\u002Fmarketplace.visualstudio.com\u002Fitems?itemName=MeshIntelligentTechnologiesInc.pieces-vscode",{"key":233,"label":234,"href":235},"extensions.visualStudio","Visual Studio extension","https:\u002F\u002Fmarketplace.visualstudio.com\u002Fitems?itemName=MeshIntelligentTechnologiesInc.PiecesVisualStudio",{"key":237,"label":238,"href":239},"extensions.jetbrains","JetBrains plugin","https:\u002F\u002Fplugins.jetbrains.com\u002Fplugin\u002F17328-pieces--save-search-share--reuse-code-snippets",{"key":241,"label":242,"href":243},"extensions.obsidian","Obsidian plugin","https:\u002F\u002Fobsidian.md\u002Fplugins?id=pieces-for-developers",{"key":245,"label":246,"href":247},"extensions.sublime","Sublime package","https:\u002F\u002Fpackagecontrol.io\u002Fpackages\u002FPieces",{"key":249,"label":250,"href":251},"extensions.neovim","Neovim plugin","https:\u002F\u002Fgithub.com\u002Fpieces-app\u002Fplugin_neo_vim",{"key":253,"label":254,"href":255},"extensions.jupyterlab","JupyterLab plugin","https:\u002F\u002Fgithub.com\u002Fpieces-app\u002Fjupyterlab-pieces",{"key":257,"label":258,"href":259},"extensions.cli","Pieces CLI","https:\u002F\u002Fpypi.org\u002Fproject\u002Fpieces-cli\u002F",{"key":261,"label":262,"href":263},"docs.home","Documentation home","https:\u002F\u002Fdocs.pieces.app",{"key":265,"label":266,"href":267},"docs.getStarted","Get started docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmeet-pieces",{"key":269,"label":270,"href":271},"docs.api","API docs","https:\u002F\u002Fdocs.pieces.app\u002Fapi",{"key":273,"label":274,"href":275},"docs.desktop.overview","Desktop overview","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fdesktop",{"key":277,"label":278,"href":279},"docs.desktop.onboarding","Desktop onboarding","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fdesktop\u002Fonboarding",{"key":281,"label":282,"href":283},"docs.desktop.timeline","Desktop timeline docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fdesktop\u002Ftimeline",{"key":285,"label":286,"href":287},"docs.desktop.summaries","Desktop summaries docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fdesktop\u002Fsingle-click-summaries",{"key":289,"label":290,"href":291},"docs.desktop.search","Desktop conversational search docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fdesktop\u002Fconversational-search",{"key":293,"label":294,"href":295},"docs.desktop.drive","Desktop drive docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fdesktop\u002Fdrive",{"key":297,"label":298,"href":299},"docs.desktop.account","Desktop account settings docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fdesktop\u002Fconfiguration\u002Faccount",{"key":301,"label":302,"href":92},"docs.desktop.download","Desktop download docs",{"key":304,"label":305,"href":306},"docs.piecesOS.overview","PiecesOS overview docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fcore-dependencies",{"key":308,"label":309,"href":310},"docs.piecesOS.details","PiecesOS details docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fcore-dependencies\u002Fpieces-os",{"key":312,"label":313,"href":215},"docs.piecesOS.install","PiecesOS install docs",{"key":315,"label":316,"href":317},"docs.piecesOS.quickMenu","PiecesOS quick menu docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fcore-dependencies\u002Fpieces-os\u002Fquick-menu",{"key":319,"label":320,"href":321},"docs.piecesOS.storage","On-device storage docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fcore-dependencies\u002Fon-device-storage",{"key":323,"label":324,"href":325},"docs.piecesOS.troubleshooting","PiecesOS troubleshooting docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fcore-dependencies\u002Fpieces-os\u002Ftroubleshooting",{"key":327,"label":328,"href":329},"docs.mcp.overview","MCP overview docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp",{"key":331,"label":332,"href":333},"docs.mcp.cursor","MCP Cursor docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fcursor",{"key":335,"label":336,"href":337},"docs.mcp.vscode","MCP VS Code docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fvs-code",{"key":339,"label":340,"href":341},"docs.mcp.claudeDesktop","MCP Claude Desktop docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fclaude-desktop",{"key":343,"label":344,"href":345},"docs.mcp.claudeCode","MCP Claude Code docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fclaude-code",{"key":347,"label":348,"href":349},"docs.mcp.claudeCowork","MCP Claude Cowork docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fclaude-cowork",{"key":351,"label":352,"href":353},"docs.mcp.githubCopilot","MCP GitHub Copilot docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fgithub-copilot",{"key":355,"label":356,"href":357},"docs.mcp.goose","MCP Goose docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fgoose",{"key":359,"label":360,"href":361},"docs.mcp.windsurf","MCP Windsurf docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fwindsurf",{"key":363,"label":364,"href":365},"docs.mcp.zed","MCP Zed docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fzed",{"key":367,"label":368,"href":369},"docs.mcp.jetbrains","MCP JetBrains docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fjetbrains-ides",{"key":371,"label":372,"href":373},"docs.mcp.continueDev","MCP Continue docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fcontinue-dev",{"key":375,"label":376,"href":377},"docs.mcp.cline","MCP Cline docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fcline",{"key":379,"label":380,"href":381},"docs.mcp.raycast","MCP Raycast docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fraycast",{"key":383,"label":384,"href":385},"docs.mcp.rovoDevCli","MCP Rovo Dev CLI docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Frovo-dev-cli",{"key":387,"label":388,"href":389},"docs.mcp.openaiCodexCli","MCP OpenAI Codex CLI docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fopenai-codex-cli",{"key":391,"label":392,"href":393},"docs.mcp.googleGeminiCli","MCP Google Gemini CLI docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fgoogle-gemini-cli",{"key":395,"label":396,"href":397},"docs.mcp.amazonQ","MCP Amazon Q docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Famazon-q-developer",{"key":399,"label":400,"href":401},"docs.mcp.chatgptDev","MCP ChatGPT Developer Mode docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fchatgpt-developer-mode",{"key":403,"label":404,"href":405},"docs.mcp.openclaw","MCP OpenClaw docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fopenclaw",{"key":407,"label":408,"href":409},"docs.mcp.mcpRemote","MCP Remote docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fmcp-remote",{"key":411,"label":412,"href":413},"docs.mcp.ngrok","MCP ngrok docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmcp\u002Fngrok-setup",{"key":415,"label":416,"href":417},"docs.troubleshooting.macOS","macOS troubleshooting docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmeet-pieces\u002Ftroubleshooting\u002Fmacos",{"key":419,"label":420,"href":421},"docs.troubleshooting.windows","Windows troubleshooting docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmeet-pieces\u002Ftroubleshooting\u002Fwindows",{"key":423,"label":424,"href":425},"docs.troubleshooting.linux","Linux troubleshooting docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fmeet-pieces\u002Ftroubleshooting\u002Flinux",{"key":427,"label":428,"href":429},"docs.privacy","Privacy and security docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fprivacy-security-your-data",{"key":431,"label":432,"href":433},"docs.support","Support docs","https:\u002F\u002Fdocs.pieces.app\u002Fproducts\u002Fsupport",{"key":435,"label":436,"href":437},"portal.home","Pieces portal","https:\u002F\u002Fportal.pieces.app",{"key":439,"label":440,"href":441},"site.home","Website home","https:\u002F\u002Fpieces.app",{"key":443,"label":444,"href":445},"site.about","About page","https:\u002F\u002Fpieces.app\u002Fabout",{"key":447,"label":448,"href":449},"site.features","Features page","https:\u002F\u002Fpieces.app\u002Ffeatures",{"key":451,"label":452,"href":453},"site.plugins","Plugins page","https:\u002F\u002Fpieces.app\u002Fplugins",{"key":455,"label":456,"href":457},"site.contact","Contact page","https:\u002F\u002Fpieces.app\u002Fcontact",{"key":459,"label":58,"href":460},"site.updates","https:\u002F\u002Fpieces.app\u002Fupdates",{"key":462,"label":463,"href":464},"site.news","News","https:\u002F\u002Fpieces.app\u002Fnews",{"key":466,"label":467,"href":468},"site.events","Community events","https:\u002F\u002Fpieces.app\u002Fcommunity\u002Fevents",{"key":470,"label":471,"href":472},"site.userStories","User stories","https:\u002F\u002Fpieces.app\u002Fuser-stories",{"key":474,"label":475,"href":476},"site.academy","Academy","https:\u002F\u002Fpieces.app\u002Flearn\u002Facademy",{"key":478,"label":479,"href":480},"site.support","Website support","https:\u002F\u002Fpieces.app\u002Fsupport",{"key":482,"label":483,"href":484},"site.standup","Standup","https:\u002F\u002Fpieces.app\u002Fstandup",{"key":486,"label":34,"href":487},"site.blog","https:\u002F\u002Fcode.pieces.app\u002Fblog",{"key":489,"label":43,"href":490},"social.discord","https:\u002F\u002Fdiscord.gg\u002Fgetpieces",{"key":492,"label":46,"href":493},"social.x","https:\u002F\u002Fx.com\u002Fgetpieces",{"key":495,"label":496,"href":493},"social.twitter","Twitter",{"key":498,"label":499,"href":500},"social.instagram","Instagram","https:\u002F\u002Fwww.instagram.com\u002Fgetpieces\u002F",{"key":502,"label":503,"href":504},"social.tiktok","TikTok","https:\u002F\u002Fwww.tiktok.com\u002F@getpieces",{"key":506,"label":49,"href":507},"social.linkedin","https:\u002F\u002Fwww.linkedin.com\u002Fcompany\u002Fgetpieces\u002F",{"key":509,"label":510,"href":511},"social.youtube","YouTube","https:\u002F\u002Fyoutube.com\u002F@getpieces",{"key":513,"label":514,"href":515},"github.org","GitHub organization","https:\u002F\u002Fgithub.com\u002Fpieces-app",{"key":517,"label":518,"href":519},"github.support","GitHub support","https:\u002F\u002Fgithub.com\u002Fpieces-app\u002Fsupport",{"key":521,"label":522,"href":523},"github.issues","GitHub issues","https:\u002F\u002Fgithub.com\u002Fpieces-app\u002Fsupport\u002Fissues",{"key":525,"label":526,"href":527},"github.discussions","GitHub discussions","https:\u002F\u002Fgithub.com\u002Fpieces-app\u002Fsupport\u002Fdiscussions",{"key":529,"label":530,"href":531},"github.documentation","GitHub documentation","https:\u002F\u002Fgithub.com\u002Fpieces-app\u002Fdocumentation",{"key":533,"label":534,"href":535},"github.opensource","GitHub open source","https:\u002F\u002Fgithub.com\u002Fpieces-app\u002Fopensource",{"key":537,"label":538,"href":539},"github.sdks.python","Python SDK","https:\u002F\u002Fgithub.com\u002Fpieces-app\u002Fpieces-os-client-sdk-for-python",{"key":541,"label":542,"href":543},"github.sdks.typescript","TypeScript SDK","https:\u002F\u002Fgithub.com\u002Fpieces-app\u002Fpieces-os-client-sdk-for-typescript",{"key":545,"label":546,"href":547},"github.sdks.dart","Dart SDK","https:\u002F\u002Fgithub.com\u002Fpieces-app\u002Fpieces-os-client-sdk-for-dart",{"key":549,"label":550,"href":551},"github.sdks.kotlin","Kotlin SDK","https:\u002F\u002Fgithub.com\u002Fpieces-app\u002Fpieces-os-client-sdk-for-kotlin",{"key":553,"label":554,"href":555},"github.plugins.obsidian","Obsidian plugin repository","https:\u002F\u002Fgithub.com\u002Fpieces-app\u002Fobsidian-pieces",{"key":557,"label":558,"href":255},"github.plugins.jupyterlab","JupyterLab plugin repository",{"key":560,"label":561,"href":562},"github.plugins.sublime","Sublime plugin repository","https:\u002F\u002Fgithub.com\u002Fpieces-app\u002Fplugin_sublime",{"key":564,"label":565,"href":566},"github.plugins.neovim","Neovim plugin repository","https:\u002F\u002Fgithub.com\u002Fpieces-app\u002Fplugin_neovim",{"key":568,"label":569,"href":570},"github.cliAgent","CLI agent repository","https:\u002F\u002Fgithub.com\u002Fpieces-app\u002Fcli-agent",{"key":572,"label":573,"href":574},"github.mcpDart","MCP Dart repository","https:\u002F\u002Fgithub.com\u002Fpieces-app\u002Fmcp_dart",{"key":576,"label":577,"href":578},"github.awesomePieces","Awesome Pieces repository","https:\u002F\u002Fgithub.com\u002Fpieces-app\u002Fawesome-pieces",{"key":580,"label":581,"href":66},"legal.privacyPolicy","Privacy policy",{"key":583,"label":584,"href":69},"legal.refundPolicy","Refund policy",{"key":586,"label":587,"href":72},"legal.terms","Terms",{"key":589,"label":590,"href":591},"legal.security","Legal security","https:\u002F\u002Fpieces.app\u002Flegal\u002Fsecurity",{"key":593,"label":594,"href":511},"videos.youtubeChannel","YouTube channel",{"key":596,"label":597,"href":598},"videos.gettingStartedDesktop","Getting started desktop video","https:\u002F\u002Fyoutu.be\u002FdUr1lRM_TYk",{"key":600,"label":601,"href":602},"videos.snippetDiscoveryxR","Snippet discovery video","https:\u002F\u002Fyoutu.be\u002FG6vb1USw-30",{"key":604,"label":605,"href":606},"sales.bookACall","Book a sales call","https:\u002F\u002Fcalendar.app.google\u002FWVUDtUfNy5Vst3sH7",{"key":608,"label":609,"href":610},"sales.enterprise","Enterprise form","https:\u002F\u002Fgetpieces.typeform.com\u002Fto\u002FaVQFTvpE",{"key":612,"label":613,"href":527},"sales.feedback","Feedback discussions",{"key":615,"label":616,"href":617},"sales.earlyAccess","Early access form","https:\u002F\u002Fgetpieces.typeform.com\u002Fearlyaccess",{"key":619,"label":620,"href":621},"sales.supportEmail","Support email","mailto:support@pieces.app",{"key":623,"label":624,"href":19},"routes.home","Home route",{"key":626,"label":627,"href":56},"routes.about","About route",{"key":629,"label":630,"href":12},"routes.downloads","Downloads route",{"key":632,"label":633,"href":634},"routes.thanks","Post-install thanks route","\u002Finstall\u002Fthanks",{"key":636,"label":637,"href":638},"routes.pricing","Pricing route","\u002Fpricing",{"key":640,"label":641,"href":642},"cta.freeTrial","Start free trial CTA (Pieces Pro) — used by \u002Fcampaigns\u002F* landing pages","https:\u002F\u002Fcampaigns.pieces.app\u002F",{"key":644,"label":645,"href":22},"routes.enterprise","Enterprise route",{"key":647,"label":648,"href":62},"routes.contact","Contact route",{"key":650,"label":651,"href":59},"routes.updates","Updates route",{"key":653,"label":654,"href":655},"routes.migrationError","Migration error route","\u002Fmigration\u002Ferror",{"key":657,"label":658,"href":659},"routes.authenticated","Post-login authenticated route","\u002Fauth\u002Fsigned-in",{"key":661,"label":662,"href":663},"routes.signed-out","Signed out route","\u002Fauth\u002Fsigned-out",{"key":665,"label":666,"href":667},"routes.authentication-error","Authentication error route","\u002Fauth\u002Ferror",{},"data\u002Fshared\u002Furls","2AvfSWI6bZACH5Kr1ZS3txMLjteRjCjbDR_ul1uRZ9Q",{"id":672,"title":673,"author":674,"authorPhoto":675,"authorPhotoAlt":676,"authorSlug":677,"body":678,"buttonText":2258,"buttonUrl":2258,"category":2259,"date":2260,"description":2261,"draft":2262,"editorsPick":2262,"extension":2263,"featured":2262,"image":2264,"imageAlt":2265,"meta":2266,"navigation":32,"ogImage":2258,"ogImageAlt":2258,"path":2267,"seo":2268,"stem":2269,"tags":2258,"__hash__":2270},"blog\u002Fblog\u002Fusing-mvvm-architecture-in-flutter.md","Using MVVM Architecture in Flutter","Aseem Wangoo","https:\u002F\u002Fstorage.googleapis.com\u002Fpieces-marketing-website\u002Fimages\u002Fblog\u002Fusing-mvvm-architecture-in-flutter\u002Fauthor.jpeg","Aseem Wangoo.","aseem-wangoo",{"type":679,"value":680,"toc":2230},"minimark",[681,686,702,722,729,733,736,758,761,769,783,787,793,802,805,826,829,837,846,851,856,868,875,880,886,926,936,950,956,963,973,977,980,986,992,1001,1011,1014,1024,1027,1032,1038,1046,1050,1059,1068,1072,1081,1090,1096,1105,1109,1112,1119,1122,1133,1136,1141,1148,1151,1156,1162,1173,1187,1193,1198,1204,1213,1216,1222,1225,1258,1262,1271,1285,1299,1309,1314,1320,1323,1326,1335,1341,1347,1354,1372,1384,1389,1392,1404,1408,1411,1429,1433,1436,1439,1442,1447,1453,1457,1468,1472,1480,1483,1489,1495,1498,1502,1508,1511,1516,1522,1525,1530,1536,1539,1542,1547,1553,1566,1579,1584,1588,1591,1594,1607,1612,1618,1631,1643,1648,1654,1660,1663,1668,1674,1692,1702,1705,1721,1725,1732,1738,1742,1745,1748,1756,1765,1778,1786,1789,1794,1801,1806,1812,1833,1837,1840,1859,1864,1870,1874,1877,1882,1888,1891,1903,1907,1913,1917,1932,1947,1950],[682,683,685],"h2",{"id":684},"what-is-model-view-viewmodel","What is Model-View-ViewModel?",[687,688,689,693,694,697,698,701],"p",{},[690,691,692],"strong",{},"Model-View-ViewModel (MVVM)"," Architecture is a unique combination of software architecture patterns that supports the separation of the UI (which is ",[690,695,696],{},"View",") from the development of the business logic or the backend logic (",[690,699,700],{},"Model","). The view model inside MVVM is the bridge responsible for the conversion of data in a way that behaves in accordance with the changes happening in the UI.",[687,703,704,705,709,710,713,714,717,718,721],{},"In addition, to know about the responsibilities of the three components, it’s also important to understand how the components interact with each other. At the highest level, ",[706,707,708],"em",{},"the view “knows about” the view model",", and ",[706,711,712],{},"the view model “knows about” the model",", but ",[706,715,716],{},"the model is unaware of the view model",", and the ",[706,719,720],{},"view model is unaware of the view",".",[687,723,724],{},[725,726],"img",{"alt":727,"src":728},"A diagram showing the Flutter MVVM architecture.","https:\u002F\u002Fstorage.googleapis.com\u002Fpieces-marketing-website\u002Fimages\u002Fblog\u002Fusing-mvvm-architecture-in-flutter\u002Fimg-001.png",[682,730,732],{"id":731},"advantages-and-disadvantages-of-mvvm","Advantages and Disadvantages of MVVM",[687,734,735],{},"There are several advantages of MVVM Architecture:",[737,738,739,746,749,752,755],"ul",{},[740,741,742,745],"li",{},[690,743,744],{},"Separation of Concerns",": This is a design principle for separating a computer program into distinct sections such that each section addresses a separate concern. A concern is anything that matters to provide a solution to a problem.",[740,747,748],{},"Improved testability",[740,750,751],{},"Defined project structure",[740,753,754],{},"Parallel development of UI",[740,756,757],{},"Abstracting the view, thus reducing the quantity of business logic required in the code behind it",[687,759,760],{},"Some disadvantages of MVVM:",[737,762,763,766],{},[740,764,765],{},"It has a somewhat steep learning curve. How all the layers work together may take some time to understand.",[740,767,768],{},"It adds a lot of extra classes, so it’s not ideal for low-complexity projects.",[687,770,771,772,775,776],{},"Since architectural or MVVM design patterns are platform-agnostic, they can be used with any framework MVVM framework; in our case, ",[690,773,774],{},"Flutter",". If you prefer visual learning, follow along with a ",[777,778,782],"a",{"href":779,"rel":780},"https:\u002F\u002Fwww.youtube.com\u002Fwatch?v=7Q9dxzIo314",[781],"nofollow","video version of this tutorial.",[682,784,786],{"id":785},"mvvm-components","MVVM Components",[687,788,789,792],{},[690,790,791],{},"Model:"," This is basically the domain model, or the model which represents the data from your backend (i.e., the data access layer). Models hold information but typically don’t handle behavior. They don’t format information or influence how data appears. The Model in the MVVM pattern in Flutter represents the actual data that will be used in application development.",[687,794,795,798,799,801],{},[690,796,797],{},"View:"," This is basically the only part of the application users actually interact with. For instance, the user presses the button, scrolls the list, edits the settings, etc. These events are then forwarded to the view model, which does the processing and returns the expected user response (which is some form of UI). It’s important to remember the ",[690,800,696],{}," isn’t responsible here for handling the state.",[687,803,804],{},"A View should be as dumb as possible. Never put your business logic in a View.",[687,806,807,810,811,813,814,816,817,820,821,825],{},[690,808,809],{},"ViewModel:"," The ViewModel acts as an intermediary between the ",[690,812,696],{}," and the ",[690,815,700],{},", in such a way that it provides data to the UI. The ViewModel may also expose methods for helping to maintain the View’s state, update the model based on the actions on a View, and trigger events on the View. In ",[690,818,819],{},"Flutter,"," we have a listener called ",[822,823,824],"code",{},"ChangeNotifier"," that allows the ViewModel to inform or update the View whenever the data is updated.",[687,827,828],{},"The ViewModel has basically two responsibilities:",[737,830,831,834],{},[740,832,833],{},"It reacts to user inputs (e.g., by changing the model, initiating network requests, or routing to different screens)",[740,835,836],{},"It offers output data that the View can subscribe to",[687,838,839,840,845],{},"In summary, the ViewModel sits behind the UI layer which is a ",[777,841,844],{"href":842,"rel":843},"https:\u002F\u002Fpieces.app\u002Fblog\u002Fuser-interface-neumorphism-glassmorphism",[781],"key user interface principle",". It exposes data needed by a View and can be viewed as the source our Views go to for both data and actions.",[847,848,850],"h3",{"id":849},"what-is-flutter-changenotifier","What is Flutter ChangeNotifier?",[687,852,853,855],{},[822,854,824],{}," is a class that provides change notifications to its listeners.",[687,857,858,859,864,865,867],{},"As per the official ",[777,860,863],{"href":861,"rel":862},"https:\u002F\u002Fapi.flutter.dev\u002Fflutter\u002Ffoundation\u002FChangeNotifier-class.html",[781],"documentation",", a ",[822,866,824],{}," is:",[687,869,870,871,874],{},"A class that can be extended or mixed in that provides a change notification API using ",[822,872,873],{},"VoidCallback"," for notifications.",[687,876,877],{},[706,878,879],{},"It is O(1) for adding listeners and O(N) for removing listeners and dispatching notifications (where N is the number of listeners).",[687,881,882,883,885],{},"There are two ways to consume the ",[822,884,824],{}," in Flutter:",[887,888,889,904],"ol",{},[740,890,891,892,895,896,898,899,721],{},"Using the ",[822,893,894],{},".addListener"," method, as the ",[822,897,824],{}," is a type of ",[777,900,903],{"href":901,"rel":902},"https:\u002F\u002Fapi.flutter.dev\u002Fflutter\u002Ffoundation\u002FListenable-class.html",[781],"Listenable",[740,905,906,907,910,913,914,709,917,920,922,923,925],{},"Using a combination of ",[822,908,909],{},"ChangeNotifierProvider",[706,911,912],{},","," ",[822,915,916],{},"Consumer",[822,918,919],{},"Provider",[706,921,721],{}," These capabilities are provided to us by the ",[822,924,919],{}," package.",[687,927,928,913,931,913,933],{},[690,929,930],{},"We will use approach 2 in the following flutter",[822,932,824],{},[690,934,935],{},"example.",[687,937,938,939,942,943,945,946,949],{},"In the real world, other classes can ",[822,940,941],{},"listen"," to a ",[822,944,824],{}," object. When the change notifier gets updated values, it can call a method called ",[822,947,948],{},"notifyListeners",", and then any of its listeners will receive the updated values.",[687,951,952],{},[725,953],{"alt":954,"src":955},"A code snippet with Dart code.","https:\u002F\u002Fstorage.googleapis.com\u002Fpieces-marketing-website\u002Fimages\u002Fblog\u002Fusing-mvvm-architecture-in-flutter\u002Fimg-002.png",[687,957,958],{},[777,959,962],{"href":960,"rel":961},"https:\u002F\u002Framan.pieces.cloud\u002F?p=2ce4479437",[781],"Save to Pieces",[687,964,965,966,969,970,972],{},"Inside the app, any class that listens to this ",[822,967,968],{},"Person"," will be notified in case the age changes. Internally, ",[822,971,948],{}," calls the registered listeners.",[682,974,976],{"id":975},"flutter-mvvm-example","Flutter MVVM Example",[687,978,979],{},"Flutter is declarative in nature. This means that Flutter builds UI by overriding your build methods to reflect the current state of your app:",[687,981,982],{},[725,983],{"alt":984,"src":985},"Code snippet with Dart code.","https:\u002F\u002Fstorage.googleapis.com\u002Fpieces-marketing-website\u002Fimages\u002Fblog\u002Fusing-mvvm-architecture-in-flutter\u002Fimg-003.png",[687,987,988],{},[777,989,962],{"href":990,"rel":991},"https:\u002F\u002Framan.pieces.cloud\u002F?p=5c8745be69",[781],[687,993,994,995,1000],{},"According to the ",[777,996,999],{"href":997,"rel":998},"https:\u002F\u002Fdocs.flutter.dev\u002Fdevelopment\u002Fdata-and-backend\u002Fstate-mgmt\u002Fephemeral-vs-app",[781],"Flutter documentation",", the state is described as “the data you need to rebuild your UI at any point in time.”",[687,1002,1003,1004,1007,1008,721],{},"A state can be contained in a single widget, known as a local state. Flutter provides inbuilt classes and methods to deal with self-contained states like ",[822,1005,1006],{},"StatefulWidget","and ",[822,1009,1010],{},"setState",[687,1012,1013],{},"However, a state that has to be shared across different widgets is known as an app state. It is at this point that we introduce state management tools.",[687,1015,1016,913,1019,913,1021],{},[706,1017,1018],{},"We will be using",[822,1020,919],{},[706,1022,1023],{},"for state management.",[687,1025,1026],{},"Let’s say you were architecting an application that includes only the screen below. How would you do it?",[687,1028,1029],{},[706,1030,1031],{},"Hint: Using Flutter MVVM",[687,1033,1034],{},[725,1035],{"alt":1036,"src":1037},"An example screen for a flutter architecture MVVM example.","https:\u002F\u002Fstorage.googleapis.com\u002Fpieces-marketing-website\u002Fimages\u002Fblog\u002Fusing-mvvm-architecture-in-flutter\u002Fimg-004.png",[737,1039,1040],{},[740,1041,1042,1043,721],{},"Each screen should comprise its own flutter MVVM folder structure. Create a folder called home which contains a view called ",[706,1044,1045],{},"home_view",[847,1047,1049],{"id":1048},"naming-convention-for-view","Naming convention for View:",[687,1051,1052,1053,1056,1057,721],{},"Each screen is called “view” and the file is suffixed with ",[822,1054,1055],{},"_view",". The view will be listening to the changes happening on the ViewModel Flutter, using the ",[822,1058,916],{},[737,1060,1061],{},[740,1062,1063,1064,1067],{},"Each view should have a ViewModel associated with it. Create a file called ",[822,1065,1066],{},"home_view_model"," which will be responsible for accepting the user interactions, processing them by running some business logic, and finally responding back.",[847,1069,1071],{"id":1070},"naming-convention-for-viewmodel","Naming convention for ViewModel:",[687,1073,1074,1075,1078,1079,721],{},"Each screen has a ViewModel associated with it and the file is suffixed with ",[822,1076,1077],{},"_view_model",". The ViewModel notifies the changes to the UI (if any) using ",[822,1080,948],{},[737,1082,1083],{},[740,1084,1085,1086,1089],{},"Let’s assume the button calls some API (more on that later) and responds back with some response. This response should be converted as a model suffixed with ",[822,1087,1088],{},"_model","and returned from the ViewModel to the view.",[687,1091,1092],{},[725,1093],{"alt":1094,"src":1095},"MVVM Project structure example imagine.","https:\u002F\u002Fstorage.googleapis.com\u002Fpieces-marketing-website\u002Fimages\u002Fblog\u002Fusing-mvvm-architecture-in-flutter\u002Fimg-005.png",[687,1097,1098,1099,1104],{},"These are the basics of MVVM architecture, as we can see in the screenshot above. This can be replicated for all of your app's screens. You can read more about ",[777,1100,1103],{"href":1101,"rel":1102},"https:\u002F\u002Fpieces.app\u002Fblog\u002Ffile-handling-web-development",[781],"The Best File Formats for Web Development"," for a better understanding. Now, let’s see a slight addition on top of this structure.",[847,1106,1108],{"id":1107},"extending-the-mvvm-toolkit-with-repository-and-services","Extending the MVVM toolkit with Repository and Services",[687,1110,1111],{},"In the real world, our app needs to interact with APIs or third-party integrations. So, we introduce something called a Repository.",[687,1113,1114,1115,1118],{},"A repository pattern provides an abstraction of data so that your application can work with a simple abstraction that has an interface. Using this pattern can help to achieve loose coupling. If implemented correctly, the Repository pattern can be a great way to ensure you follow the ",[706,1116,1117],{},"Single Responsibility Principle"," for your data access code.",[687,1120,1121],{},"Some benefits of using the Repository pattern:",[887,1123,1124,1127,1130],{},[740,1125,1126],{},"It separates the business logic for accessing external services",[740,1128,1129],{},"It makes mocking easier and allows to do unit tests",[740,1131,1132],{},"It easily switches data sources without doing time-consuming code changes",[687,1134,1135],{},"Some disadvantages of using the Repository pattern:",[887,1137,1138],{},[740,1139,1140],{},"It adds another layer of abstraction, which adds a certain level of complexity, making it overkill for small applications.",[687,1142,1143,1144,1147],{},"Continuing with the previous example, let’s say our button needs to call an API. Let’s implement it using the ",[706,1145,1146],{},"Repository"," pattern.",[687,1149,1150],{},"Dart has no interfaces, like Java, but we can create one with an abstract class. We begin by creating an abstract class that defines the interface for our home_repo.",[687,1152,1153],{},[725,1154],{"alt":954,"src":1155},"https:\u002F\u002Fstorage.googleapis.com\u002Fpieces-marketing-website\u002Fimages\u002Fblog\u002Fusing-mvvm-architecture-in-flutter\u002Fimg-006.png",[687,1157,1158],{},[777,1159,962],{"href":1160,"rel":1161},"https:\u002F\u002Framan.pieces.cloud\u002F?p=9e2b429fe1",[781],[687,1163,1164,1165,1168,1169,1172],{},"This abstract class helps to create a boundary, and we are free to work on either side of that boundary. We could work on implementing the home repository (",[706,1166,1167],{},"recommended","), or we could just use the implementation directly in our app (",[706,1170,1171],{},"not recommended",").",[687,1174,1175,1176,1179,1180,1183,1184,721],{},"Here, the ",[822,1177,1178],{},"HomeRepository"," has only one method, ",[822,1181,1182],{},"fetchData",". This method returns the response as a model called ",[822,1185,1186],{},"CarouselModel",[687,1188,1189,1190,1192],{},"Next, let’s implement the ",[822,1191,1178],{},":",[687,1194,1195],{},[725,1196],{"alt":954,"src":1197},"https:\u002F\u002Fstorage.googleapis.com\u002Fpieces-marketing-website\u002Fimages\u002Fblog\u002Fusing-mvvm-architecture-in-flutter\u002Fimg-007.png",[687,1199,1200],{},[777,1201,962],{"href":1202,"rel":1203},"https:\u002F\u002Framan.pieces.cloud\u002F?p=6e8d4189d5",[781],[687,1205,1206,1207,1209,1210],{},"Inside the method ",[822,1208,1182],{},", we introduce a delay and then load the data from the assets, which is a JSON file. This delay is basically a substitute for calling the API, ",[706,1211,1212],{},"but I hope I am able to convey my thoughts to the reader.",[687,1214,1215],{},"As your application grows, you may find yourself adding more and more methods to a given repository. In this scenario, consider creating multiple repositories and keeping related methods together.",[687,1217,1218],{},[725,1219],{"alt":1220,"src":1221},"An example of MVVM folder structure Flutter.","https:\u002F\u002Fstorage.googleapis.com\u002Fpieces-marketing-website\u002Fimages\u002Fblog\u002Fusing-mvvm-architecture-in-flutter\u002Fimg-008.png",[687,1223,1224],{},"Now, we have",[737,1226,1227,1236,1243,1251],{},[740,1228,1229,1232,1233],{},[822,1230,1231],{},"carousel_model"," representing the ",[690,1234,1235],{},"Model (M)",[740,1237,1238,1232,1240],{},[822,1239,1045],{},[690,1241,1242],{},"View (V)",[740,1244,1245,1247,1248],{},[822,1246,1066],{},"representing the ",[690,1249,1250],{},"View Model (VM)",[740,1252,1253,1232,1256],{},[822,1254,1255],{},"home_repo",[690,1257,1146],{},[847,1259,1261],{"id":1260},"register-the-repository","Register the Repository",[687,1263,1264,1265,1270],{},"Since our repository is ready, now we need to figure out how to register it and make it available inside our app. This is when we introduce another concept called Dependency Injection (DI). We make use of the package ",[777,1266,1269],{"href":1267,"rel":1268},"https:\u002F\u002Fpub.dev\u002Fpackages\u002Fget_it",[781],"get_it",". As per the documentation:",[687,1272,1273,1274,1277,1278,1281,1282,1284],{},"This is a simple Service Locator for Dart and Flutter projects with some additional goodies highly inspired by ",[706,1275,1276],{},"Splat",". It can be used instead of ",[822,1279,1280],{},"InheritedWidget"," or ",[822,1283,919],{},"to access objects, e.g., from your UI.",[687,1286,1287,1290,1291,1294,1295,1298],{},[690,1288,1289],{},"GetIt is super fast"," because it uses just a ",[822,1292,1293],{},"Map",", which makes access to it ",[690,1296,1297],{},"O(1)."," GetIt itself is a singleton, so you can access it from everywhere using its instance property (see below).",[687,1300,1301,1302,1304,1305,1308],{},"We install ",[822,1303,1269],{}," it by including it inside the ",[822,1306,1307],{},"pubspec.yaml","as:",[687,1310,1311],{},[725,1312],{"alt":954,"src":1313},"https:\u002F\u002Fstorage.googleapis.com\u002Fpieces-marketing-website\u002Fimages\u002Fblog\u002Fusing-mvvm-architecture-in-flutter\u002Fimg-009.png",[687,1315,1316],{},[777,1317,962],{"href":1318,"rel":1319},"https:\u002F\u002Framan.pieces.cloud\u002F?p=79cf469234",[781],[687,1321,1322],{},"Typically at the start of your app, you register the types that you want to later access from anywhere. After that, you can access instances of the registered types by calling the locator again.",[687,1324,1325],{},"The nice thing is you can register an interface or abstract class together with a concrete implementation. When accessing the instance, you always ask for the interface\u002Fabstract class type. This makes it easy to switch the implementation by just switching the concrete type at registration time.",[687,1327,1328,1329,1332,1333,1192],{},"We create a file called ",[822,1330,1331],{},"locator.dart"," inside which we will instantiate the object of ",[822,1334,1269],{},[687,1336,1337],{},[725,1338],{"alt":1339,"src":1340},"A code snippet with Dart code that helps to build MVVM Architecture.","https:\u002F\u002Fstorage.googleapis.com\u002Fpieces-marketing-website\u002Fimages\u002Fblog\u002Fusing-mvvm-architecture-in-flutter\u002Fimg-010.png",[687,1342,1343],{},[777,1344,962],{"href":1345,"rel":1346},"https:\u002F\u002Framan.pieces.cloud\u002F?p=b47845a2c2",[781],[687,1348,1349,1350,1353],{},"As Dart supports global variables, we assign the ",[822,1351,1352],{},"GetIt"," instance to a global variable to make access to it as easy as possible.",[687,1355,1356,1357,1359,1360,1363,1364,1366,1367,1369,1370,721],{},"Although ",[822,1358,1352],{}," is a singleton, we will assign its instance to a global variable",[822,1361,1362],{},"locator","to minimize the code for accessing ",[822,1365,1352],{},". Any call to ",[822,1368,1362],{}," in any package of a project will get the same instance of ",[822,1371,1352],{},[687,1373,1374,1375,1377,1378,1381,1382,721],{},"Next, we use the ",[822,1376,1362],{}," and use the ",[822,1379,1380],{},"registerFactory"," to register our ",[822,1383,1178],{},[1385,1386,1388],"h4",{"id":1387},"provider-as-an-alternative-to-getit","Provider as an alternative to GetIt",[687,1390,1391],{},"Provider is a powerful alternative to GetIt. But there are some reasons why people use GetIt for Dependency injection:",[737,1393,1394,1401],{},[740,1395,1396,1397,1400],{},"Provider needs a ",[822,1398,1399],{},"BuildContext"," to access the registered objects, so you can’t use it inside business objects outside of the widget tree or in a pure Dart MVVM package.",[740,1402,1403],{},"Provider adds its own widget classes to the widget tree that are no GUI elements, but are needed to access the in Provider registered objects.",[1385,1405,1407],{"id":1406},"testing-repository","Testing Repository",[687,1409,1410],{},"You can implement unit testing for different elements of your Flutter applications, such as widgets, controllers, models, services, and repositories. It’s possible to unit test repository-based Flutter codebases with the following strategies:",[737,1412,1413,1416],{},[740,1414,1415],{},"Implement a mock repository class and test the logic",[740,1417,1418,1419,1424,1425,721],{},"You don’t need to implement mock classes by yourself — the ",[777,1420,1423],{"href":1421,"rel":1422},"https:\u002F\u002Fpub.dev\u002Fpackages\u002Fmockito",[781],"Mockito package"," helps you to generate them quickly and ",[777,1426,1428],{"href":1421,"rel":1427},[781],"automatically",[682,1430,1432],{"id":1431},"integrate-repository-in-viewmodel","Integrate Repository in ViewModel",[687,1434,1435],{},"Now comes the time to use the Dependency Injection (DI). But before that, let’s see what it is.",[687,1437,1438],{},"When class A uses some functionality of class B, then it’s said that class A has a dependency of class B.",[687,1440,1441],{},"Before we can use methods of other classes, we first need to create the object of that class (i.e., class A needs to create an instance of class B).",[687,1443,1444],{},[690,1445,1446],{},"Dependency injection is transferring the task of creating the object to someone else and directly using the dependency.",[687,1448,1449],{},[725,1450],{"alt":1451,"src":1452},"A comic strip that illustrates dependency injection.","https:\u002F\u002Fstorage.googleapis.com\u002Fpieces-marketing-website\u002Fimages\u002Fblog\u002Fusing-mvvm-architecture-in-flutter\u002Fimg-011.png",[847,1454,1456],{"id":1455},"benefits-of-using-di","Benefits of using DI",[887,1458,1459,1462,1465],{},[740,1460,1461],{},"Supports unit testing",[740,1463,1464],{},"Boilerplate code is reduced, as the initializing of dependencies is done by another component (locator in our case)",[740,1466,1467],{},"Enables loose coupling",[847,1469,1471],{"id":1470},"drawbacks-of-using-di","Drawbacks of using DI",[887,1473,1474,1477],{},[740,1475,1476],{},"It’s complex to learn, and if overused, can lead to management issues and other problems",[740,1478,1479],{},"Many compile time errors are pushed to runtime",[687,1481,1482],{},"Coming back to our application, let’s see how we integrate it:",[687,1484,1485],{},[725,1486],{"alt":1487,"src":1488},"A code snippet with Dart code that integrates DI.","https:\u002F\u002Fstorage.googleapis.com\u002Fpieces-marketing-website\u002Fimages\u002Fblog\u002Fusing-mvvm-architecture-in-flutter\u002Fimg-012.png",[687,1490,1491],{},[777,1492,962],{"href":1493,"rel":1494},"https:\u002F\u002Framan.pieces.cloud\u002F?p=954243a2ae",[781],[687,1496,1497],{},"Here, we create a constructor inside our HomeViewModel and specify the homeRepo as our required parameter. This way, we direct whomever needs access to our ViewModel first through the homeRepo.",[847,1499,1501],{"id":1500},"initialize-the-service-locator","Initialize the service locator",[687,1503,1504,1505],{},"You need to register the services on app startup, so you can do that in ",[706,1506,1507],{},"main.dart.",[687,1509,1510],{},"Replace the standard:",[687,1512,1513],{},[725,1514],{"alt":954,"src":1515},"https:\u002F\u002Fstorage.googleapis.com\u002Fpieces-marketing-website\u002Fimages\u002Fblog\u002Fusing-mvvm-architecture-in-flutter\u002Fimg-013.png",[687,1517,1518],{},[777,1519,962],{"href":1520,"rel":1521},"https:\u002F\u002Framan.pieces.cloud\u002F?p=71a54b9f05",[781],[687,1523,1524],{},"With the following:",[687,1526,1527],{},[725,1528],{"alt":954,"src":1529},"https:\u002F\u002Fstorage.googleapis.com\u002Fpieces-marketing-website\u002Fimages\u002Fblog\u002Fusing-mvvm-architecture-in-flutter\u002Fimg-014.png",[687,1531,1532],{},[777,1533,962],{"href":1534,"rel":1535},"https:\u002F\u002Framan.pieces.cloud\u002F?p=17054bb0ae",[781],[687,1537,1538],{},"This will register any services you have with GetIt before the widget tree is built.",[687,1540,1541],{},"If we recall, our homeRepo was registered inside the locator, so in order to declare our ViewModel, we follow this:",[687,1543,1544],{},[725,1545],{"alt":954,"src":1546},"https:\u002F\u002Fstorage.googleapis.com\u002Fpieces-marketing-website\u002Fimages\u002Fblog\u002Fusing-mvvm-architecture-in-flutter\u002Fimg-015.png",[687,1548,1549],{},[777,1550,962],{"href":1551,"rel":1552},"https:\u002F\u002Framan.pieces.cloud\u002F?p=31d14b9ab7",[781],[687,1554,1555,1556,1559,1560,1563,1564,721],{},"Inside our ",[822,1557,1558],{},"main",", we call the ",[822,1561,1562],{},"setupLocator",", which is the method that comprises all the registered dependencies under ",[822,1565,1331],{},[687,1567,1568,1569,1574,1575,721],{},"Next, inside our ",[777,1570,1573],{"href":1571,"rel":1572},"https:\u002F\u002Fpub.dev\u002Fdocumentation\u002Fprovider\u002Flatest\u002Fprovider\u002FMultiProvider-class.html",[781],"MultiProvider",", we specify the HomeViewModel under the ",[777,1576,909],{"href":1577,"rel":1578},"https:\u002F\u002Fpub.dev\u002Fdocumentation\u002Fprovider\u002Flatest\u002Fprovider\u002FChangeNotifierProvider-class.html",[781],[687,1580,1581],{},[706,1582,1583],{},"ChangeNotifierProvider creates a ChangeNotifier using create and automatically disposes it when it is removed from the widget tree.",[847,1585,1587],{"id":1586},"using-viewmodel-inside-the-view","Using ViewModel inside the View",[687,1589,1590],{},"We have our repository registered and passed as a required parameter to our ViewModel. Let’s see how to use the ViewModel inside our View.",[687,1592,1593],{},"There are two ways to access the ViewModel inside the View:",[887,1595,1596,1601],{},[740,1597,891,1598,1600],{},[706,1599,916],{}," widget",[740,1602,1603,1604],{},"Using ",[706,1605,1606],{},"Provider.of(context)",[687,1608,1609],{},[725,1610],{"alt":954,"src":1611},"https:\u002F\u002Fstorage.googleapis.com\u002Fpieces-marketing-website\u002Fimages\u002Fblog\u002Fusing-mvvm-architecture-in-flutter\u002Fimg-016.png",[687,1613,1614],{},[777,1615,962],{"href":1616,"rel":1617},"https:\u002F\u002Framan.pieces.cloud\u002F?p=9bb34aaed0",[781],[687,1619,1620,1621,1624,1625,1628,1629,721],{},"We instantiate the ",[822,1622,1623],{},"viewModel"," using ",[690,1626,1627],{},"Provider.of"," inside the ",[822,1630,1045],{},[687,1632,1633,1635,1636,1639,1640,1642],{},[822,1634,1606],{}," is used when you need to access the dependency, but you don’t want to make any changes to the UI. We simply set ",[822,1637,1638],{},"listen: false",", signifying that we don’t need to listen to updates from the ChangeNotifier. The",[822,1641,1638],{},"parameter is used to specify when you're using Provider to fetch an instance and call a method on that instance.",[687,1644,1645],{},[706,1646,1647],{},"Note: We can also use the below:",[687,1649,1650],{},[725,1651],{"alt":1652,"src":1653},"A Dart code snippet.","https:\u002F\u002Fstorage.googleapis.com\u002Fpieces-marketing-website\u002Fimages\u002Fblog\u002Fusing-mvvm-architecture-in-flutter\u002Fimg-017.png",[687,1655,1656],{},[777,1657,962],{"href":1658,"rel":1659},"https:\u002F\u002Framan.pieces.cloud\u002F?p=103e41a5cd",[781],[687,1661,1662],{},"For reacting to the changes that happen to the viewModel, we use Consumer when we want to rebuild the widgets when a value changes. It is a must to provide the type so that the Provider can understand which dependency you are referring to.",[687,1664,1665],{},[725,1666],{"alt":1652,"src":1667},"https:\u002F\u002Fstorage.googleapis.com\u002Fpieces-marketing-website\u002Fimages\u002Fblog\u002Fusing-mvvm-architecture-in-flutter\u002Fimg-018.png",[687,1669,1670],{},[777,1671,962],{"href":1672,"rel":1673},"https:\u002F\u002Framan.pieces.cloud\u002F?p=691240bae8",[781],[687,1675,1676,1677,1681,1682,1686,1687,721],{},"The ",[777,1678,916],{"href":1679,"rel":1680},"https:\u002F\u002Fpub.dev\u002Fdocumentation\u002Fprovider\u002Flatest\u002Fprovider\u002FConsumer-class.html",[781]," widget doesn’t do any fancy work. It just calls ",[777,1683,1627],{"href":1684,"rel":1685},"https:\u002F\u002Fpub.dev\u002Fdocumentation\u002Fprovider\u002Flatest\u002Fprovider\u002FProvider\u002Fof.html",[781]," in a new widget and delegates its build implementation to the ",[777,1688,1691],{"href":1689,"rel":1690},"https:\u002F\u002Fpub.dev\u002Fdocumentation\u002Fprovider\u002Flatest\u002Fprovider\u002FConsumer\u002Fbuilder.html",[781],"builder",[687,1693,1694,1695,1697,1698,1701],{},"The Consumer widget takes two parameters, the ",[822,1696,1691],{}," parameter and the ",[822,1699,1700],{},"child"," parameter (optional). The child parameter widget is not affected by any change in the ChangeNotifier.",[687,1703,1704],{},"This builder can be called multiple times (such as when the provided value changes), and that is where we can rebuild our UI. The Consumer widget has two main purposes:",[737,1706,1707,1718],{},[740,1708,1709,1710,1714,1715,721],{},"It allows us to obtain a value from a provider when we don’t have a ",[777,1711,1399],{"href":1712,"rel":1713},"https:\u002F\u002Fapi.flutter.dev\u002Fflutter\u002Fwidgets\u002FBuildContext-class.html",[781]," that is a descendant of said provider and therefore cannot use ",[777,1716,1627],{"href":1684,"rel":1717},[781],[740,1719,1720],{},"It helps with performance optimization by providing more granular rebuilds.",[847,1722,1724],{"id":1723},"unit-tests-for-the-viewmodel-optional","Unit tests for the ViewModel (Optional)",[687,1726,1727,1728,1731],{},"You can mock dependencies by creating an alternative implementation of a class by making use of the ",[777,1729,1423],{"href":1421,"rel":1730},[781]," as a shortcut.",[687,1733,1734],{},[725,1735],{"alt":1736,"src":1737},"A flowchart of the Flutter MVVM architecture.","https:\u002F\u002Fstorage.googleapis.com\u002Fpieces-marketing-website\u002Fimages\u002Fblog\u002Fusing-mvvm-architecture-in-flutter\u002Fimg-019.png",[682,1739,1741],{"id":1740},"what-are-services","What are Services?",[687,1743,1744],{},"Services are normal Dart classes that are written to do some specialized task in your app. The purpose of a service is to isolate a task, especially volatile third-party packages, and hide its implementation details from the rest of the app.",[687,1746,1747],{},"Some common examples you might create a service to handle:",[737,1749,1750,1753],{},[740,1751,1752],{},"Using a third-party package, for instance, read and write to local storage (shared preferences)",[740,1754,1755],{},"Using Cloud Providers like Firebase or some other third-party package",[687,1757,1758,1759,1764],{},"Let’s say you’re using ",[777,1760,1763],{"href":1761,"rel":1762},"https:\u002F\u002Fpub.dev\u002Fpackages\u002Fpackage_info_plus",[781],"package_info"," to get the package details of your app.",[687,1766,1767,1768,1770,1771,1774,1775,721],{},"You use the package directly inside the app, but after some time, you found an even better package. You go through and replace all the references to ",[822,1769,1763],{}," with the new package ",[822,1772,1773],{},"some_great_package",". This was surely ",[690,1776,1777],{},"a waste of your time and effort",[687,1779,1780,1781,1783,1784,721],{},"Let’s say the product owners found that no user was using this feature. Instead, they requested a new feature. You go through and remove all the references to ",[822,1782,1773],{},". This was, again, ",[690,1785,1777],{},[687,1787,1788],{},"The point is, when you have tight coupling to some function scattered around your code, it makes it error-prone and difficult to change.",[687,1790,1791,721],{},[690,1792,1793],{},"Clean coding takes time and effort up front, but will save you more time and effort in the long run",[687,1795,1796,1797,1800],{},"This is where services come in. You make a new class and call it something like ",[822,1798,1799],{},"PackageInfoService",". The rest of the classes in the app don’t know how it works internally, they just call methods on the service to get the result.",[687,1802,1803],{},[725,1804],{"alt":1652,"src":1805},"https:\u002F\u002Fstorage.googleapis.com\u002Fpieces-marketing-website\u002Fimages\u002Fblog\u002Fusing-mvvm-architecture-in-flutter\u002Fimg-020.png",[687,1807,1808],{},[777,1809,962],{"href":1810,"rel":1811},"https:\u002F\u002Framan.pieces.cloud\u002F?p=e5444f8103",[781],[737,1813,1814,1823,1826],{},[740,1815,1816,1817,1819,1820,1822],{},"This makes it easy to change. If you want to switch ",[822,1818,1763],{}," to ",[822,1821,1773],{},", just alter the code inside the service class. Updating the service code automatically affects everywhere the service is used inside the app.",[740,1824,1825],{},"This supports swapping around implementations. You can create a “fake” implementation that just returns hard-coded data while another team is finalizing\u002Fdeveloping the service implementation.",[740,1827,1828,1829,1832],{},"Sometimes, the implementation may rely on other services. For example, your ",[822,1830,1831],{},"xyzService"," might use a service for making a network call to get other types of data.",[847,1834,1836],{"id":1835},"registering-your-service","Registering your Service",[687,1838,1839],{},"Using a service locator like GetIt is a convenient way to provide services throughout your app.",[737,1841,1842,1849],{},[740,1843,1844,1845,1381,1847],{},"We use the ",[706,1846,1362],{},[822,1848,1799],{},[740,1850,1851,1852,1854,1855,1858],{},"We will be registering ",[822,1853,1799],{}," as a lazy singleton. It only gets initialized when it’s first used. If you want it to be initialized on app startup, then use",[822,1856,1857],{},"registerSingleton()"," instead. Since it’s a singleton, you’ll always have the same instance of your service.",[687,1860,1861],{},[725,1862],{"alt":1652,"src":1863},"https:\u002F\u002Fstorage.googleapis.com\u002Fpieces-marketing-website\u002Fimages\u002Fblog\u002Fusing-mvvm-architecture-in-flutter\u002Fimg-021.png",[687,1865,1866],{},[777,1867,962],{"href":1868,"rel":1869},"https:\u002F\u002Framan.pieces.cloud\u002F?p=950f499442",[781],[847,1871,1873],{"id":1872},"using-the-service","Using the Service",[687,1875,1876],{},"Since we registered the service using the GetIt, we can get a reference to the service from anywhere in the code.",[687,1878,1879],{},[725,1880],{"alt":1652,"src":1881},"https:\u002F\u002Fstorage.googleapis.com\u002Fpieces-marketing-website\u002Fimages\u002Fblog\u002Fusing-mvvm-architecture-in-flutter\u002Fimg-022.png",[687,1883,1884],{},[777,1885,962],{"href":1886,"rel":1887},"https:\u002F\u002Framan.pieces.cloud\u002F?p=852d42a141",[781],[687,1889,1890],{},"Then you can use it within that class like this:",[737,1892,1893,1898],{},[740,1894,1895],{},[822,1896,1897],{},"packageService.getSomeValue()",[740,1899,1900],{},[822,1901,1902],{},"packageService.doSomething(someValue)",[1385,1904,1906],{"id":1905},"unit-tests-for-the-service-optional","Unit tests for the service (Optional)",[687,1908,1909,1910,721],{},"You can mock dependencies by creating an alternative implementation of the service class by making use of the ",[777,1911,1423],{"href":1421,"rel":1912},[781],[682,1914,1916],{"id":1915},"use-pieces-to-store-your-flutter-snippets","Use Pieces to Store Your Flutter Snippets",[687,1918,1919,1920,1925,1926,1931],{},"When ",[777,1921,1924],{"href":1922,"rel":1923},"https:\u002F\u002Fpieces.app\u002Fblog\u002Fbuilding-a-flutter-web-app-from-scratch-a-complete-guide",[781],"developing Flutter web applications",", you may have tons of widgets you save that you want to reuse later, but you just don't have them in a safe place where you can access them. There also may be the scenario where you are combing through ",[777,1927,1930],{"href":1928,"rel":1929},"https:\u002F\u002Fpieces.app\u002Fblog\u002Fusing-pieces-flutter-to-build-pieces",[781],"Flutter and Dart"," documentation, and you want to save examples that come in handy when implementing a new feature or figuring out which widget to use for different circumstances.",[687,1933,1934,1936,1937,1941,1942,721],{},[690,1935,8],{}," helps you save all your useful code snippets efficiently through a desktop application and integrations. Using Pieces, you can save any code snippets from StackOverflow with the click of a button using ",[777,1938,1940],{"href":453,"rel":1939},[781],"the chrome extension",", have your code autosaved from locally-hosted ML algorithms that recognize your code patterns, auto-classify snippets by language, share code with others using generated links, and more! The Pieces’ suite is continuously being developed, and there’s some groundbreaking stuff that is being put together to share, reuse, and ",[777,1943,1946],{"href":1944,"rel":1945},"https:\u002F\u002Fpieces.app\u002Fblog\u002Fhow-to-store-code-snippets-and-10x-your-developer-productivity",[781],"store code snippets to 10x your developer productivity",[687,1948,1949],{},"Btw, we use Dart to power our architecture, incase you are interested in knowing the technicals, you can go through these changelogs.",[887,1951,1952,1959,1966,1973,1980,1987,1994,2001,2008,2015,2022,2029,2040,2047,2054,2061,2068,2075,2082,2089,2096,2103,2110,2117,2124,2131,2138,2145,2152,2159,2165,2172,2179,2191,2202,2209,2216,2223],{},[740,1953,1954],{},[777,1955,1958],{"href":1956,"rel":1957},"https:\u002F\u002Fpieces.app\u002Fchangelog\u002F1-1-5-pieces-chrome-extension-improved-snippet-saving",[781],"Improved Snippet Saving in the Browser",[740,1960,1961],{},[777,1962,1965],{"href":1963,"rel":1964},"https:\u002F\u002Fpieces.app\u002Fchangelog\u002F1-4-10-related-links-support-for-image-processing-and-more",[781],"Related Links, Support for Image Processing and More",[740,1967,1968],{},[777,1969,1972],{"href":1970,"rel":1971},"https:\u002F\u002Fpieces.app\u002Fchangelog\u002F1-4-7-improved-search-results-suggestions-api-and-more",[781],"Improved Search Results, Suggestions API and More",[740,1974,1975],{},[777,1976,1979],{"href":1977,"rel":1978},"https:\u002F\u002Fpieces.app\u002Fchangelog\u002F1-4-8-suggested-save-from-jetbrains-one-click-save-from-chrome",[781],"Suggested Save from JetBrains, One-Click Save from Chrome",[740,1981,1982],{},[777,1983,1986],{"href":1984,"rel":1985},"https:\u002F\u002Fpieces.app\u002Fchangelog\u002F1-5-1-hotfix-search-problem-solved-preparing-for-cloud",[781],"Hotfix: Search Problem Solved & Preparing for Cloud",[740,1988,1989],{},[777,1990,1993],{"href":1991,"rel":1992},"https:\u002F\u002Fpieces.app\u002Fchangelog\u002F170-collections-personal-pieces-domain-and-more",[781],"Collections, Personal Pieces Subdomains, and more!",[740,1995,1996],{},[777,1997,2000],{"href":1998,"rel":1999},"https:\u002F\u002Fpieces.app\u002Fchangelog\u002Fadditional-llm-support-upcoming-features",[781],"Additional LLM Support 🌴 and the New Upcoming View 👀",[740,2002,2003],{},[777,2004,2007],{"href":2005,"rel":2006},"https:\u002F\u002Fpieces.app\u002Fchangelog\u002Fask-copilot-shortcut-gemini-support-and-more-pieces-for-developers-vs-code-extension-1111-obsidian-plugin-1100-jupyterlab-plugin-1110",[781],"Ask Copilot Shortcut, Gemini Support, and More!",[740,2009,2010],{},[777,2011,2014],{"href":2012,"rel":2013},"https:\u002F\u002Fpieces.app\u002Fchangelog\u002Fbackup-restore-context-view",[781],"2024’s Biggest Release Yet! Backup & Restore your Pieces Database",[740,2016,2017],{},[777,2018,2021],{"href":2019,"rel":2020},"https:\u002F\u002Fpieces.app\u002Fchangelog\u002Fdiscover-related-people-set-copilot-context-pieces-for-developers",[781],"Discover Related People, Set Copilot Context, and So Much More",[740,2023,2024],{},[777,2025,2028],{"href":2026,"rel":2027},"https:\u002F\u002Fpieces.app\u002Fchangelog\u002Ffilter-snippet-list-obsidian-jupyterlab",[781],"Filter Your Snippet Lists in Obsidian and Jupyter",[740,2030,2031,2035],{},[777,2032,2034],{"href":2026,"rel":2033},[781],"Lab",[777,2036,2039],{"href":2037,"rel":2038},"https:\u002F\u002Fpieces.app\u002Fchangelog\u002Fgemini-support-search-quick-filters-more-accessible-support-and-more-pieces-for-developers-292-pieces-os-720",[781],"Gemini Support, Search Quick Filters, More Accessible Support",[740,2041,2042],{},[777,2043,2046],{"href":2044,"rel":2045},"https:\u002F\u002Fpieces.app\u002Fchangelog\u002Fhowdy-world",[781],"Howdy World!",[740,2048,2049],{},[777,2050,2053],{"href":2051,"rel":2052},"https:\u002F\u002Fpieces.app\u002Fchangelog\u002Fintroducing-commands-directives-and-more-pieces-copilot-enhancements-pieces-for-developers-vs-code-extension-1100-obsidian-plugin-190-jupyterlab-extension-190",[781],"Introducing Commands, Directives, and Plugin Updates",[740,2055,2056],{},[777,2057,2060],{"href":2058,"rel":2059},"https:\u002F\u002Fpieces.app\u002Fchangelog\u002Fintroducing-the-pieces-for-developers-visual-studio-extension",[781],"Introducing the Pieces for Developers Visual Studio Extension 🎉",[740,2062,2063],{},[777,2064,2067],{"href":2065,"rel":2066},"https:\u002F\u002Fpieces.app\u002Fchangelog\u002Fjetbrains-3-4-2-import-files-to-pieces-filter-your-snippet-list-and-more",[781],"Import Files to Pieces, Filter your Snippet List and More",[740,2069,2070],{},[777,2071,2074],{"href":2072,"rel":2073},"https:\u002F\u002Fpieces.app\u002Fchangelog\u002Fmake-the-pieces-copilot-yours-with-pieces-desktop-app-223",[781],"Make the Pieces Copilot Yours with Customization Features",[740,2076,2077],{},[777,2078,2081],{"href":2079,"rel":2080},"https:\u002F\u002Fpieces.app\u002Fchangelog\u002Fnew-pieces-cli-for-macos",[781],"New! Pieces CLI for macOS",[740,2083,2084],{},[777,2085,2088],{"href":2086,"rel":2087},"https:\u002F\u002Fpieces.app\u002Fchangelog\u002Fnew-search-result-filters-and-continuous-copilot-suggestions-pieces-for-developers-250-pieces-os-610",[781],"New Search Result Filters and Continuous Copilot Suggestions",[740,2090,2091],{},[777,2092,2095],{"href":2093,"rel":2094},"https:\u002F\u002Fpieces.app\u002Fchangelog\u002Four-most-comprehensive-onboarding-overhaul-ever-pieces-for-developers-230",[781],"Our Most Comprehensive Onboarding Overhaul Ever",[740,2097,2098],{},[777,2099,2102],{"href":2100,"rel":2101},"https:\u002F\u002Fpieces.app\u002Fchangelog\u002Fpieces-1-8-0-automatic-snippet-descriptions-json-yaml-toml-support-gen2-sharing",[781],"Automatic Snippet Descriptions, Gen 2 Sharing, and Way More 🔥",[740,2104,2105],{},[777,2106,2109],{"href":2107,"rel":2108},"https:\u002F\u002Fpieces.app\u002Fchangelog\u002Fpieces-copilot-runtime-pieces-for-jetbrains-630",[781],"Snippet Streaming, Pieces Copilot Runtime Manager and more ⭐",[740,2111,2112],{},[777,2113,2116],{"href":2114,"rel":2115},"https:\u002F\u002Fpieces.app\u002Fchangelog\u002Fpieces-desktop-app-193-paste-images-improved-snippet-discovery",[781],"Paste images & improved Snippet Discovery",[740,2118,2119],{},[777,2120,2123],{"href":2121,"rel":2122},"https:\u002F\u002Fpieces.app\u002Fchangelog\u002Fpieces-desktop-app-local-ml-image-enrichment",[781],"More Powerful Local ML Models 💪 and Additional Image Enrichment 🖼️",[740,2125,2126],{},[777,2127,2130],{"href":2128,"rel":2129},"https:\u002F\u002Fpieces.app\u002Fchangelog\u002Fpieces-developers-ai-transformations",[781],"Dropping in Even More AI Transformations, Describe to Generate",[740,2132,2133],{},[777,2134,2137],{"href":2135,"rel":2136},"https:\u002F\u002Fpieces.app\u002Fchangelog\u002Fpieces-for-developers-1-9-2-are-you-seeing-double-try-duplicating-your-code-snippets",[781],"Duplicate Code Snippets for Better Management",[740,2139,2140],{},[777,2141,2144],{"href":2142,"rel":2143},"https:\u002F\u002Fpieces.app\u002Fchangelog\u002Fpieces-for-developers-now-available-for-firefox-and-opera-pieces-for-developers-web-extension-282",[781],"Pieces for Developers Now Available for Firefox and Opera 🔥",[740,2146,2147],{},[777,2148,2151],{"href":2149,"rel":2150},"https:\u002F\u002Fpieces.app\u002Fchangelog\u002Fpieces-for-jetbrains-3-3-3-auto-complete-code-from-your-personal-snippets",[781],"Auto-Complete Code from your Personal Snippets in JetBrains",[740,2153,2154],{},[777,2155,2158],{"href":2156,"rel":2157},"https:\u002F\u002Fpieces.app\u002Fchangelog\u002Fpieces-for-ultraedit-available-for-beta-release",[781],"Pieces for Ultra",[740,2160,2161],{},[777,2162,2164],{"href":2156,"rel":2163},[781],"Edit available for beta release",[740,2166,2167],{},[777,2168,2171],{"href":2169,"rel":2170},"https:\u002F\u002Fpieces.app\u002Fchangelog\u002Fpieces-for-vs-code-030-reactive-snippet-preview-ux-enhancements",[781],"Reactive Snippet Preview & UX Enhancements in VS Code",[740,2173,2174],{},[777,2175,2178],{"href":2176,"rel":2177},"https:\u002F\u002Fpieces.app\u002Fchangelog\u002Fpieces-recap-save-to-pieces-as-git-history-dart-cli-tutorials-and-more",[781],"Save to Pieces As, Git History, Dart CLI tutorials and More",[740,2180,2181,2186],{},[777,2182,2185],{"href":2183,"rel":2184},"https:\u002F\u002Fpieces.app\u002Fchangelog\u002Fpieces-release-1-3-9-integrations-better-search-and-much-more-630d209548fb0",[781],"Integrations, Better Search and Much More!",[777,2187,2190],{"href":2188,"rel":2189},"https:\u002F\u002Fpieces.app\u002Fchangelog\u002Fpieces-release-1-4-vs-code-and-ultraedit-integrations",[781],"VS Code and Ultra",[740,2192,2193,2197],{},[777,2194,2196],{"href":2188,"rel":2195},[781],"Edit Integrations are Live!",[777,2198,2201],{"href":2199,"rel":2200},"https:\u002F\u002Fpieces.app\u002Fchangelog\u002Fpieces-smart-layout-duplicate-transformations",[781],"Smart Layout, Duplicate Transformations, and More 🌟",[740,2203,2204],{},[777,2205,2208],{"href":2206,"rel":2207},"https:\u002F\u002Fpieces.app\u002Fchangelog\u002Fpieces-suite-installer-for-windows-available-in-beta",[781],"Pieces Suite Installer for Windows Available in Beta!",[740,2210,2211],{},[777,2212,2215],{"href":2213,"rel":2214},"https:\u002F\u002Fpieces.app\u002Fchangelog\u002Fpieces-vs-code-suggested-materials-view",[781],"Brand-New Suggested Materials View in VS Code ✨",[740,2217,2218],{},[777,2219,2222],{"href":2220,"rel":2221},"https:\u002F\u002Fpieces.app\u002Fchangelog\u002Fshareable-links-land-in-plugins",[781],"Generate Shareable Links from Any Plugin",[740,2224,2225],{},[777,2226,2229],{"href":2227,"rel":2228},"https:\u002F\u002Fpieces.app\u002Fchangelog\u002Ftemporally-grounded-pieces-copilot-now-available-for-early-access-pieces-for-developers-2111-pieces-os-900-fZf44m0vCJUJ0M",[781],"Temporally Grounded Pieces Copilot now Available for Early Access",{"title":2231,"searchDepth":2232,"depth":2232,"links":2233},"",2,[2234,2235,2236,2240,2246,2253,2257],{"id":684,"depth":2232,"text":685},{"id":731,"depth":2232,"text":732},{"id":785,"depth":2232,"text":786,"children":2237},[2238],{"id":849,"depth":2239,"text":850},3,{"id":975,"depth":2232,"text":976,"children":2241},[2242,2243,2244,2245],{"id":1048,"depth":2239,"text":1049},{"id":1070,"depth":2239,"text":1071},{"id":1107,"depth":2239,"text":1108},{"id":1260,"depth":2239,"text":1261},{"id":1431,"depth":2232,"text":1432,"children":2247},[2248,2249,2250,2251,2252],{"id":1455,"depth":2239,"text":1456},{"id":1470,"depth":2239,"text":1471},{"id":1500,"depth":2239,"text":1501},{"id":1586,"depth":2239,"text":1587},{"id":1723,"depth":2239,"text":1724},{"id":1740,"depth":2232,"text":1741,"children":2254},[2255,2256],{"id":1835,"depth":2239,"text":1836},{"id":1872,"depth":2239,"text":1873},{"id":1915,"depth":2232,"text":1916},null,"Software Development","2022-08-04T00:00:00.000Z","Model-View-ViewModel (MVVM) Architecture is a software pattern that supports separating the UI (which is View) from the backend (Model).",false,"md","https:\u002F\u002Fstorage.googleapis.com\u002Fpieces-marketing-website\u002Fimages\u002Fblog\u002Fusing-mvvm-architecture-in-flutter\u002Fhero.png","MVVM in Flutter.",{},"\u002Fblog\u002Fusing-mvvm-architecture-in-flutter",{"title":673,"description":2261},"blog\u002Fusing-mvvm-architecture-in-flutter","NcOBkm_GKuqq__R4RxYR1OFYSDL4KQlK5utjxt0m7EQ",{"id":2272,"title":674,"body":2273,"description":2277,"draft":2262,"extension":2263,"meta":2280,"navigation":32,"path":2281,"photo":2282,"photoAlt":2258,"seo":2283,"stem":2284,"__hash__":2285},"authors\u002Fauthors\u002Faseem-wangoo.md",{"type":679,"value":2274,"toc":2278},[2275],[687,2276,2277],{},"Aseem is a seasoned software engineer with over 10 years of expertise and leadership experience. Who combines technical proficiency with strategic insight to deliver impactful solutions and guide teams toward success.",{"title":2231,"searchDepth":2232,"depth":2232,"links":2279},[],{},"\u002Fauthors\u002Faseem-wangoo","https:\u002F\u002Fstorage.googleapis.com\u002Fpieces-marketing-website\u002Fimages\u002Fauthors\u002Fplaceholder.svg",{"title":674,"description":2277},"authors\u002Faseem-wangoo","BykQHOcgQJBv43HQCbia0i-Yq_w6EXmHMny9Py5gycQ",{"left":2287,"top":2287,"width":2288,"height":2288,"rotate":2287,"vFlip":2262,"hFlip":2262,"body":2289},0,24,"\u003Cpath fill=\"currentColor\" d=\"m7.825 13l4.9 4.9q.3.3.288.7t-.313.7q-.3.275-.7.288t-.7-.288l-6.6-6.6q-.15-.15-.213-.325T4.426 12t.063-.375t.212-.325l6.6-6.6q.275-.275.688-.275t.712.275q.3.3.3.713t-.3.712L7.825 11H19q.425 0 .713.288T20 12t-.288.713T19 13z\"\u002F>"]