macos_security_scoped_bookmarks 0.1.0 copy "macos_security_scoped_bookmarks: ^0.1.0" to clipboard
macos_security_scoped_bookmarks: ^0.1.0 copied to clipboard

PlatformmacOS

Token-based macOS security-scoped bookmark creation, resolution, and access lifetimes.

example/lib/main.dart

import 'dart:async';
import 'dart:io';

import 'package:file_selector/file_selector.dart';
import 'package:flutter/material.dart';
import 'package:macos_security_scoped_bookmarks/macos_security_scoped_bookmarks.dart';
import 'package:shared_preferences/shared_preferences.dart';

void main() => runApp(const BookmarkExampleApp());

const _bookmarkPreferenceKey = 'securityScopedBookmark';

abstract interface class BookmarkStore {
  Future<MacOSSecurityScopedBookmark?> load();

  Future<void> save(MacOSSecurityScopedBookmark bookmark);
}

final class PreferencesBookmarkStore implements BookmarkStore {
  const PreferencesBookmarkStore();

  @override
  Future<MacOSSecurityScopedBookmark?> load() async {
    final encoded = await SharedPreferencesAsync().getString(
      _bookmarkPreferenceKey,
    );
    if (encoded == null) {
      return null;
    }
    try {
      return MacOSSecurityScopedBookmark.decode(encoded);
    } on FormatException {
      return null;
    }
  }

  @override
  Future<void> save(final MacOSSecurityScopedBookmark bookmark) {
    return SharedPreferencesAsync().setString(
      _bookmarkPreferenceKey,
      bookmark.encode(),
    );
  }
}

class BookmarkExampleApp extends StatelessWidget {
  const BookmarkExampleApp({
    super.key,
    this.store = const PreferencesBookmarkStore(),
  });

  final BookmarkStore store;

  @override
  Widget build(final BuildContext context) {
    return MaterialApp(
      title: 'Security-Scoped Bookmarks',
      theme: ThemeData(colorSchemeSeed: Colors.indigo),
      home: BookmarkExamplePage(store: store),
    );
  }
}

class BookmarkExamplePage extends StatefulWidget {
  const BookmarkExamplePage({required this.store, super.key});

  final BookmarkStore store;

  @override
  State<BookmarkExamplePage> createState() => _BookmarkExamplePageState();
}

class _BookmarkExamplePageState extends State<BookmarkExamplePage> {
  MacOSSecurityScopedBookmark? _bookmark;
  bool _isRestoring = true;
  String _status = 'Restoring any previously saved bookmark…';

  @override
  void initState() {
    super.initState();
    unawaited(_restoreBookmark());
  }

  Future<void> _restoreBookmark() async {
    MacOSSecurityScopedBookmark? bookmark;
    Object? restoreError;
    try {
      bookmark = await widget.store.load();
    } on Object catch (error) {
      restoreError = error;
    }
    if (!mounted) {
      return;
    }
    setState(() {
      _isRestoring = false;
      _bookmark = bookmark;
      _status =
          restoreError != null
              ? 'Could not restore bookmark: $restoreError'
              : bookmark == null
              ? 'Choose a file to create a read-only bookmark.'
              : 'Restored a bookmark saved during an earlier launch.';
    });
  }

  Future<void> _chooseFile() async {
    try {
      final selection = await openFile();
      if (selection == null) {
        return;
      }
      const access = MacOSSecurityScopedBookmarkAccess.readOnly;
      final bookmark = await createBookmark(
        File(selection.path),
        access: access,
      );
      await widget.store.save(bookmark);
      if (!mounted) {
        return;
      }
      setState(() {
        _bookmark = bookmark;
        _status = 'Bookmark created for ${selection.name}.';
      });
    } on Object catch (error) {
      if (!mounted) {
        return;
      }
      setState(() => _status = 'Could not create bookmark: $error');
    }
  }

  Future<void> _resolveAndRead() async {
    final bookmark = _bookmark;
    if (bookmark == null) {
      return;
    }
    try {
      final byteCount = await withBookmarkAccess(bookmark, (
        final resource,
      ) async {
        if (resource.isStale) {
          final refreshedBookmark = await resource.refreshBookmark();
          await widget.store.save(refreshedBookmark);
          _bookmark = refreshedBookmark;
        }
        return (resource.entity as File).length();
      });
      if (!mounted) {
        return;
      }
      setState(() {
        _status = 'Read access succeeded: $byteCount bytes.';
      });
    } on Object catch (error) {
      if (!mounted) {
        return;
      }
      setState(() => _status = 'Could not access bookmark: $error');
    }
  }

  @override
  Widget build(final BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Security-Scoped Bookmarks')),
      body: Center(
        child: ConstrainedBox(
          constraints: const BoxConstraints(maxWidth: 520),
          child: Padding(
            padding: const EdgeInsets.all(32),
            child: Column(
              mainAxisSize: MainAxisSize.min,
              crossAxisAlignment: CrossAxisAlignment.stretch,
              children: [
                Text(_status, textAlign: TextAlign.center),
                const SizedBox(height: 24),
                FilledButton(
                  onPressed: _isRestoring ? null : _chooseFile,
                  child: const Text('Choose file and create bookmark'),
                ),
                const SizedBox(height: 12),
                OutlinedButton(
                  onPressed:
                      _isRestoring || _bookmark == null
                          ? null
                          : _resolveAndRead,
                  child: const Text('Resolve bookmark and read file'),
                ),
              ],
            ),
          ),
        ),
      ),
    );
  }
}
2
likes
160
points
0
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

Token-based macOS security-scoped bookmark creation, resolution, and access lifetimes.

Repository (GitHub)
View/report issues

Topics

#macos #bookmarks #files #security

License

BSD-3-Clause (license)

Dependencies

flutter

More

Packages that depend on macos_security_scoped_bookmarks

Packages that implement macos_security_scoped_bookmarks