@@ -11,12 +11,12 @@ android {
 | 
				
			|||||||
    ndkVersion = flutter.ndkVersion
 | 
					    ndkVersion = flutter.ndkVersion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    compileOptions {
 | 
					    compileOptions {
 | 
				
			||||||
        sourceCompatibility = JavaVersion.VERSION_11
 | 
					        sourceCompatibility = JavaVersion.VERSION_17
 | 
				
			||||||
        targetCompatibility = JavaVersion.VERSION_11
 | 
					        targetCompatibility = JavaVersion.VERSION_17
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    kotlinOptions {
 | 
					    kotlinOptions {
 | 
				
			||||||
        jvmTarget = JavaVersion.VERSION_11.toString()
 | 
					        jvmTarget = JavaVersion.VERSION_17.toString()
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    defaultConfig {
 | 
					    defaultConfig {
 | 
				
			||||||
 
 | 
				
			|||||||
| 
		 Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 1.4 KiB  | 
@@ -1,42 +1,33 @@
 | 
				
			|||||||
import 'package:flutter/material.dart';
 | 
					import 'package:flutter/material.dart';
 | 
				
			||||||
import 'package:flutter/services.dart';
 | 
					import 'package:flutter/services.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import 'package:f0ckapp/providers/MediaProvider.dart';
 | 
					 | 
				
			||||||
import 'package:f0ckapp/providers/ThemeProvider.dart';
 | 
					 | 
				
			||||||
import 'package:f0ckapp/screens/MediaGrid.dart';
 | 
					import 'package:f0ckapp/screens/MediaGrid.dart';
 | 
				
			||||||
import 'package:f0ckapp/utils/AppVersion.dart';
 | 
					import 'package:f0ckapp/utils/AppVersion.dart';
 | 
				
			||||||
 | 
					import 'package:f0ckapp/providers/ThemeProvider.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import 'package:provider/provider.dart';
 | 
					import 'package:flutter_riverpod/flutter_riverpod.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void main() async {
 | 
					void main() async {
 | 
				
			||||||
  WidgetsFlutterBinding.ensureInitialized();
 | 
					  WidgetsFlutterBinding.ensureInitialized();
 | 
				
			||||||
  await SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]);
 | 
					  await SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]);
 | 
				
			||||||
  await AppVersion.init();
 | 
					  await AppVersion.init();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  runApp(
 | 
					  runApp(ProviderScope(child: const F0ckApp()));
 | 
				
			||||||
    MultiProvider(
 | 
					 | 
				
			||||||
      providers: [
 | 
					 | 
				
			||||||
        ChangeNotifierProvider(create: (context) => ThemeProvider()),
 | 
					 | 
				
			||||||
        ChangeNotifierProvider(create: (context) => MediaProvider())
 | 
					 | 
				
			||||||
      ],
 | 
					 | 
				
			||||||
      child: F0ckApp()
 | 
					 | 
				
			||||||
    )
 | 
					 | 
				
			||||||
  );
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class F0ckApp extends StatelessWidget {
 | 
					class F0ckApp extends ConsumerWidget {
 | 
				
			||||||
  const F0ckApp({super.key});
 | 
					  const F0ckApp({super.key});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @override
 | 
					  @override
 | 
				
			||||||
  Widget build(BuildContext context) {
 | 
					  Widget build(BuildContext context, WidgetRef ref) {
 | 
				
			||||||
    final themeProvider = Provider.of<ThemeProvider>(context);
 | 
					    return Consumer(
 | 
				
			||||||
 | 
					      builder: (context, ref, _) {
 | 
				
			||||||
    return MaterialApp(
 | 
					        return MaterialApp(
 | 
				
			||||||
      debugShowCheckedModeBanner: false,
 | 
					          debugShowCheckedModeBanner: false,
 | 
				
			||||||
      theme: themeProvider.themeData,
 | 
					          theme: ref.watch(themeNotifierProvider),
 | 
				
			||||||
      home: Scaffold(
 | 
					          home: const MediaGrid(),
 | 
				
			||||||
        body: MediaGrid(),
 | 
					        );
 | 
				
			||||||
      ),
 | 
					      },
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,123 +1,142 @@
 | 
				
			|||||||
import 'package:flutter/material.dart';
 | 
					import 'package:flutter_riverpod/flutter_riverpod.dart';
 | 
				
			||||||
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
 | 
					import 'package:flutter_secure_storage/flutter_secure_storage.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import 'package:f0ckapp/models/MediaItem.dart';
 | 
					import 'package:f0ckapp/models/MediaItem.dart';
 | 
				
			||||||
import 'package:f0ckapp/services/Api.dart';
 | 
					import 'package:f0ckapp/services/Api.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class MediaProvider extends ChangeNotifier {
 | 
					const List<String> mediaTypes = ["alles", "image", "video", "audio"];
 | 
				
			||||||
  int _typeid = 0;
 | 
					const List<String> mediaModes = ["sfw", "nsfw", "untagged", "all"];
 | 
				
			||||||
  int _mode = 0;
 | 
					const _unsetTag = Object();
 | 
				
			||||||
  bool _random = false;
 | 
					
 | 
				
			||||||
  String? _tag;
 | 
					class MediaState {
 | 
				
			||||||
  int _crossAxisCount = 0;
 | 
					  final int typeIndex;
 | 
				
			||||||
  List<MediaItem> _mediaItems = [];
 | 
					  final int modeIndex;
 | 
				
			||||||
  bool _isLoading = false;
 | 
					  final bool random;
 | 
				
			||||||
  bool _muted = false;
 | 
					  final String? tag;
 | 
				
			||||||
  final storage = FlutterSecureStorage(
 | 
					  final int crossAxisCount;
 | 
				
			||||||
    aOptions: const AndroidOptions(encryptedSharedPreferences: true),
 | 
					  final List<MediaItem> mediaItems;
 | 
				
			||||||
 | 
					  final bool isLoading;
 | 
				
			||||||
 | 
					  final bool muted;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const MediaState({
 | 
				
			||||||
 | 
					    this.typeIndex = 0,
 | 
				
			||||||
 | 
					    this.modeIndex = 0,
 | 
				
			||||||
 | 
					    this.random = false,
 | 
				
			||||||
 | 
					    this.tag,
 | 
				
			||||||
 | 
					    this.crossAxisCount = 0,
 | 
				
			||||||
 | 
					    this.mediaItems = const [],
 | 
				
			||||||
 | 
					    this.isLoading = false,
 | 
				
			||||||
 | 
					    this.muted = false,
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  MediaState replace({
 | 
				
			||||||
 | 
					    int? typeIndex,
 | 
				
			||||||
 | 
					    int? modeIndex,
 | 
				
			||||||
 | 
					    bool? random,
 | 
				
			||||||
 | 
					    Object? tag = _unsetTag,
 | 
				
			||||||
 | 
					    int? crossAxisCount,
 | 
				
			||||||
 | 
					    List<MediaItem>? mediaItems,
 | 
				
			||||||
 | 
					    bool? isLoading,
 | 
				
			||||||
 | 
					    bool? muted,
 | 
				
			||||||
 | 
					  }) {
 | 
				
			||||||
 | 
					    return MediaState(
 | 
				
			||||||
 | 
					      typeIndex: typeIndex ?? this.typeIndex,
 | 
				
			||||||
 | 
					      modeIndex: modeIndex ?? this.modeIndex,
 | 
				
			||||||
 | 
					      random: random ?? this.random,
 | 
				
			||||||
 | 
					      tag: identical(tag, _unsetTag) ? this.tag : tag as String?,
 | 
				
			||||||
 | 
					      crossAxisCount: crossAxisCount ?? this.crossAxisCount,
 | 
				
			||||||
 | 
					      mediaItems: mediaItems ?? this.mediaItems,
 | 
				
			||||||
 | 
					      isLoading: isLoading ?? this.isLoading,
 | 
				
			||||||
 | 
					      muted: muted ?? this.muted,
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class MediaNotifier extends StateNotifier<MediaState> {
 | 
				
			||||||
 | 
					  final _storage = const FlutterSecureStorage(
 | 
				
			||||||
 | 
					    aOptions: AndroidOptions(encryptedSharedPreferences: true),
 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  List<String> types = ["alles", "image", "video", "audio"];
 | 
					  MediaNotifier() : super(const MediaState()) {
 | 
				
			||||||
  List<String> modes = ["sfw", "nsfw", "untagged", "all"];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  String get type => types[_typeid];
 | 
					 | 
				
			||||||
  int get typeid => _typeid;
 | 
					 | 
				
			||||||
  int get mode => _mode;
 | 
					 | 
				
			||||||
  bool get random => _random;
 | 
					 | 
				
			||||||
  String? get tag => _tag;
 | 
					 | 
				
			||||||
  int get crossAxisCount => _crossAxisCount;
 | 
					 | 
				
			||||||
  List<MediaItem> get mediaItems => _mediaItems;
 | 
					 | 
				
			||||||
  bool get isLoading => _isLoading;
 | 
					 | 
				
			||||||
  bool get muted => _muted;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  Function get resetMedia => _resetMedia;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  MediaProvider() {
 | 
					 | 
				
			||||||
    _loadMutedState();
 | 
					    _loadMutedState();
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  void setType(String type) {
 | 
					 | 
				
			||||||
    _typeid = types.indexOf(type);
 | 
					 | 
				
			||||||
    _resetMedia();
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  void setMode(int mode) {
 | 
					 | 
				
			||||||
    _mode = mode;
 | 
					 | 
				
			||||||
    _resetMedia();
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  void toggleRandom() {
 | 
					 | 
				
			||||||
    _random = !_random;
 | 
					 | 
				
			||||||
    _resetMedia();
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  void setTag(String? tag) {
 | 
					 | 
				
			||||||
    _tag = tag;
 | 
					 | 
				
			||||||
    _resetMedia();
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  void setCrossAxisCount(int crossAxisCount) {
 | 
					 | 
				
			||||||
    _crossAxisCount = crossAxisCount;
 | 
					 | 
				
			||||||
    notifyListeners();
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  void setMediaItems(List<MediaItem> mediaItems) {
 | 
					 | 
				
			||||||
    if (_mediaItems != mediaItems) {
 | 
					 | 
				
			||||||
      _mediaItems.clear();
 | 
					 | 
				
			||||||
      _mediaItems.addAll(mediaItems);
 | 
					 | 
				
			||||||
      notifyListeners();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  void addMediaItems(List<MediaItem> newItems) {
 | 
					 | 
				
			||||||
    _mediaItems.addAll(newItems);
 | 
					 | 
				
			||||||
    notifyListeners();
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  void _resetMedia() {
 | 
					 | 
				
			||||||
    _mediaItems.clear();
 | 
					 | 
				
			||||||
    notifyListeners();
 | 
					 | 
				
			||||||
    loadMedia();
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  void toggleMute() {
 | 
					 | 
				
			||||||
    _muted = !_muted;
 | 
					 | 
				
			||||||
    _saveMutedState();
 | 
					 | 
				
			||||||
    notifyListeners();
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  Future<void> _loadMutedState() async {
 | 
					  Future<void> _loadMutedState() async {
 | 
				
			||||||
    _muted = (await storage.read(key: 'muted') == 'true');
 | 
					    final storedMuted = await _storage.read(key: 'muted');
 | 
				
			||||||
    notifyListeners();
 | 
					    final isMuted = storedMuted == 'true';
 | 
				
			||||||
 | 
					    state = state.replace(muted: isMuted);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  Future<void> _saveMutedState() async {
 | 
					  Future<void> _saveMutedState() async {
 | 
				
			||||||
    await storage.write(key: 'muted', value: _muted ? 'false' : 'true');
 | 
					    await _storage.write(key: 'muted', value: state.muted.toString());
 | 
				
			||||||
    notifyListeners();
 | 
					 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  Future<void> loadMedia({bool notify = true}) async {
 | 
					  void setType(String type) {
 | 
				
			||||||
    if (_isLoading) return;
 | 
					    final newIndex = mediaTypes.indexOf(type);
 | 
				
			||||||
    _isLoading = true;
 | 
					    state = state.replace(typeIndex: newIndex);
 | 
				
			||||||
    if (notify) notifyListeners();
 | 
					    resetMedia();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  void setMode(int modeIndex) {
 | 
				
			||||||
 | 
					    state = state.replace(modeIndex: modeIndex);
 | 
				
			||||||
 | 
					    resetMedia();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  void toggleRandom() {
 | 
				
			||||||
 | 
					    state = state.replace(random: !state.random);
 | 
				
			||||||
 | 
					    resetMedia();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  void setTag(String? tag) {
 | 
				
			||||||
 | 
					    state = state.replace(tag: tag);
 | 
				
			||||||
 | 
					    resetMedia();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  void setCrossAxisCount(int count) {
 | 
				
			||||||
 | 
					    state = state.replace(crossAxisCount: count);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  void resetMedia() {
 | 
				
			||||||
 | 
					    state = state.replace(mediaItems: []);
 | 
				
			||||||
 | 
					    loadMedia();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  void addMediaItems(List<MediaItem> newItems) {
 | 
				
			||||||
 | 
					    final updated = List<MediaItem>.from(state.mediaItems)..addAll(newItems);
 | 
				
			||||||
 | 
					    state = state.replace(mediaItems: updated);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  Future<void> loadMedia() async {
 | 
				
			||||||
 | 
					    if (state.isLoading) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    state = state.replace(isLoading: true);
 | 
				
			||||||
    try {
 | 
					    try {
 | 
				
			||||||
 | 
					      final older = state.mediaItems.isNotEmpty
 | 
				
			||||||
 | 
					          ? state.mediaItems.last.id
 | 
				
			||||||
 | 
					          : null;
 | 
				
			||||||
      final newMedia = await fetchMedia(
 | 
					      final newMedia = await fetchMedia(
 | 
				
			||||||
        older: _mediaItems.isNotEmpty ? _mediaItems.last.id : null,
 | 
					        older: older,
 | 
				
			||||||
        type: type,
 | 
					        type: mediaTypes[state.typeIndex],
 | 
				
			||||||
        mode: mode,
 | 
					        mode: state.modeIndex,
 | 
				
			||||||
        random: random,
 | 
					        random: state.random,
 | 
				
			||||||
        tag: tag,
 | 
					        tag: state.tag,
 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
 | 
					      if (newMedia.isNotEmpty) {
 | 
				
			||||||
      if (_mediaItems != newMedia) {
 | 
					 | 
				
			||||||
        addMediaItems(newMedia);
 | 
					        addMediaItems(newMedia);
 | 
				
			||||||
        if (notify) notifyListeners();
 | 
					 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    } catch (e) {
 | 
					    } catch (e) {
 | 
				
			||||||
      debugPrint('Fehler beim Laden der Medien: $e');
 | 
					      print('Fehler beim Laden der Medien: $e');
 | 
				
			||||||
    } finally {
 | 
					    } finally {
 | 
				
			||||||
      _isLoading = false;
 | 
					      state = state.replace(isLoading: false);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  void toggleMute() {
 | 
				
			||||||
 | 
					    state = state.replace(muted: !state.muted);
 | 
				
			||||||
 | 
					    _saveMutedState();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					final mediaProvider = StateNotifierProvider<MediaNotifier, MediaState>(
 | 
				
			||||||
 | 
					  (ref) => MediaNotifier(),
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,132 +1,236 @@
 | 
				
			|||||||
import 'package:flutter/material.dart';
 | 
					import 'package:flutter/material.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import 'package:flutter_secure_storage/flutter_secure_storage.dart';
 | 
				
			||||||
 | 
					import 'package:flutter_riverpod/flutter_riverpod.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ThemeNotifier extends StateNotifier<ThemeData> {
 | 
				
			||||||
 | 
					  final FlutterSecureStorage secureStorage;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  ThemeNotifier({required this.secureStorage}) : super(f0ckTheme) {
 | 
				
			||||||
 | 
					    _loadTheme();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  Future<void> _loadTheme() async {
 | 
				
			||||||
 | 
					    String? savedThemeName = await secureStorage.read(key: 'theme');
 | 
				
			||||||
 | 
					    if (savedThemeName != null) {
 | 
				
			||||||
 | 
					      final customTheme = themes.firstWhere(
 | 
				
			||||||
 | 
					        (t) => t.name == savedThemeName,
 | 
				
			||||||
 | 
					        orElse: () => CustomTheme(name: 'f0ck', theme: f0ckTheme),
 | 
				
			||||||
 | 
					      );
 | 
				
			||||||
 | 
					      state = customTheme.theme;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  Future<void> updateTheme(String themeName) async {
 | 
				
			||||||
 | 
					    await secureStorage.write(key: 'theme', value: themeName);
 | 
				
			||||||
 | 
					    final newTheme = themes.firstWhere(
 | 
				
			||||||
 | 
					      (t) => t.name == themeName,
 | 
				
			||||||
 | 
					      orElse: () => CustomTheme(name: 'f0ck', theme: f0ckTheme),
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					    state = newTheme.theme;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					final themeNotifierProvider = StateNotifierProvider<ThemeNotifier, ThemeData>((
 | 
				
			||||||
 | 
					  ref,
 | 
				
			||||||
 | 
					) {
 | 
				
			||||||
 | 
					  return ThemeNotifier(secureStorage: FlutterSecureStorage());
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class CustomTheme {
 | 
				
			||||||
 | 
					  final String name;
 | 
				
			||||||
 | 
					  final ThemeData theme;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  CustomTheme({required this.name, required this.theme});
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					final List<CustomTheme> themes = [
 | 
				
			||||||
 | 
					  CustomTheme(name: 'f0ck', theme: f0ckTheme),
 | 
				
			||||||
 | 
					  CustomTheme(name: 'Paper', theme: paperTheme),
 | 
				
			||||||
 | 
					  CustomTheme(name: 'Orange', theme: orangeTheme),
 | 
				
			||||||
 | 
					  CustomTheme(name: 'Amoled', theme: amoledTheme),
 | 
				
			||||||
 | 
					  CustomTheme(name: 'f0ck95', theme: f0ck95Theme),
 | 
				
			||||||
 | 
					  CustomTheme(name: 'f0ck95d', theme: f0ck95dTheme),
 | 
				
			||||||
 | 
					];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
final ThemeData f0ckTheme = ThemeData(
 | 
					final ThemeData f0ckTheme = ThemeData(
 | 
				
			||||||
  brightness: Brightness.dark,
 | 
					  brightness: Brightness.dark,
 | 
				
			||||||
  primaryColor: Color(0xFF9FFF00),
 | 
					  primaryColor: const Color(0xFF9FFF00),
 | 
				
			||||||
  scaffoldBackgroundColor: Color(0xFF000000),
 | 
					  scaffoldBackgroundColor: const Color(0xFF000000),
 | 
				
			||||||
  colorScheme: ColorScheme.dark(
 | 
					  colorScheme: const ColorScheme.dark(
 | 
				
			||||||
    primary: Color(0xFF9FFF00),
 | 
					    primary: Color(0xFF9FFF00),
 | 
				
			||||||
    secondary: Color(0xFF262626),
 | 
					    secondary: Color(0xFF262626),
 | 
				
			||||||
    surface: Color(0xFF232323),
 | 
					    surface: Color(0xFF232323),
 | 
				
			||||||
    onPrimary: Color(0xFF000000),
 | 
					    onPrimary: Color(0xFF000000),
 | 
				
			||||||
    onSecondary: Color(0xFFFFFFFF),
 | 
					    onSecondary: Colors.white,
 | 
				
			||||||
    onSurface: Color(0xFFFFFFFF),
 | 
					    onSurface: Colors.white,
 | 
				
			||||||
  ),
 | 
					  ),
 | 
				
			||||||
  appBarTheme: AppBarTheme(
 | 
					  appBarTheme: const AppBarTheme(
 | 
				
			||||||
    backgroundColor: Color(0xFF2B2B2B),
 | 
					    backgroundColor: Color(0xFF2B2B2B),
 | 
				
			||||||
    foregroundColor: Color(0xFF9FFF00),
 | 
					    foregroundColor: Color(0xFF9FFF00),
 | 
				
			||||||
    elevation: 2,
 | 
					    elevation: 2,
 | 
				
			||||||
  ),
 | 
					  ),
 | 
				
			||||||
  textTheme: TextTheme(
 | 
					  textTheme: const TextTheme(
 | 
				
			||||||
    bodyLarge: TextStyle(fontFamily: 'VCR', color: Color(0xFFFFFFFF)),
 | 
					    bodyLarge: TextStyle(color: Colors.white),
 | 
				
			||||||
    bodyMedium: TextStyle(fontFamily: 'monospace', color: Color(0xFFFFFFFF)),
 | 
					    bodyMedium: TextStyle(color: Colors.white),
 | 
				
			||||||
  ),
 | 
					  ),
 | 
				
			||||||
  buttonTheme: ButtonThemeData(
 | 
					  buttonTheme: ButtonThemeData(
 | 
				
			||||||
    buttonColor: Color(0xFF9FFF00),
 | 
					    buttonColor: const Color(0xFF9FFF00),
 | 
				
			||||||
    textTheme: ButtonTextTheme.primary,
 | 
					    textTheme: ButtonTextTheme.primary,
 | 
				
			||||||
  ),
 | 
					  ),
 | 
				
			||||||
  scrollbarTheme: ScrollbarThemeData(
 | 
					  scrollbarTheme: ScrollbarThemeData(
 | 
				
			||||||
    thumbColor: WidgetStateProperty.all(Color(0xFF2B2B2B)),
 | 
					    thumbColor: WidgetStatePropertyAll<Color>(Color(0xFF2B2B2B)),
 | 
				
			||||||
    trackColor: WidgetStateProperty.all(Color(0xFF424242)),
 | 
					    trackColor: WidgetStatePropertyAll<Color>(Color(0xFF424242)),
 | 
				
			||||||
  ),
 | 
					  ),
 | 
				
			||||||
);
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
final ThemeData paperTheme = ThemeData(
 | 
					final ThemeData paperTheme = ThemeData(
 | 
				
			||||||
  brightness: Brightness.light,
 | 
					  brightness: Brightness.light,
 | 
				
			||||||
  primaryColor: Color(0xFF000000),
 | 
					  primaryColor: const Color(0xFF000000),
 | 
				
			||||||
  scaffoldBackgroundColor: Color(0xFFFFFFFF),
 | 
					  scaffoldBackgroundColor: const Color(0xFFFFFFFF),
 | 
				
			||||||
  colorScheme: ColorScheme.light(
 | 
					  colorScheme: const ColorScheme.light(
 | 
				
			||||||
    primary: Color(0xFF000000),
 | 
					    primary: Color(0xFF000000),
 | 
				
			||||||
    secondary: Color(0xFF262626),
 | 
					    secondary: Color(0xFF262626),
 | 
				
			||||||
    surface: Color(0xFFFFFFFF),
 | 
					    surface: Color(0xFFFFFFFF),
 | 
				
			||||||
    onPrimary: Color(0xFFFFFFFF),
 | 
					    onPrimary: Colors.white,
 | 
				
			||||||
    onSecondary: Color(0xFFFFFFFF),
 | 
					    onSecondary: Colors.white,
 | 
				
			||||||
    onSurface: Color(0xFF000000),
 | 
					    onSurface: Color(0xFF000000),
 | 
				
			||||||
  ),
 | 
					  ),
 | 
				
			||||||
  appBarTheme: AppBarTheme(
 | 
					  appBarTheme: const AppBarTheme(
 | 
				
			||||||
    backgroundColor: Color(0xFFFFFFFF),
 | 
					    backgroundColor: Color(0xFFFFFFFF),
 | 
				
			||||||
    foregroundColor: Color(0xFF000000),
 | 
					    foregroundColor: Color(0xFF000000),
 | 
				
			||||||
    elevation: 0,
 | 
					    elevation: 0,
 | 
				
			||||||
  ),
 | 
					  ),
 | 
				
			||||||
  textTheme: TextTheme(
 | 
					  textTheme: const TextTheme(
 | 
				
			||||||
    bodyLarge: TextStyle(fontFamily: 'VCR', color: Color(0xFF000000)),
 | 
					    bodyLarge: TextStyle(color: Color(0xFF000000)),
 | 
				
			||||||
    bodyMedium: TextStyle(fontFamily: 'monospace', color: Color(0xFF000000)),
 | 
					    bodyMedium: TextStyle(color: Color(0xFF000000)),
 | 
				
			||||||
  ),
 | 
					  ),
 | 
				
			||||||
  buttonTheme: ButtonThemeData(
 | 
					  buttonTheme: ButtonThemeData(
 | 
				
			||||||
    buttonColor: Color(0xFF000000),
 | 
					    buttonColor: const Color(0xFF000000),
 | 
				
			||||||
    textTheme: ButtonTextTheme.primary,
 | 
					    textTheme: ButtonTextTheme.primary,
 | 
				
			||||||
  ),
 | 
					  ),
 | 
				
			||||||
);
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					final ThemeData orangeTheme = ThemeData(
 | 
				
			||||||
 | 
					  brightness: Brightness.dark,
 | 
				
			||||||
 | 
					  primaryColor: const Color(0xFFFF6F00),
 | 
				
			||||||
 | 
					  scaffoldBackgroundColor: const Color(0xFF171717),
 | 
				
			||||||
 | 
					  colorScheme: const ColorScheme.dark(
 | 
				
			||||||
 | 
					    primary: Color(0xFFFF6F00),
 | 
				
			||||||
 | 
					    secondary: Color(0xFF262626),
 | 
				
			||||||
 | 
					    surface: Color(0xFF232323),
 | 
				
			||||||
 | 
					    onPrimary: Colors.white,
 | 
				
			||||||
 | 
					    onSecondary: Colors.white,
 | 
				
			||||||
 | 
					    onSurface: Colors.white,
 | 
				
			||||||
 | 
					  ),
 | 
				
			||||||
 | 
					  appBarTheme: const AppBarTheme(
 | 
				
			||||||
 | 
					    backgroundColor: Color(0xFF2B2B2B),
 | 
				
			||||||
 | 
					    foregroundColor: Color(0xFFFF6F00),
 | 
				
			||||||
 | 
					    elevation: 2,
 | 
				
			||||||
 | 
					  ),
 | 
				
			||||||
 | 
					  textTheme: const TextTheme(
 | 
				
			||||||
 | 
					    bodyLarge: TextStyle(color: Colors.white),
 | 
				
			||||||
 | 
					    bodyMedium: TextStyle(color: Colors.white),
 | 
				
			||||||
 | 
					  ),
 | 
				
			||||||
 | 
					  buttonTheme: ButtonThemeData(
 | 
				
			||||||
 | 
					    buttonColor: const Color(0xFFFF6F00),
 | 
				
			||||||
 | 
					    textTheme: ButtonTextTheme.primary,
 | 
				
			||||||
 | 
					  ),
 | 
				
			||||||
 | 
					  scrollbarTheme: ScrollbarThemeData(
 | 
				
			||||||
 | 
					    thumbColor: WidgetStatePropertyAll<Color>(Color(0xFF2B2B2B)),
 | 
				
			||||||
 | 
					    trackColor: WidgetStatePropertyAll<Color>(Color(0xFF424242)),
 | 
				
			||||||
 | 
					  ),
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					final ThemeData amoledTheme = ThemeData(
 | 
				
			||||||
 | 
					  brightness: Brightness.dark,
 | 
				
			||||||
 | 
					  primaryColor: const Color(0xFFFFFFFF),
 | 
				
			||||||
 | 
					  scaffoldBackgroundColor: const Color(0xFF000000),
 | 
				
			||||||
 | 
					  canvasColor: const Color(0xFF000000),
 | 
				
			||||||
 | 
					  cardColor: const Color(0xFF000000),
 | 
				
			||||||
 | 
					  colorScheme: const ColorScheme.dark(
 | 
				
			||||||
 | 
					    primary: Color(0xFFFFFFFF),
 | 
				
			||||||
 | 
					    secondary: Color(0xFF1F1F1F),
 | 
				
			||||||
 | 
					    surface: Color(0xFF000000),
 | 
				
			||||||
 | 
					    onPrimary: Color(0xFF000000),
 | 
				
			||||||
 | 
					    onSecondary: Colors.white,
 | 
				
			||||||
 | 
					    onSurface: Colors.white,
 | 
				
			||||||
 | 
					  ),
 | 
				
			||||||
 | 
					  appBarTheme: const AppBarTheme(
 | 
				
			||||||
 | 
					    backgroundColor: Color(0xFF000000),
 | 
				
			||||||
 | 
					    foregroundColor: Colors.white,
 | 
				
			||||||
 | 
					    elevation: 2,
 | 
				
			||||||
 | 
					  ),
 | 
				
			||||||
 | 
					  textTheme: const TextTheme(
 | 
				
			||||||
 | 
					    bodyLarge: TextStyle(color: Colors.white),
 | 
				
			||||||
 | 
					    bodyMedium: TextStyle(color: Colors.white),
 | 
				
			||||||
 | 
					  ),
 | 
				
			||||||
 | 
					  buttonTheme: ButtonThemeData(
 | 
				
			||||||
 | 
					    buttonColor: const Color(0xFFFFFFFF),
 | 
				
			||||||
 | 
					    textTheme: ButtonTextTheme.primary,
 | 
				
			||||||
 | 
					  ),
 | 
				
			||||||
 | 
					  scrollbarTheme: ScrollbarThemeData(
 | 
				
			||||||
 | 
					    thumbColor: WidgetStateProperty.all<Color>(const Color(0xFF1D1C1C)),
 | 
				
			||||||
 | 
					    trackColor: WidgetStateProperty.all<Color>(const Color(0xFF000000)),
 | 
				
			||||||
 | 
					  ),
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
final ThemeData f0ck95Theme = ThemeData(
 | 
					final ThemeData f0ck95Theme = ThemeData(
 | 
				
			||||||
  brightness: Brightness.light,
 | 
					  brightness: Brightness.light,
 | 
				
			||||||
  primaryColor: Color(0xFFC0C0C0),
 | 
					  primaryColor: const Color(0xFFC0C0C0),
 | 
				
			||||||
  scaffoldBackgroundColor: Color(0xFF008080),
 | 
					  scaffoldBackgroundColor: const Color(0xFF008080),
 | 
				
			||||||
  colorScheme: ColorScheme.light(
 | 
					  colorScheme: const ColorScheme.light(
 | 
				
			||||||
    primary: Color(0xFFC0C0C0),
 | 
					    primary: Color(0xFFC0C0C0),
 | 
				
			||||||
    secondary: Color(0xFF808080),
 | 
					    secondary: Color(0xFF808080),
 | 
				
			||||||
    surface: Color(0xFFC0C0C0),
 | 
					    surface: Color(0xFFC0C0C0),
 | 
				
			||||||
    onPrimary: Color(0xFF000000),
 | 
					    onPrimary: Colors.black,
 | 
				
			||||||
    onSecondary: Color(0xFFFFFFFF),
 | 
					    onSecondary: Colors.white,
 | 
				
			||||||
  ),
 | 
					  ),
 | 
				
			||||||
  appBarTheme: AppBarTheme(
 | 
					  appBarTheme: const AppBarTheme(
 | 
				
			||||||
    backgroundColor: Color(0xFFC0C0C0),
 | 
					    backgroundColor: Color(0xFFC0C0C0),
 | 
				
			||||||
    foregroundColor: Color(0xFF000000),
 | 
					    foregroundColor: Colors.black,
 | 
				
			||||||
    elevation: 2,
 | 
					    elevation: 2,
 | 
				
			||||||
  ),
 | 
					  ),
 | 
				
			||||||
  textTheme: TextTheme(
 | 
					  textTheme: const TextTheme(
 | 
				
			||||||
    bodyLarge: TextStyle(fontFamily: 'VCR', color: Color(0xFF000000)),
 | 
					    bodyLarge: TextStyle(color: Colors.black),
 | 
				
			||||||
    bodyMedium: TextStyle(fontFamily: 'monospace', color: Color(0xFF000000)),
 | 
					    bodyMedium: TextStyle(color: Colors.black),
 | 
				
			||||||
  ),
 | 
					  ),
 | 
				
			||||||
  buttonTheme: ButtonThemeData(
 | 
					  buttonTheme: ButtonThemeData(
 | 
				
			||||||
    buttonColor: Color(0xFF000000),
 | 
					    buttonColor: Colors.black,
 | 
				
			||||||
    textTheme: ButtonTextTheme.primary,
 | 
					    textTheme: ButtonTextTheme.primary,
 | 
				
			||||||
  ),
 | 
					  ),
 | 
				
			||||||
  scrollbarTheme: ScrollbarThemeData(
 | 
					  scrollbarTheme: ScrollbarThemeData(
 | 
				
			||||||
    thumbColor: WidgetStateProperty.all(Color(0xFF2B2B2B)),
 | 
					    thumbColor: WidgetStatePropertyAll<Color>(Color(0xFF2B2B2B)),
 | 
				
			||||||
    trackColor: WidgetStateProperty.all(Color(0xFF424242)),
 | 
					    trackColor: WidgetStatePropertyAll<Color>(Color(0xFF424242)),
 | 
				
			||||||
  ),
 | 
					  ),
 | 
				
			||||||
);
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
final ThemeData f0ck95dTheme = ThemeData(
 | 
					final ThemeData f0ck95dTheme = ThemeData(
 | 
				
			||||||
  brightness: Brightness.dark,
 | 
					  brightness: Brightness.dark,
 | 
				
			||||||
  primaryColor: Color(0xFFFFFFFF),
 | 
					  primaryColor: const Color(0xFFFFFFFF),
 | 
				
			||||||
  scaffoldBackgroundColor: Color(0xFF0E0F0F),
 | 
					  scaffoldBackgroundColor: const Color(0xFF0E0F0F),
 | 
				
			||||||
  colorScheme: ColorScheme.dark(
 | 
					  colorScheme: const ColorScheme.dark(
 | 
				
			||||||
    primary: Color(0xFFFFFFFF),
 | 
					    primary: Color(0xFFFFFFFF),
 | 
				
			||||||
    secondary: Color(0xFFC0C0C0),
 | 
					    secondary: Color(0xFFC0C0C0),
 | 
				
			||||||
    surface: Color(0xFF333131),
 | 
					    surface: Color(0xFF333131),
 | 
				
			||||||
    onPrimary: Color(0xFF000000),
 | 
					    onPrimary: Colors.black,
 | 
				
			||||||
    onSecondary: Color(0xFFFFFFFF),
 | 
					    onSecondary: Colors.white,
 | 
				
			||||||
  ),
 | 
					  ),
 | 
				
			||||||
  appBarTheme: AppBarTheme(
 | 
					  appBarTheme: const AppBarTheme(
 | 
				
			||||||
    backgroundColor: Color(0xFF0B0A0A),
 | 
					    backgroundColor: Color(0xFF0B0A0A),
 | 
				
			||||||
    foregroundColor: Color(0xFFFFFFFF),
 | 
					    foregroundColor: Colors.white,
 | 
				
			||||||
    elevation: 2,
 | 
					    elevation: 2,
 | 
				
			||||||
  ),
 | 
					  ),
 | 
				
			||||||
  textTheme: TextTheme(
 | 
					  textTheme: const TextTheme(
 | 
				
			||||||
    bodyLarge: TextStyle(fontFamily: 'VCR', color: Color(0xFFFFFFFF)),
 | 
					    bodyLarge: TextStyle(color: Colors.white),
 | 
				
			||||||
    bodyMedium: TextStyle(fontFamily: 'monospace', color: Color(0xFFFFFFFF)),
 | 
					    bodyMedium: TextStyle(color: Colors.white),
 | 
				
			||||||
  ),
 | 
					  ),
 | 
				
			||||||
  buttonTheme: ButtonThemeData(
 | 
					  buttonTheme: ButtonThemeData(
 | 
				
			||||||
    buttonColor: Color(0xFFFFFFFF),
 | 
					    buttonColor: Colors.white,
 | 
				
			||||||
    textTheme: ButtonTextTheme.primary,
 | 
					    textTheme: ButtonTextTheme.primary,
 | 
				
			||||||
  ),
 | 
					  ),
 | 
				
			||||||
  scrollbarTheme: ScrollbarThemeData(
 | 
					  scrollbarTheme: ScrollbarThemeData(
 | 
				
			||||||
    thumbColor: WidgetStateProperty.all(Color(0xFF2B2B2B)),
 | 
					    thumbColor: WidgetStatePropertyAll<Color>(Color(0xFF2B2B2B)),
 | 
				
			||||||
    trackColor: WidgetStateProperty.all(Color(0xFF424242)),
 | 
					    trackColor: WidgetStatePropertyAll<Color>(Color(0xFF424242)),
 | 
				
			||||||
  ),
 | 
					  ),
 | 
				
			||||||
);
 | 
					);
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class ThemeProvider extends ChangeNotifier {
 | 
					 | 
				
			||||||
  ThemeData _themeData = f0ck95dTheme;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  ThemeData get themeData => _themeData;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  /*void toggleTheme() {
 | 
					 | 
				
			||||||
    _themeData = _themeData == lightTheme ? darkTheme : lightTheme;
 | 
					 | 
				
			||||||
    notifyListeners();
 | 
					 | 
				
			||||||
  }*/
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,27 +2,28 @@ import 'dart:io';
 | 
				
			|||||||
import 'dart:typed_data';
 | 
					import 'dart:typed_data';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import 'package:flutter/material.dart';
 | 
					import 'package:flutter/material.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import 'package:cached_network_image/cached_network_image.dart';
 | 
					import 'package:cached_network_image/cached_network_image.dart';
 | 
				
			||||||
import 'package:provider/provider.dart';
 | 
					import 'package:flutter_riverpod/flutter_riverpod.dart';
 | 
				
			||||||
 | 
					import 'package:flutter_cache_manager/flutter_cache_manager.dart';
 | 
				
			||||||
 | 
					import 'package:share_plus/share_plus.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import 'package:f0ckapp/models/MediaItem.dart';
 | 
					import 'package:f0ckapp/models/MediaItem.dart';
 | 
				
			||||||
import 'package:f0ckapp/services/Api.dart';
 | 
					 | 
				
			||||||
import 'package:f0ckapp/widgets/VideoWidget.dart';
 | 
					import 'package:f0ckapp/widgets/VideoWidget.dart';
 | 
				
			||||||
import 'package:f0ckapp/utils/SmartRefreshIndicator.dart';
 | 
					import 'package:f0ckapp/utils/SmartRefreshIndicator.dart';
 | 
				
			||||||
import 'package:f0ckapp/utils/PageTransformer.dart';
 | 
					import 'package:f0ckapp/utils/PageTransformer.dart';
 | 
				
			||||||
import 'package:f0ckapp/providers/MediaProvider.dart';
 | 
					import 'package:f0ckapp/providers/MediaProvider.dart';
 | 
				
			||||||
import 'package:flutter_cache_manager/flutter_cache_manager.dart';
 | 
					 | 
				
			||||||
import 'package:share_plus/share_plus.dart';
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
class DetailView extends StatefulWidget {
 | 
					class DetailView extends ConsumerStatefulWidget {
 | 
				
			||||||
  final int initialItemId;
 | 
					  final int initialItemId;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const DetailView({super.key, required this.initialItemId});
 | 
					  const DetailView({super.key, required this.initialItemId});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @override
 | 
					  @override
 | 
				
			||||||
  State createState() => _DetailViewState();
 | 
					  ConsumerState<DetailView> createState() => _DetailViewState();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class _DetailViewState extends State<DetailView> {
 | 
					class _DetailViewState extends ConsumerState<DetailView> {
 | 
				
			||||||
  late PageController _pageController;
 | 
					  late PageController _pageController;
 | 
				
			||||||
  bool isLoading = false;
 | 
					  bool isLoading = false;
 | 
				
			||||||
  int _currentIndex = 0;
 | 
					  int _currentIndex = 0;
 | 
				
			||||||
@@ -30,15 +31,14 @@ class _DetailViewState extends State<DetailView> {
 | 
				
			|||||||
  @override
 | 
					  @override
 | 
				
			||||||
  void initState() {
 | 
					  void initState() {
 | 
				
			||||||
    super.initState();
 | 
					    super.initState();
 | 
				
			||||||
    final provider = Provider.of<MediaProvider>(context, listen: false);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    final initialIndex = provider.mediaItems.indexWhere(
 | 
					    final mediaState = ref.read(mediaProvider);
 | 
				
			||||||
 | 
					    final initialIndex = mediaState.mediaItems.indexWhere(
 | 
				
			||||||
      (item) => item.id == widget.initialItemId,
 | 
					      (item) => item.id == widget.initialItemId,
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
 | 
					 | 
				
			||||||
    _pageController = PageController(initialPage: initialIndex);
 | 
					    _pageController = PageController(initialPage: initialIndex);
 | 
				
			||||||
 | 
					 | 
				
			||||||
    _currentIndex = initialIndex;
 | 
					    _currentIndex = initialIndex;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    _pageController.addListener(() {
 | 
					    _pageController.addListener(() {
 | 
				
			||||||
      setState(() => _currentIndex = _pageController.page?.round() ?? 0);
 | 
					      setState(() => _currentIndex = _pageController.page?.round() ?? 0);
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
@@ -47,16 +47,15 @@ class _DetailViewState extends State<DetailView> {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  void _preloadAdjacentMedia(int index) async {
 | 
					  void _preloadAdjacentMedia(int index) async {
 | 
				
			||||||
    final provider = Provider.of<MediaProvider>(context, listen: false);
 | 
					    final mediaState = ref.read(mediaProvider);
 | 
				
			||||||
    if (index + 1 < provider.mediaItems.length) {
 | 
					    if (index + 1 < mediaState.mediaItems.length) {
 | 
				
			||||||
      final nextUrl = provider.mediaItems[index + 1].mediaUrl;
 | 
					      final nextUrl = mediaState.mediaItems[index + 1].mediaUrl;
 | 
				
			||||||
      if (await DefaultCacheManager().getFileFromCache(nextUrl) == null) {
 | 
					      if (await DefaultCacheManager().getFileFromCache(nextUrl) == null) {
 | 
				
			||||||
        await DefaultCacheManager().downloadFile(nextUrl);
 | 
					        await DefaultCacheManager().downloadFile(nextUrl);
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (index - 1 >= 0) {
 | 
					    if (index - 1 >= 0) {
 | 
				
			||||||
      final prevUrl = provider.mediaItems[index - 1].mediaUrl;
 | 
					      final prevUrl = mediaState.mediaItems[index - 1].mediaUrl;
 | 
				
			||||||
      if (await DefaultCacheManager().getFileFromCache(prevUrl) == null) {
 | 
					      if (await DefaultCacheManager().getFileFromCache(prevUrl) == null) {
 | 
				
			||||||
        await DefaultCacheManager().downloadFile(prevUrl);
 | 
					        await DefaultCacheManager().downloadFile(prevUrl);
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
@@ -67,19 +66,8 @@ class _DetailViewState extends State<DetailView> {
 | 
				
			|||||||
    if (isLoading) return;
 | 
					    if (isLoading) return;
 | 
				
			||||||
    setState(() => isLoading = true);
 | 
					    setState(() => isLoading = true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    final provider = Provider.of<MediaProvider>(context, listen: false);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    try {
 | 
					    try {
 | 
				
			||||||
      final newMedia = await fetchMedia(
 | 
					      await ref.read(mediaProvider.notifier).loadMedia();
 | 
				
			||||||
        older: provider.mediaItems.last.id,
 | 
					 | 
				
			||||||
        type: provider.type,
 | 
					 | 
				
			||||||
        mode: provider.mode,
 | 
					 | 
				
			||||||
        random: provider.random,
 | 
					 | 
				
			||||||
        tag: provider.tag,
 | 
					 | 
				
			||||||
      );
 | 
					 | 
				
			||||||
      if (mounted && newMedia.isNotEmpty) {
 | 
					 | 
				
			||||||
        setState(() => provider.mediaItems.addAll(newMedia));
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    } catch (e) {
 | 
					    } catch (e) {
 | 
				
			||||||
      _showError("Fehler beim Laden der Medien: $e");
 | 
					      _showError("Fehler beim Laden der Medien: $e");
 | 
				
			||||||
    } finally {
 | 
					    } finally {
 | 
				
			||||||
@@ -89,41 +77,49 @@ class _DetailViewState extends State<DetailView> {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  void _showError(String message) {
 | 
					  void _showError(String message) {
 | 
				
			||||||
    if (!mounted) return;
 | 
					    if (!mounted) return;
 | 
				
			||||||
    ScaffoldMessenger.of(
 | 
					    ScaffoldMessenger.of(context)
 | 
				
			||||||
      context,
 | 
					      ..removeCurrentSnackBar()
 | 
				
			||||||
    ).showSnackBar(SnackBar(content: Text(message)));
 | 
					      ..showSnackBar(SnackBar(content: Text(message)));
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  void dispose() {
 | 
				
			||||||
 | 
					    _pageController.dispose();
 | 
				
			||||||
 | 
					    super.dispose();
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @override
 | 
					  @override
 | 
				
			||||||
  Widget build(BuildContext context) {
 | 
					  Widget build(BuildContext context) {
 | 
				
			||||||
    final provider = Provider.of<MediaProvider>(context);
 | 
					    final mediaState = ref.watch(mediaProvider);
 | 
				
			||||||
 | 
					    final mediaNotifier = ref.read(mediaProvider.notifier);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (mediaState.mediaItems.isEmpty) {
 | 
				
			||||||
 | 
					      return Scaffold(
 | 
				
			||||||
 | 
					        appBar: AppBar(),
 | 
				
			||||||
 | 
					        body: const Center(child: CircularProgressIndicator()),
 | 
				
			||||||
 | 
					      );
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return Scaffold(
 | 
					    return Scaffold(
 | 
				
			||||||
      appBar: AppBar(
 | 
					      appBar: AppBar(
 | 
				
			||||||
        centerTitle: true,
 | 
					        centerTitle: true,
 | 
				
			||||||
        title: Text(
 | 
					        title: Text('f0ck #${mediaState.mediaItems[_currentIndex].id}'),
 | 
				
			||||||
          'f0ck #${provider.mediaItems.elementAt(_currentIndex).id.toString()}',
 | 
					 | 
				
			||||||
        ),
 | 
					 | 
				
			||||||
        actions: [
 | 
					        actions: [
 | 
				
			||||||
          IconButton(
 | 
					          IconButton(
 | 
				
			||||||
            icon: Icon(
 | 
					            icon: Icon(mediaState.muted ? Icons.volume_off : Icons.volume_up),
 | 
				
			||||||
              provider.muted ? Icons.volume_up : Icons.volume_off,
 | 
					 | 
				
			||||||
              color: Colors.white,
 | 
					 | 
				
			||||||
            ),
 | 
					 | 
				
			||||||
            onPressed: () {
 | 
					            onPressed: () {
 | 
				
			||||||
              provider.toggleMute();
 | 
					              mediaNotifier.toggleMute();
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
          ),
 | 
					          ),
 | 
				
			||||||
          PopupMenuButton<String>(
 | 
					          PopupMenuButton<String>(
 | 
				
			||||||
            onSelected: (value) async {
 | 
					            onSelected: (value) async {
 | 
				
			||||||
              final item = provider.mediaItems.elementAt(_currentIndex);
 | 
					              final item = mediaState.mediaItems[_currentIndex];
 | 
				
			||||||
              switch (value) {
 | 
					              switch (value) {
 | 
				
			||||||
                case 'media':
 | 
					                case 'media':
 | 
				
			||||||
                  File file = await DefaultCacheManager().getSingleFile(
 | 
					                  File file = await DefaultCacheManager().getSingleFile(
 | 
				
			||||||
                    item.mediaUrl,
 | 
					                    item.mediaUrl,
 | 
				
			||||||
                  );
 | 
					                  );
 | 
				
			||||||
                  Uint8List bytes = await file.readAsBytes();
 | 
					                  Uint8List bytes = await file.readAsBytes();
 | 
				
			||||||
 | 
					 | 
				
			||||||
                  final params = ShareParams(
 | 
					                  final params = ShareParams(
 | 
				
			||||||
                    files: [XFile.fromData(bytes, mimeType: item.mime)],
 | 
					                    files: [XFile.fromData(bytes, mimeType: item.mime)],
 | 
				
			||||||
                  );
 | 
					                  );
 | 
				
			||||||
@@ -145,26 +141,26 @@ class _DetailViewState extends State<DetailView> {
 | 
				
			|||||||
              PopupMenuItem(
 | 
					              PopupMenuItem(
 | 
				
			||||||
                value: 'media',
 | 
					                value: 'media',
 | 
				
			||||||
                child: ListTile(
 | 
					                child: ListTile(
 | 
				
			||||||
                  leading: Icon(Icons.image),
 | 
					                  leading: const Icon(Icons.image),
 | 
				
			||||||
                  title: Text('Als Datei'),
 | 
					                  title: const Text('Als Datei'),
 | 
				
			||||||
                ),
 | 
					                ),
 | 
				
			||||||
              ),
 | 
					              ),
 | 
				
			||||||
              PopupMenuItem(
 | 
					              PopupMenuItem(
 | 
				
			||||||
                value: 'direct_link',
 | 
					                value: 'direct_link',
 | 
				
			||||||
                child: ListTile(
 | 
					                child: ListTile(
 | 
				
			||||||
                  leading: Icon(Icons.link),
 | 
					                  leading: const Icon(Icons.link),
 | 
				
			||||||
                  title: Text('Link zum Bild'),
 | 
					                  title: const Text('Link zum Bild'),
 | 
				
			||||||
                ),
 | 
					                ),
 | 
				
			||||||
              ),
 | 
					              ),
 | 
				
			||||||
              PopupMenuItem(
 | 
					              PopupMenuItem(
 | 
				
			||||||
                value: 'post_link',
 | 
					                value: 'post_link',
 | 
				
			||||||
                child: ListTile(
 | 
					                child: ListTile(
 | 
				
			||||||
                  leading: Icon(Icons.article),
 | 
					                  leading: const Icon(Icons.article),
 | 
				
			||||||
                  title: Text('Link zum Post'),
 | 
					                  title: const Text('Link zum Post'),
 | 
				
			||||||
                ),
 | 
					                ),
 | 
				
			||||||
              ),
 | 
					              ),
 | 
				
			||||||
            ],
 | 
					            ],
 | 
				
			||||||
            icon: Icon(Icons.share),
 | 
					            icon: const Icon(Icons.share),
 | 
				
			||||||
          ),
 | 
					          ),
 | 
				
			||||||
        ],
 | 
					        ],
 | 
				
			||||||
      ),
 | 
					      ),
 | 
				
			||||||
@@ -172,9 +168,8 @@ class _DetailViewState extends State<DetailView> {
 | 
				
			|||||||
        children: [
 | 
					        children: [
 | 
				
			||||||
          PageTransformer(
 | 
					          PageTransformer(
 | 
				
			||||||
            controller: _pageController,
 | 
					            controller: _pageController,
 | 
				
			||||||
            pages: provider.mediaItems.map((item) {
 | 
					            pages: mediaState.mediaItems.map((item) {
 | 
				
			||||||
              int itemIndex = provider.mediaItems.indexOf(item);
 | 
					              int itemIndex = mediaState.mediaItems.indexOf(item);
 | 
				
			||||||
 | 
					 | 
				
			||||||
              return SafeArea(
 | 
					              return SafeArea(
 | 
				
			||||||
                child: SmartRefreshIndicator(
 | 
					                child: SmartRefreshIndicator(
 | 
				
			||||||
                  onRefresh: _loadMoreMedia,
 | 
					                  onRefresh: _loadMoreMedia,
 | 
				
			||||||
@@ -185,14 +180,14 @@ class _DetailViewState extends State<DetailView> {
 | 
				
			|||||||
          ),
 | 
					          ),
 | 
				
			||||||
        ],
 | 
					        ],
 | 
				
			||||||
      ),
 | 
					      ),
 | 
				
			||||||
      persistentFooterButtons: provider.tag != null
 | 
					      persistentFooterButtons: mediaState.tag != null
 | 
				
			||||||
          ? [
 | 
					          ? [
 | 
				
			||||||
              InputChip(
 | 
					              InputChip(
 | 
				
			||||||
                label: Text(provider.tag!),
 | 
					                label: Text(mediaState.tag!),
 | 
				
			||||||
                backgroundColor: const Color(0xFF090909),
 | 
					                //backgroundColor: const Color(0xFF090909),
 | 
				
			||||||
                labelStyle: const TextStyle(color: Colors.white),
 | 
					                //labelStyle: const TextStyle(color: Colors.white),
 | 
				
			||||||
                onDeleted: () {
 | 
					                onDeleted: () {
 | 
				
			||||||
                  provider.setTag(null);
 | 
					                  mediaNotifier.setTag(null);
 | 
				
			||||||
                  Navigator.pop(context);
 | 
					                  Navigator.pop(context);
 | 
				
			||||||
                },
 | 
					                },
 | 
				
			||||||
              ),
 | 
					              ),
 | 
				
			||||||
@@ -202,7 +197,7 @@ class _DetailViewState extends State<DetailView> {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  Widget _buildMediaItem(MediaItem item, bool isActive) {
 | 
					  Widget _buildMediaItem(MediaItem item, bool isActive) {
 | 
				
			||||||
    final provider = Provider.of<MediaProvider>(context);
 | 
					    final mediaNotifier = ref.read(mediaProvider.notifier);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return SingleChildScrollView(
 | 
					    return SingleChildScrollView(
 | 
				
			||||||
      child: Column(
 | 
					      child: Column(
 | 
				
			||||||
@@ -211,16 +206,11 @@ class _DetailViewState extends State<DetailView> {
 | 
				
			|||||||
            CachedNetworkImage(
 | 
					            CachedNetworkImage(
 | 
				
			||||||
              imageUrl: item.mediaUrl,
 | 
					              imageUrl: item.mediaUrl,
 | 
				
			||||||
              fit: BoxFit.contain,
 | 
					              fit: BoxFit.contain,
 | 
				
			||||||
              placeholder: (context, url) => CircularProgressIndicator(),
 | 
					              placeholder: (context, url) => const CircularProgressIndicator(),
 | 
				
			||||||
              errorWidget: (context, url, error) => Icon(Icons.error),
 | 
					              errorWidget: (context, url, error) => const Icon(Icons.error),
 | 
				
			||||||
            )
 | 
					            )
 | 
				
			||||||
          else
 | 
					          else
 | 
				
			||||||
            VideoWidget(details: item, isActive: isActive),
 | 
					            VideoWidget(details: item, isActive: isActive),
 | 
				
			||||||
          /*const SizedBox(height: 20),
 | 
					 | 
				
			||||||
          Text(
 | 
					 | 
				
			||||||
            'f0ck #${item.id.toString()}',
 | 
					 | 
				
			||||||
            style: const TextStyle(color: Colors.white, fontSize: 18),
 | 
					 | 
				
			||||||
          ),*/
 | 
					 | 
				
			||||||
          const SizedBox(height: 10, width: double.infinity),
 | 
					          const SizedBox(height: 10, width: double.infinity),
 | 
				
			||||||
          Wrap(
 | 
					          Wrap(
 | 
				
			||||||
            alignment: WrapAlignment.center,
 | 
					            alignment: WrapAlignment.center,
 | 
				
			||||||
@@ -230,7 +220,7 @@ class _DetailViewState extends State<DetailView> {
 | 
				
			|||||||
                onPressed: () {
 | 
					                onPressed: () {
 | 
				
			||||||
                  if (tag.tag == 'sfw' || tag.tag == 'nsfw') return;
 | 
					                  if (tag.tag == 'sfw' || tag.tag == 'nsfw') return;
 | 
				
			||||||
                  setState(() {
 | 
					                  setState(() {
 | 
				
			||||||
                    provider.setTag(tag.tag);
 | 
					                    mediaNotifier.setTag(tag.tag);
 | 
				
			||||||
                    Navigator.pop(context, true);
 | 
					                    Navigator.pop(context, true);
 | 
				
			||||||
                  });
 | 
					                  });
 | 
				
			||||||
                },
 | 
					                },
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,37 +1,29 @@
 | 
				
			|||||||
import 'package:flutter/material.dart';
 | 
					import 'package:flutter/material.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import 'package:cached_network_image/cached_network_image.dart';
 | 
					import 'package:cached_network_image/cached_network_image.dart';
 | 
				
			||||||
import 'package:provider/provider.dart';
 | 
					import 'package:flutter_riverpod/flutter_riverpod.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import 'package:f0ckapp/screens/DetailView.dart';
 | 
					import 'package:f0ckapp/screens/DetailView.dart';
 | 
				
			||||||
import 'package:f0ckapp/providers/MediaProvider.dart';
 | 
					import 'package:f0ckapp/providers/MediaProvider.dart';
 | 
				
			||||||
import 'package:f0ckapp/utils/AppVersion.dart';
 | 
					import 'package:f0ckapp/utils/AppVersion.dart';
 | 
				
			||||||
 | 
					import 'package:f0ckapp/providers/ThemeProvider.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class MediaGrid extends StatefulWidget {
 | 
					const List<String> mediaTypes = ["alles", "image", "video", "audio"];
 | 
				
			||||||
 | 
					const List<String> mediaModes = ["sfw", "nsfw", "untagged", "all"];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class MediaGrid extends ConsumerStatefulWidget {
 | 
				
			||||||
  const MediaGrid({super.key});
 | 
					  const MediaGrid({super.key});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @override
 | 
					  @override
 | 
				
			||||||
  State createState() => _MediaGridState();
 | 
					  ConsumerState<MediaGrid> createState() => _MediaGridState();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class _MediaGridState extends State<MediaGrid> {
 | 
					class _MediaGridState extends ConsumerState<MediaGrid> {
 | 
				
			||||||
  final ScrollController _scrollController = ScrollController();
 | 
					  final ScrollController _scrollController = ScrollController();
 | 
				
			||||||
 | 
					  final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @override
 | 
					  final TextEditingController _usernameController = TextEditingController();
 | 
				
			||||||
  void initState() {
 | 
					  final TextEditingController _passwordController = TextEditingController();
 | 
				
			||||||
    super.initState();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    final provider = Provider.of<MediaProvider>(context, listen: false);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    Future.microtask(() {
 | 
					 | 
				
			||||||
      provider.loadMedia();
 | 
					 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    _scrollController.addListener(() {
 | 
					 | 
				
			||||||
      if (_scrollController.position.pixels >=
 | 
					 | 
				
			||||||
          _scrollController.position.maxScrollExtent - 200) {
 | 
					 | 
				
			||||||
        provider.loadMedia(notify: false);
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  int _calculateCrossAxisCount(BuildContext context, int defaultCount) {
 | 
					  int _calculateCrossAxisCount(BuildContext context, int defaultCount) {
 | 
				
			||||||
    return defaultCount == 0
 | 
					    return defaultCount == 0
 | 
				
			||||||
@@ -40,34 +32,59 @@ class _MediaGridState extends State<MediaGrid> {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @override
 | 
					  @override
 | 
				
			||||||
  Widget build(BuildContext context) {
 | 
					  void initState() {
 | 
				
			||||||
    final provider = Provider.of<MediaProvider>(context);
 | 
					    super.initState();
 | 
				
			||||||
    final GlobalKey<ScaffoldState> scaffoldKey = GlobalKey<ScaffoldState>();
 | 
					    Future.microtask(() {
 | 
				
			||||||
 | 
					      ref.read(mediaProvider.notifier).loadMedia();
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					    _scrollController.addListener(() {
 | 
				
			||||||
 | 
					      if (_scrollController.position.pixels >=
 | 
				
			||||||
 | 
					          _scrollController.position.maxScrollExtent - 200) {
 | 
				
			||||||
 | 
					        ref.read(mediaProvider.notifier).loadMedia();
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    final TextEditingController _usernameController = TextEditingController();
 | 
					  @override
 | 
				
			||||||
    final TextEditingController _passwordController = TextEditingController();
 | 
					  void dispose() {
 | 
				
			||||||
 | 
					    _scrollController.dispose();
 | 
				
			||||||
 | 
					    _usernameController.dispose();
 | 
				
			||||||
 | 
					    _passwordController.dispose();
 | 
				
			||||||
 | 
					    super.dispose();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  Widget build(BuildContext context) {
 | 
				
			||||||
 | 
					    final mediaState = ref.watch(mediaProvider);
 | 
				
			||||||
 | 
					    final mediaNotifier = ref.read(mediaProvider.notifier);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return Scaffold(
 | 
					    return Scaffold(
 | 
				
			||||||
      key: scaffoldKey,
 | 
					      key: _scaffoldKey,
 | 
				
			||||||
      appBar: AppBar(
 | 
					      appBar: AppBar(
 | 
				
			||||||
        title: Image.asset(
 | 
					        title: Row(
 | 
				
			||||||
          'assets/images/f0ck_small.webp',
 | 
					          spacing: 15,
 | 
				
			||||||
          fit: BoxFit.fitHeight,
 | 
					          children: [
 | 
				
			||||||
 | 
					            Image.asset('assets/images/f0ck_small.webp', fit: BoxFit.fitHeight),
 | 
				
			||||||
 | 
					            Text(
 | 
				
			||||||
 | 
					              'fApp',
 | 
				
			||||||
 | 
					              style: TextStyle(fontSize: 24),
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					          ],
 | 
				
			||||||
        ),
 | 
					        ),
 | 
				
			||||||
        actions: [
 | 
					        actions: [
 | 
				
			||||||
          IconButton(
 | 
					          IconButton(
 | 
				
			||||||
            icon: Icon(
 | 
					            icon: Icon(
 | 
				
			||||||
              provider.random ? Icons.shuffle_on_outlined : Icons.shuffle,
 | 
					              mediaState.random ? Icons.shuffle_on_outlined : Icons.shuffle,
 | 
				
			||||||
            ),
 | 
					            ),
 | 
				
			||||||
            onPressed: () {
 | 
					            onPressed: () {
 | 
				
			||||||
              provider.toggleRandom();
 | 
					              mediaNotifier.toggleRandom();
 | 
				
			||||||
              _scrollController.jumpTo(0);
 | 
					              _scrollController.jumpTo(0);
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
          ),
 | 
					          ),
 | 
				
			||||||
          IconButton(
 | 
					          IconButton(
 | 
				
			||||||
            icon: const Icon(Icons.menu),
 | 
					            icon: const Icon(Icons.menu),
 | 
				
			||||||
            onPressed: () {
 | 
					            onPressed: () {
 | 
				
			||||||
              scaffoldKey.currentState?.openEndDrawer();
 | 
					              _scaffoldKey.currentState?.openEndDrawer();
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
          ),
 | 
					          ),
 | 
				
			||||||
        ],
 | 
					        ],
 | 
				
			||||||
@@ -77,32 +94,11 @@ class _MediaGridState extends State<MediaGrid> {
 | 
				
			|||||||
        child: Row(
 | 
					        child: Row(
 | 
				
			||||||
          mainAxisAlignment: MainAxisAlignment.spaceAround,
 | 
					          mainAxisAlignment: MainAxisAlignment.spaceAround,
 | 
				
			||||||
          children: [
 | 
					          children: [
 | 
				
			||||||
            Text('type: '),
 | 
					            const Text('type: '),
 | 
				
			||||||
            DropdownButton<String>(
 | 
					            DropdownButton<String>(
 | 
				
			||||||
              // type
 | 
					              value: mediaTypes[mediaState.typeIndex],
 | 
				
			||||||
              value: provider.type,
 | 
					 | 
				
			||||||
              isDense: true,
 | 
					              isDense: true,
 | 
				
			||||||
              //icon: SizedBox.shrink(),
 | 
					              items: mediaTypes.map((String value) {
 | 
				
			||||||
              items: provider.types.map((String value) {
 | 
					 | 
				
			||||||
                return DropdownMenuItem<String>(
 | 
					 | 
				
			||||||
                  value: value,
 | 
					 | 
				
			||||||
                  child: Text(value, style: TextStyle(color: Colors.white)),
 | 
					 | 
				
			||||||
                );
 | 
					 | 
				
			||||||
              }).toList(),
 | 
					 | 
				
			||||||
              onChanged: (String? newValue) {
 | 
					 | 
				
			||||||
                if (newValue != null) {
 | 
					 | 
				
			||||||
                  provider.setType(newValue);
 | 
					 | 
				
			||||||
                  _scrollController.jumpTo(0);
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
              },
 | 
					 | 
				
			||||||
            ),
 | 
					 | 
				
			||||||
            Text('mode: '),
 | 
					 | 
				
			||||||
            DropdownButton<String>(
 | 
					 | 
				
			||||||
              // mode
 | 
					 | 
				
			||||||
              value: provider.modes[provider.mode],
 | 
					 | 
				
			||||||
              isDense: true,
 | 
					 | 
				
			||||||
              //icon: SizedBox.shrink(),
 | 
					 | 
				
			||||||
              items: provider.modes.map((String value) {
 | 
					 | 
				
			||||||
                return DropdownMenuItem<String>(
 | 
					                return DropdownMenuItem<String>(
 | 
				
			||||||
                  value: value,
 | 
					                  value: value,
 | 
				
			||||||
                  child: Text(value),
 | 
					                  child: Text(value),
 | 
				
			||||||
@@ -110,7 +106,24 @@ class _MediaGridState extends State<MediaGrid> {
 | 
				
			|||||||
              }).toList(),
 | 
					              }).toList(),
 | 
				
			||||||
              onChanged: (String? newValue) {
 | 
					              onChanged: (String? newValue) {
 | 
				
			||||||
                if (newValue != null) {
 | 
					                if (newValue != null) {
 | 
				
			||||||
                  provider.setMode(provider.modes.indexOf(newValue));
 | 
					                  mediaNotifier.setType(newValue);
 | 
				
			||||||
 | 
					                  _scrollController.jumpTo(0);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					              },
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					            const Text('mode: '),
 | 
				
			||||||
 | 
					            DropdownButton<String>(
 | 
				
			||||||
 | 
					              value: mediaModes[mediaState.modeIndex],
 | 
				
			||||||
 | 
					              isDense: true,
 | 
				
			||||||
 | 
					              items: mediaModes.map((String value) {
 | 
				
			||||||
 | 
					                return DropdownMenuItem<String>(
 | 
				
			||||||
 | 
					                  value: value,
 | 
				
			||||||
 | 
					                  child: Text(value),
 | 
				
			||||||
 | 
					                );
 | 
				
			||||||
 | 
					              }).toList(),
 | 
				
			||||||
 | 
					              onChanged: (String? newValue) {
 | 
				
			||||||
 | 
					                if (newValue != null) {
 | 
				
			||||||
 | 
					                  mediaNotifier.setMode(mediaModes.indexOf(newValue));
 | 
				
			||||||
                  _scrollController.jumpTo(0);
 | 
					                  _scrollController.jumpTo(0);
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
              },
 | 
					              },
 | 
				
			||||||
@@ -123,7 +136,7 @@ class _MediaGridState extends State<MediaGrid> {
 | 
				
			|||||||
          padding: EdgeInsets.zero,
 | 
					          padding: EdgeInsets.zero,
 | 
				
			||||||
          children: [
 | 
					          children: [
 | 
				
			||||||
            DrawerHeader(
 | 
					            DrawerHeader(
 | 
				
			||||||
              decoration: BoxDecoration(
 | 
					              decoration: const BoxDecoration(
 | 
				
			||||||
                image: DecorationImage(
 | 
					                image: DecorationImage(
 | 
				
			||||||
                  image: AssetImage('assets/images/menu.webp'),
 | 
					                  image: AssetImage('assets/images/menu.webp'),
 | 
				
			||||||
                  fit: BoxFit.cover,
 | 
					                  fit: BoxFit.cover,
 | 
				
			||||||
@@ -133,71 +146,100 @@ class _MediaGridState extends State<MediaGrid> {
 | 
				
			|||||||
              child: null,
 | 
					              child: null,
 | 
				
			||||||
            ),
 | 
					            ),
 | 
				
			||||||
            ExpansionTile(
 | 
					            ExpansionTile(
 | 
				
			||||||
              title: Text('Login'),
 | 
					              title: const Text('Login'),
 | 
				
			||||||
              children: [
 | 
					              children: [
 | 
				
			||||||
                Padding(
 | 
					                Padding(
 | 
				
			||||||
                  padding: EdgeInsets.all(16.0),
 | 
					                  padding: const EdgeInsets.all(16.0),
 | 
				
			||||||
                  child: Column(
 | 
					                  child: Column(
 | 
				
			||||||
                    children: [
 | 
					                    children: [
 | 
				
			||||||
                      TextField(
 | 
					                      TextField(
 | 
				
			||||||
                        readOnly: true,
 | 
					                        readOnly: true,
 | 
				
			||||||
                        controller: _usernameController,
 | 
					                        controller: _usernameController,
 | 
				
			||||||
                        decoration: InputDecoration(labelText: 'Benutzername'),
 | 
					                        decoration: const InputDecoration(
 | 
				
			||||||
 | 
					                          labelText: 'Benutzername',
 | 
				
			||||||
 | 
					                        ),
 | 
				
			||||||
                      ),
 | 
					                      ),
 | 
				
			||||||
                      SizedBox(height: 10),
 | 
					                      const SizedBox(height: 10),
 | 
				
			||||||
                      TextField(
 | 
					                      TextField(
 | 
				
			||||||
                        readOnly: true,
 | 
					                        readOnly: true,
 | 
				
			||||||
                        controller: _passwordController,
 | 
					                        controller: _passwordController,
 | 
				
			||||||
                        obscureText: true,
 | 
					                        obscureText: true,
 | 
				
			||||||
                        decoration: InputDecoration(labelText: 'Passwort'),
 | 
					                        decoration: const InputDecoration(
 | 
				
			||||||
 | 
					                          labelText: 'Passwort',
 | 
				
			||||||
 | 
					                        ),
 | 
				
			||||||
                      ),
 | 
					                      ),
 | 
				
			||||||
                      SizedBox(height: 20),
 | 
					                      const SizedBox(height: 20),
 | 
				
			||||||
                      ElevatedButton(
 | 
					                      ElevatedButton(
 | 
				
			||||||
                        onPressed: () async {
 | 
					                        onPressed: () async {
 | 
				
			||||||
                          ScaffoldMessenger.of(context).showSnackBar(
 | 
					                          ScaffoldMessenger.of(context).showSnackBar(
 | 
				
			||||||
                            SnackBar(
 | 
					                            const SnackBar(
 | 
				
			||||||
                              content: Text("noch nicht implementiert lol"),
 | 
					                              content: Text("noch nicht implementiert lol"),
 | 
				
			||||||
                            ),
 | 
					                            ),
 | 
				
			||||||
                          );
 | 
					                            /*final success = await login(
 | 
				
			||||||
                          /*final success = await login(
 | 
					                              _usernameController.text,
 | 
				
			||||||
                            _usernameController.text,
 | 
					                              _passwordController.text,
 | 
				
			||||||
                            _passwordController.text,
 | 
					 | 
				
			||||||
                          );
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                          if (success) {
 | 
					 | 
				
			||||||
                            Navigator.pop(context);
 | 
					 | 
				
			||||||
                          } else {
 | 
					 | 
				
			||||||
                            ScaffoldMessenger.of(context).showSnackBar(
 | 
					 | 
				
			||||||
                              SnackBar(content: Text("Login fehlgeschlagen!")),
 | 
					 | 
				
			||||||
                            );
 | 
					                            );
 | 
				
			||||||
                          }*/
 | 
					
 | 
				
			||||||
 | 
					                            if (success) {
 | 
				
			||||||
 | 
					                              Navigator.pop(context);
 | 
				
			||||||
 | 
					                            } else {
 | 
				
			||||||
 | 
					                              ScaffoldMessenger.of(context).showSnackBar(
 | 
				
			||||||
 | 
					                                SnackBar(content: Text("Login fehlgeschlagen!")),
 | 
				
			||||||
 | 
					                              );
 | 
				
			||||||
 | 
					                            }*/
 | 
				
			||||||
 | 
					                          );
 | 
				
			||||||
                        },
 | 
					                        },
 | 
				
			||||||
                        child: Text('Login'),
 | 
					                        child: const Text('Login'),
 | 
				
			||||||
                      ),
 | 
					                      ),
 | 
				
			||||||
                    ],
 | 
					                    ],
 | 
				
			||||||
                  ),
 | 
					                  ),
 | 
				
			||||||
                ),
 | 
					                ),
 | 
				
			||||||
              ],
 | 
					              ],
 | 
				
			||||||
            ),
 | 
					            ),
 | 
				
			||||||
 | 
					            ExpansionTile(
 | 
				
			||||||
 | 
					              title: const Text('Theme'),
 | 
				
			||||||
 | 
					              children: [
 | 
				
			||||||
 | 
					                Padding(
 | 
				
			||||||
 | 
					                  padding: const EdgeInsets.symmetric(horizontal: 16.0),
 | 
				
			||||||
 | 
					                  child: Column(
 | 
				
			||||||
 | 
					                    children: themes.map((themeData) {
 | 
				
			||||||
 | 
					                      final currentTheme = ref.watch(themeNotifierProvider);
 | 
				
			||||||
 | 
					                      final isSelected = currentTheme == themeData.theme;
 | 
				
			||||||
 | 
					                      return ListTile(
 | 
				
			||||||
 | 
					                        title: Text(themeData.name),
 | 
				
			||||||
 | 
					                        selected: isSelected,
 | 
				
			||||||
 | 
					                        selectedTileColor: Colors.blue.withValues(alpha: 0.2),
 | 
				
			||||||
 | 
					                        onTap: () async {
 | 
				
			||||||
 | 
					                          await ref
 | 
				
			||||||
 | 
					                              .read(themeNotifierProvider.notifier)
 | 
				
			||||||
 | 
					                              .updateTheme(themeData.name);
 | 
				
			||||||
 | 
					                        },
 | 
				
			||||||
 | 
					                      );
 | 
				
			||||||
 | 
					                    }).toList(),
 | 
				
			||||||
 | 
					                  ),
 | 
				
			||||||
 | 
					                ),
 | 
				
			||||||
 | 
					              ],
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            ListTile(
 | 
					            ListTile(
 | 
				
			||||||
              title: Text('v${AppVersion.version}'),
 | 
					              title: Text('v${AppVersion.version}'),
 | 
				
			||||||
              onTap: () {
 | 
					              onTap: () {
 | 
				
			||||||
                ScaffoldMessenger.of(context).showSnackBar(
 | 
					                ScaffoldMessenger.of(context).showSnackBar(
 | 
				
			||||||
                  SnackBar(content: Text('jooong lass das, hier ist nichts')),
 | 
					                  const SnackBar(
 | 
				
			||||||
 | 
					                    content: Text('jooong lass das, hier ist nichts'),
 | 
				
			||||||
 | 
					                  ),
 | 
				
			||||||
                );
 | 
					                );
 | 
				
			||||||
              },
 | 
					              },
 | 
				
			||||||
            ),
 | 
					            ),
 | 
				
			||||||
          ],
 | 
					          ],
 | 
				
			||||||
        ),
 | 
					        ),
 | 
				
			||||||
      ),
 | 
					      ),
 | 
				
			||||||
      persistentFooterButtons: provider.tag != null
 | 
					      persistentFooterButtons: mediaState.tag != null
 | 
				
			||||||
          ? [
 | 
					          ? [
 | 
				
			||||||
              InputChip(
 | 
					              InputChip(
 | 
				
			||||||
                label: Text(provider.tag!),
 | 
					                label: Text(mediaState.tag!),
 | 
				
			||||||
                backgroundColor: const Color(0xFF090909),
 | 
					 | 
				
			||||||
                labelStyle: const TextStyle(color: Colors.white),
 | 
					 | 
				
			||||||
                onDeleted: () {
 | 
					                onDeleted: () {
 | 
				
			||||||
                  provider.setTag(null);
 | 
					                  mediaNotifier.setTag(null);
 | 
				
			||||||
                  _scrollController.jumpTo(0);
 | 
					                  _scrollController.jumpTo(0);
 | 
				
			||||||
                },
 | 
					                },
 | 
				
			||||||
              ),
 | 
					              ),
 | 
				
			||||||
@@ -205,68 +247,64 @@ class _MediaGridState extends State<MediaGrid> {
 | 
				
			|||||||
          : null,
 | 
					          : null,
 | 
				
			||||||
      body: RefreshIndicator(
 | 
					      body: RefreshIndicator(
 | 
				
			||||||
        onRefresh: () async {
 | 
					        onRefresh: () async {
 | 
				
			||||||
          await provider.resetMedia();
 | 
					          mediaNotifier.resetMedia();
 | 
				
			||||||
          _scrollController.jumpTo(0);
 | 
					          _scrollController.jumpTo(0);
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        child: Consumer<MediaProvider>(
 | 
					        child: GridView.builder(
 | 
				
			||||||
          builder: (context, mediaProvider, child) {
 | 
					          key: const PageStorageKey('mediaGrid'),
 | 
				
			||||||
            return GridView.builder(
 | 
					          controller: _scrollController,
 | 
				
			||||||
              key: PageStorageKey('mediaGrid'),
 | 
					          gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
 | 
				
			||||||
              controller: _scrollController,
 | 
					            crossAxisCount: _calculateCrossAxisCount(
 | 
				
			||||||
              gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
 | 
					              context,
 | 
				
			||||||
                crossAxisCount: _calculateCrossAxisCount(
 | 
					              mediaState.crossAxisCount,
 | 
				
			||||||
                  context,
 | 
					            ),
 | 
				
			||||||
                  provider.crossAxisCount,
 | 
					            crossAxisSpacing: 5.0,
 | 
				
			||||||
                ),
 | 
					            mainAxisSpacing: 5.0,
 | 
				
			||||||
                crossAxisSpacing: 5.0,
 | 
					          ),
 | 
				
			||||||
                mainAxisSpacing: 5.0,
 | 
					          itemCount:
 | 
				
			||||||
              ),
 | 
					              mediaState.mediaItems.length + (mediaState.isLoading ? 1 : 0),
 | 
				
			||||||
              itemCount:
 | 
					          itemBuilder: (context, index) {
 | 
				
			||||||
                  provider.mediaItems.length + (provider.isLoading ? 1 : 0),
 | 
					            if (index >= mediaState.mediaItems.length) {
 | 
				
			||||||
              itemBuilder: (context, index) {
 | 
					              return const Center(child: CircularProgressIndicator());
 | 
				
			||||||
                if (index >= provider.mediaItems.length) {
 | 
					            }
 | 
				
			||||||
                  return const Center(child: CircularProgressIndicator());
 | 
					            final item = mediaState.mediaItems[index];
 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                final item = provider.mediaItems[index];
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
                return InkWell(
 | 
					            return InkWell(
 | 
				
			||||||
                  onTap: () async {
 | 
					              onTap: () async {
 | 
				
			||||||
                    bool? ret = await Navigator.push(
 | 
					                bool? ret = await Navigator.push(
 | 
				
			||||||
                      context,
 | 
					                  context,
 | 
				
			||||||
                      MaterialPageRoute(
 | 
					                  MaterialPageRoute(
 | 
				
			||||||
                        builder: (context) =>
 | 
					                    builder: (context) => DetailView(initialItemId: item.id),
 | 
				
			||||||
                            DetailView(initialItemId: item.id),
 | 
					 | 
				
			||||||
                      ),
 | 
					 | 
				
			||||||
                    );
 | 
					 | 
				
			||||||
                    if (ret != null && ret) {
 | 
					 | 
				
			||||||
                      _scrollController.jumpTo(0);
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                  },
 | 
					 | 
				
			||||||
                  child: Stack(
 | 
					 | 
				
			||||||
                    fit: StackFit.expand,
 | 
					 | 
				
			||||||
                    children: <Widget>[
 | 
					 | 
				
			||||||
                      CachedNetworkImage(
 | 
					 | 
				
			||||||
                        imageUrl: item.thumbnailUrl,
 | 
					 | 
				
			||||||
                        fit: BoxFit.cover,
 | 
					 | 
				
			||||||
                        placeholder: (context, url) => SizedBox.shrink(),
 | 
					 | 
				
			||||||
                        errorWidget: (context, url, error) => Icon(Icons.error),
 | 
					 | 
				
			||||||
                      ),
 | 
					 | 
				
			||||||
                      Align(
 | 
					 | 
				
			||||||
                        alignment: FractionalOffset.bottomRight,
 | 
					 | 
				
			||||||
                        child: Icon(
 | 
					 | 
				
			||||||
                          Icons.square,
 | 
					 | 
				
			||||||
                          color: switch (item.mode) {
 | 
					 | 
				
			||||||
                            1 => Colors.green,
 | 
					 | 
				
			||||||
                            2 => Colors.red,
 | 
					 | 
				
			||||||
                            _ => Colors.yellow,
 | 
					 | 
				
			||||||
                          },
 | 
					 | 
				
			||||||
                          size: 15.0,
 | 
					 | 
				
			||||||
                        ),
 | 
					 | 
				
			||||||
                      ),
 | 
					 | 
				
			||||||
                    ],
 | 
					 | 
				
			||||||
                  ),
 | 
					                  ),
 | 
				
			||||||
                );
 | 
					                );
 | 
				
			||||||
 | 
					                if (ret != null && ret) {
 | 
				
			||||||
 | 
					                  _scrollController.jumpTo(0);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
              },
 | 
					              },
 | 
				
			||||||
 | 
					              child: Stack(
 | 
				
			||||||
 | 
					                fit: StackFit.expand,
 | 
				
			||||||
 | 
					                children: <Widget>[
 | 
				
			||||||
 | 
					                  CachedNetworkImage(
 | 
				
			||||||
 | 
					                    imageUrl: item.thumbnailUrl,
 | 
				
			||||||
 | 
					                    fit: BoxFit.cover,
 | 
				
			||||||
 | 
					                    placeholder: (context, url) => const SizedBox.shrink(),
 | 
				
			||||||
 | 
					                    errorWidget: (context, url, error) =>
 | 
				
			||||||
 | 
					                        const Icon(Icons.error),
 | 
				
			||||||
 | 
					                  ),
 | 
				
			||||||
 | 
					                  Align(
 | 
				
			||||||
 | 
					                    alignment: Alignment.bottomRight,
 | 
				
			||||||
 | 
					                    child: Icon(
 | 
				
			||||||
 | 
					                      Icons.square,
 | 
				
			||||||
 | 
					                      color: switch (item.mode) {
 | 
				
			||||||
 | 
					                        1 => Colors.green,
 | 
				
			||||||
 | 
					                        2 => Colors.red,
 | 
				
			||||||
 | 
					                        _ => Colors.yellow,
 | 
				
			||||||
 | 
					                      },
 | 
				
			||||||
 | 
					                      size: 15.0,
 | 
				
			||||||
 | 
					                    ),
 | 
				
			||||||
 | 
					                  ),
 | 
				
			||||||
 | 
					                ],
 | 
				
			||||||
 | 
					              ),
 | 
				
			||||||
            );
 | 
					            );
 | 
				
			||||||
          },
 | 
					          },
 | 
				
			||||||
        ),
 | 
					        ),
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,4 +1,5 @@
 | 
				
			|||||||
import 'dart:convert';
 | 
					import 'dart:convert';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import 'package:http/http.dart' as http;
 | 
					import 'package:http/http.dart' as http;
 | 
				
			||||||
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
 | 
					import 'package:flutter_secure_storage/flutter_secure_storage.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,4 +1,5 @@
 | 
				
			|||||||
import 'package:flutter/material.dart';
 | 
					import 'package:flutter/material.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import 'package:cached_video_player_plus/cached_video_player_plus.dart';
 | 
					import 'package:cached_video_player_plus/cached_video_player_plus.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class VideoControlsOverlay extends StatelessWidget {
 | 
					class VideoControlsOverlay extends StatelessWidget {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,21 +1,26 @@
 | 
				
			|||||||
import 'package:flutter/material.dart';
 | 
					 | 
				
			||||||
import 'package:cached_video_player_plus/cached_video_player_plus.dart';
 | 
					 | 
				
			||||||
import 'package:cached_network_image/cached_network_image.dart';
 | 
					 | 
				
			||||||
import 'package:f0ckapp/models/MediaItem.dart';
 | 
					 | 
				
			||||||
import 'package:f0ckapp/widgets/VideoOverlay.dart';
 | 
					 | 
				
			||||||
import 'dart:async';
 | 
					import 'dart:async';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class VideoWidget extends StatefulWidget {
 | 
					import 'package:flutter/material.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import 'package:cached_video_player_plus/cached_video_player_plus.dart';
 | 
				
			||||||
 | 
					import 'package:cached_network_image/cached_network_image.dart';
 | 
				
			||||||
 | 
					import 'package:flutter_riverpod/flutter_riverpod.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import 'package:f0ckapp/models/MediaItem.dart';
 | 
				
			||||||
 | 
					import 'package:f0ckapp/widgets/VideoOverlay.dart';
 | 
				
			||||||
 | 
					import 'package:f0ckapp/providers/MediaProvider.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class VideoWidget extends ConsumerStatefulWidget {
 | 
				
			||||||
  final MediaItem details;
 | 
					  final MediaItem details;
 | 
				
			||||||
  final bool isActive;
 | 
					  final bool isActive;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const VideoWidget({super.key, required this.details, required this.isActive});
 | 
					  const VideoWidget({super.key, required this.details, required this.isActive});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @override
 | 
					  @override
 | 
				
			||||||
  State createState() => _VideoWidgetState();
 | 
					  ConsumerState<VideoWidget> createState() => _VideoWidgetState();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class _VideoWidgetState extends State<VideoWidget> {
 | 
					class _VideoWidgetState extends ConsumerState<VideoWidget> {
 | 
				
			||||||
  late CachedVideoPlayerPlusController _controller;
 | 
					  late CachedVideoPlayerPlusController _controller;
 | 
				
			||||||
  bool _showControls = false;
 | 
					  bool _showControls = false;
 | 
				
			||||||
  Timer? _hideControlsTimer;
 | 
					  Timer? _hideControlsTimer;
 | 
				
			||||||
@@ -34,10 +39,26 @@ class _VideoWidgetState extends State<VideoWidget> {
 | 
				
			|||||||
    setState(() {});
 | 
					    setState(() {});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    _controller.addListener(() => setState(() {}));
 | 
					    _controller.addListener(() => setState(() {}));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (widget.isActive) {
 | 
					    if (widget.isActive) {
 | 
				
			||||||
      _controller.play();
 | 
					      _controller.play();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    _controller.setLooping(true);
 | 
					    _controller.setLooping(true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    final muted = ref.read(mediaProvider).muted;
 | 
				
			||||||
 | 
					    _controller.setVolume(muted ? 0.0 : 1.0);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  void didUpdateWidget(covariant VideoWidget oldWidget) {
 | 
				
			||||||
 | 
					    super.didUpdateWidget(oldWidget);
 | 
				
			||||||
 | 
					    if (widget.isActive != oldWidget.isActive) {
 | 
				
			||||||
 | 
					      if (widget.isActive) {
 | 
				
			||||||
 | 
					        _controller.play();
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        _controller.pause();
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @override
 | 
					  @override
 | 
				
			||||||
@@ -47,24 +68,13 @@ class _VideoWidgetState extends State<VideoWidget> {
 | 
				
			|||||||
    super.dispose();
 | 
					    super.dispose();
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @override
 | 
					 | 
				
			||||||
  void didUpdateWidget(VideoWidget oldWidget) {
 | 
					 | 
				
			||||||
    super.didUpdateWidget(oldWidget);
 | 
					 | 
				
			||||||
    if (widget.isActive) {
 | 
					 | 
				
			||||||
      _controller.play();
 | 
					 | 
				
			||||||
    } else {
 | 
					 | 
				
			||||||
      _controller.pause();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  void _onTap({bool ctrlButton = false}) {
 | 
					  void _onTap({bool ctrlButton = false}) {
 | 
				
			||||||
    if (!ctrlButton) {
 | 
					    if (!ctrlButton) {
 | 
				
			||||||
      setState(() => _showControls = !_showControls);
 | 
					      setState(() => _showControls = !_showControls);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (_showControls) {
 | 
					    if (_showControls) {
 | 
				
			||||||
      _hideControlsTimer?.cancel();
 | 
					      _hideControlsTimer?.cancel();
 | 
				
			||||||
      _hideControlsTimer = Timer(Duration(seconds: 2), () {
 | 
					      _hideControlsTimer = Timer(const Duration(seconds: 2), () {
 | 
				
			||||||
        setState(() => _showControls = false);
 | 
					        setState(() => _showControls = false);
 | 
				
			||||||
      });
 | 
					      });
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -72,6 +82,12 @@ class _VideoWidgetState extends State<VideoWidget> {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  @override
 | 
					  @override
 | 
				
			||||||
  Widget build(BuildContext context) {
 | 
					  Widget build(BuildContext context) {
 | 
				
			||||||
 | 
					    final muted = ref.watch(mediaProvider).muted;
 | 
				
			||||||
 | 
					    if (_controller.value.isInitialized &&
 | 
				
			||||||
 | 
					        _controller.value.volume != (muted ? 0.0 : 1.0)) {
 | 
				
			||||||
 | 
					      _controller.setVolume(muted ? 0.0 : 1.0);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    bool isAudio = widget.details.mime.startsWith('audio');
 | 
					    bool isAudio = widget.details.mime.startsWith('audio');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return Column(
 | 
					    return Column(
 | 
				
			||||||
@@ -91,7 +107,7 @@ class _VideoWidgetState extends State<VideoWidget> {
 | 
				
			|||||||
                        imageUrl: widget.details.coverUrl,
 | 
					                        imageUrl: widget.details.coverUrl,
 | 
				
			||||||
                        fit: BoxFit.cover,
 | 
					                        fit: BoxFit.cover,
 | 
				
			||||||
                        placeholder: (context, url) =>
 | 
					                        placeholder: (context, url) =>
 | 
				
			||||||
                            CircularProgressIndicator(),
 | 
					                            const CircularProgressIndicator(),
 | 
				
			||||||
                        errorWidget: (context, url, error) => Image.asset(
 | 
					                        errorWidget: (context, url, error) => Image.asset(
 | 
				
			||||||
                          'assets/images/music.webp',
 | 
					                          'assets/images/music.webp',
 | 
				
			||||||
                          fit: BoxFit.contain,
 | 
					                          fit: BoxFit.contain,
 | 
				
			||||||
@@ -100,7 +116,7 @@ class _VideoWidgetState extends State<VideoWidget> {
 | 
				
			|||||||
                      )
 | 
					                      )
 | 
				
			||||||
                    : _controller.value.isInitialized
 | 
					                    : _controller.value.isInitialized
 | 
				
			||||||
                    ? CachedVideoPlayerPlus(_controller)
 | 
					                    ? CachedVideoPlayerPlus(_controller)
 | 
				
			||||||
                    : Center(child: CircularProgressIndicator()),
 | 
					                    : const Center(child: CircularProgressIndicator()),
 | 
				
			||||||
              ),
 | 
					              ),
 | 
				
			||||||
              if (_controller.value.isInitialized && _showControls) ...[
 | 
					              if (_controller.value.isInitialized && _showControls) ...[
 | 
				
			||||||
                IgnorePointer(
 | 
					                IgnorePointer(
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										1
									
								
								linux/.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						@@ -1 +0,0 @@
 | 
				
			|||||||
flutter/ephemeral
 | 
					 | 
				
			||||||
@@ -1,128 +0,0 @@
 | 
				
			|||||||
# Project-level configuration.
 | 
					 | 
				
			||||||
cmake_minimum_required(VERSION 3.13)
 | 
					 | 
				
			||||||
project(runner LANGUAGES CXX)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# The name of the executable created for the application. Change this to change
 | 
					 | 
				
			||||||
# the on-disk name of your application.
 | 
					 | 
				
			||||||
set(BINARY_NAME "f0ckapp")
 | 
					 | 
				
			||||||
# The unique GTK application identifier for this application. See:
 | 
					 | 
				
			||||||
# https://wiki.gnome.org/HowDoI/ChooseApplicationID
 | 
					 | 
				
			||||||
set(APPLICATION_ID "com.example.f0ckapp")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# Explicitly opt in to modern CMake behaviors to avoid warnings with recent
 | 
					 | 
				
			||||||
# versions of CMake.
 | 
					 | 
				
			||||||
cmake_policy(SET CMP0063 NEW)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# Load bundled libraries from the lib/ directory relative to the binary.
 | 
					 | 
				
			||||||
set(CMAKE_INSTALL_RPATH "$ORIGIN/lib")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# Root filesystem for cross-building.
 | 
					 | 
				
			||||||
if(FLUTTER_TARGET_PLATFORM_SYSROOT)
 | 
					 | 
				
			||||||
  set(CMAKE_SYSROOT ${FLUTTER_TARGET_PLATFORM_SYSROOT})
 | 
					 | 
				
			||||||
  set(CMAKE_FIND_ROOT_PATH ${CMAKE_SYSROOT})
 | 
					 | 
				
			||||||
  set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
 | 
					 | 
				
			||||||
  set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
 | 
					 | 
				
			||||||
  set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
 | 
					 | 
				
			||||||
  set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
 | 
					 | 
				
			||||||
endif()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# Define build configuration options.
 | 
					 | 
				
			||||||
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
 | 
					 | 
				
			||||||
  set(CMAKE_BUILD_TYPE "Debug" CACHE
 | 
					 | 
				
			||||||
    STRING "Flutter build mode" FORCE)
 | 
					 | 
				
			||||||
  set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS
 | 
					 | 
				
			||||||
    "Debug" "Profile" "Release")
 | 
					 | 
				
			||||||
endif()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# Compilation settings that should be applied to most targets.
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
# Be cautious about adding new options here, as plugins use this function by
 | 
					 | 
				
			||||||
# default. In most cases, you should add new options to specific targets instead
 | 
					 | 
				
			||||||
# of modifying this function.
 | 
					 | 
				
			||||||
function(APPLY_STANDARD_SETTINGS TARGET)
 | 
					 | 
				
			||||||
  target_compile_features(${TARGET} PUBLIC cxx_std_14)
 | 
					 | 
				
			||||||
  target_compile_options(${TARGET} PRIVATE -Wall -Werror)
 | 
					 | 
				
			||||||
  target_compile_options(${TARGET} PRIVATE "$<$<NOT:$<CONFIG:Debug>>:-O3>")
 | 
					 | 
				
			||||||
  target_compile_definitions(${TARGET} PRIVATE "$<$<NOT:$<CONFIG:Debug>>:NDEBUG>")
 | 
					 | 
				
			||||||
endfunction()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# Flutter library and tool build rules.
 | 
					 | 
				
			||||||
set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter")
 | 
					 | 
				
			||||||
add_subdirectory(${FLUTTER_MANAGED_DIR})
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# System-level dependencies.
 | 
					 | 
				
			||||||
find_package(PkgConfig REQUIRED)
 | 
					 | 
				
			||||||
pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# Application build; see runner/CMakeLists.txt.
 | 
					 | 
				
			||||||
add_subdirectory("runner")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# Run the Flutter tool portions of the build. This must not be removed.
 | 
					 | 
				
			||||||
add_dependencies(${BINARY_NAME} flutter_assemble)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# Only the install-generated bundle's copy of the executable will launch
 | 
					 | 
				
			||||||
# correctly, since the resources must in the right relative locations. To avoid
 | 
					 | 
				
			||||||
# people trying to run the unbundled copy, put it in a subdirectory instead of
 | 
					 | 
				
			||||||
# the default top-level location.
 | 
					 | 
				
			||||||
set_target_properties(${BINARY_NAME}
 | 
					 | 
				
			||||||
  PROPERTIES
 | 
					 | 
				
			||||||
  RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/intermediates_do_not_run"
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# Generated plugin build rules, which manage building the plugins and adding
 | 
					 | 
				
			||||||
# them to the application.
 | 
					 | 
				
			||||||
include(flutter/generated_plugins.cmake)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# === Installation ===
 | 
					 | 
				
			||||||
# By default, "installing" just makes a relocatable bundle in the build
 | 
					 | 
				
			||||||
# directory.
 | 
					 | 
				
			||||||
set(BUILD_BUNDLE_DIR "${PROJECT_BINARY_DIR}/bundle")
 | 
					 | 
				
			||||||
if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
 | 
					 | 
				
			||||||
  set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE)
 | 
					 | 
				
			||||||
endif()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# Start with a clean build bundle directory every time.
 | 
					 | 
				
			||||||
install(CODE "
 | 
					 | 
				
			||||||
  file(REMOVE_RECURSE \"${BUILD_BUNDLE_DIR}/\")
 | 
					 | 
				
			||||||
  " COMPONENT Runtime)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data")
 | 
					 | 
				
			||||||
set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}"
 | 
					 | 
				
			||||||
  COMPONENT Runtime)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}"
 | 
					 | 
				
			||||||
  COMPONENT Runtime)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
 | 
					 | 
				
			||||||
  COMPONENT Runtime)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
foreach(bundled_library ${PLUGIN_BUNDLED_LIBRARIES})
 | 
					 | 
				
			||||||
  install(FILES "${bundled_library}"
 | 
					 | 
				
			||||||
    DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
 | 
					 | 
				
			||||||
    COMPONENT Runtime)
 | 
					 | 
				
			||||||
endforeach(bundled_library)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# Copy the native assets provided by the build.dart from all packages.
 | 
					 | 
				
			||||||
set(NATIVE_ASSETS_DIR "${PROJECT_BUILD_DIR}native_assets/linux/")
 | 
					 | 
				
			||||||
install(DIRECTORY "${NATIVE_ASSETS_DIR}"
 | 
					 | 
				
			||||||
   DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
 | 
					 | 
				
			||||||
   COMPONENT Runtime)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# Fully re-copy the assets directory on each build to avoid having stale files
 | 
					 | 
				
			||||||
# from a previous install.
 | 
					 | 
				
			||||||
set(FLUTTER_ASSET_DIR_NAME "flutter_assets")
 | 
					 | 
				
			||||||
install(CODE "
 | 
					 | 
				
			||||||
  file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\")
 | 
					 | 
				
			||||||
  " COMPONENT Runtime)
 | 
					 | 
				
			||||||
install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}"
 | 
					 | 
				
			||||||
  DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# Install the AOT library on non-Debug builds only.
 | 
					 | 
				
			||||||
if(NOT CMAKE_BUILD_TYPE MATCHES "Debug")
 | 
					 | 
				
			||||||
  install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
 | 
					 | 
				
			||||||
    COMPONENT Runtime)
 | 
					 | 
				
			||||||
endif()
 | 
					 | 
				
			||||||
@@ -1,88 +0,0 @@
 | 
				
			|||||||
# This file controls Flutter-level build steps. It should not be edited.
 | 
					 | 
				
			||||||
cmake_minimum_required(VERSION 3.10)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# Configuration provided via flutter tool.
 | 
					 | 
				
			||||||
include(${EPHEMERAL_DIR}/generated_config.cmake)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# TODO: Move the rest of this into files in ephemeral. See
 | 
					 | 
				
			||||||
# https://github.com/flutter/flutter/issues/57146.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# Serves the same purpose as list(TRANSFORM ... PREPEND ...),
 | 
					 | 
				
			||||||
# which isn't available in 3.10.
 | 
					 | 
				
			||||||
function(list_prepend LIST_NAME PREFIX)
 | 
					 | 
				
			||||||
    set(NEW_LIST "")
 | 
					 | 
				
			||||||
    foreach(element ${${LIST_NAME}})
 | 
					 | 
				
			||||||
        list(APPEND NEW_LIST "${PREFIX}${element}")
 | 
					 | 
				
			||||||
    endforeach(element)
 | 
					 | 
				
			||||||
    set(${LIST_NAME} "${NEW_LIST}" PARENT_SCOPE)
 | 
					 | 
				
			||||||
endfunction()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# === Flutter Library ===
 | 
					 | 
				
			||||||
# System-level dependencies.
 | 
					 | 
				
			||||||
find_package(PkgConfig REQUIRED)
 | 
					 | 
				
			||||||
pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0)
 | 
					 | 
				
			||||||
pkg_check_modules(GLIB REQUIRED IMPORTED_TARGET glib-2.0)
 | 
					 | 
				
			||||||
pkg_check_modules(GIO REQUIRED IMPORTED_TARGET gio-2.0)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/libflutter_linux_gtk.so")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# Published to parent scope for install step.
 | 
					 | 
				
			||||||
set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE)
 | 
					 | 
				
			||||||
set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE)
 | 
					 | 
				
			||||||
set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE)
 | 
					 | 
				
			||||||
set(AOT_LIBRARY "${PROJECT_DIR}/build/lib/libapp.so" PARENT_SCOPE)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
list(APPEND FLUTTER_LIBRARY_HEADERS
 | 
					 | 
				
			||||||
  "fl_basic_message_channel.h"
 | 
					 | 
				
			||||||
  "fl_binary_codec.h"
 | 
					 | 
				
			||||||
  "fl_binary_messenger.h"
 | 
					 | 
				
			||||||
  "fl_dart_project.h"
 | 
					 | 
				
			||||||
  "fl_engine.h"
 | 
					 | 
				
			||||||
  "fl_json_message_codec.h"
 | 
					 | 
				
			||||||
  "fl_json_method_codec.h"
 | 
					 | 
				
			||||||
  "fl_message_codec.h"
 | 
					 | 
				
			||||||
  "fl_method_call.h"
 | 
					 | 
				
			||||||
  "fl_method_channel.h"
 | 
					 | 
				
			||||||
  "fl_method_codec.h"
 | 
					 | 
				
			||||||
  "fl_method_response.h"
 | 
					 | 
				
			||||||
  "fl_plugin_registrar.h"
 | 
					 | 
				
			||||||
  "fl_plugin_registry.h"
 | 
					 | 
				
			||||||
  "fl_standard_message_codec.h"
 | 
					 | 
				
			||||||
  "fl_standard_method_codec.h"
 | 
					 | 
				
			||||||
  "fl_string_codec.h"
 | 
					 | 
				
			||||||
  "fl_value.h"
 | 
					 | 
				
			||||||
  "fl_view.h"
 | 
					 | 
				
			||||||
  "flutter_linux.h"
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
list_prepend(FLUTTER_LIBRARY_HEADERS "${EPHEMERAL_DIR}/flutter_linux/")
 | 
					 | 
				
			||||||
add_library(flutter INTERFACE)
 | 
					 | 
				
			||||||
target_include_directories(flutter INTERFACE
 | 
					 | 
				
			||||||
  "${EPHEMERAL_DIR}"
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}")
 | 
					 | 
				
			||||||
target_link_libraries(flutter INTERFACE
 | 
					 | 
				
			||||||
  PkgConfig::GTK
 | 
					 | 
				
			||||||
  PkgConfig::GLIB
 | 
					 | 
				
			||||||
  PkgConfig::GIO
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
add_dependencies(flutter flutter_assemble)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# === Flutter tool backend ===
 | 
					 | 
				
			||||||
# _phony_ is a non-existent file to force this command to run every time,
 | 
					 | 
				
			||||||
# since currently there's no way to get a full input/output list from the
 | 
					 | 
				
			||||||
# flutter tool.
 | 
					 | 
				
			||||||
add_custom_command(
 | 
					 | 
				
			||||||
  OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS}
 | 
					 | 
				
			||||||
    ${CMAKE_CURRENT_BINARY_DIR}/_phony_
 | 
					 | 
				
			||||||
  COMMAND ${CMAKE_COMMAND} -E env
 | 
					 | 
				
			||||||
    ${FLUTTER_TOOL_ENVIRONMENT}
 | 
					 | 
				
			||||||
    "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.sh"
 | 
					 | 
				
			||||||
      ${FLUTTER_TARGET_PLATFORM} ${CMAKE_BUILD_TYPE}
 | 
					 | 
				
			||||||
  VERBATIM
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
add_custom_target(flutter_assemble DEPENDS
 | 
					 | 
				
			||||||
  "${FLUTTER_LIBRARY}"
 | 
					 | 
				
			||||||
  ${FLUTTER_LIBRARY_HEADERS}
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
@@ -1,19 +0,0 @@
 | 
				
			|||||||
//
 | 
					 | 
				
			||||||
//  Generated file. Do not edit.
 | 
					 | 
				
			||||||
//
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// clang-format off
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "generated_plugin_registrant.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <flutter_secure_storage_linux/flutter_secure_storage_linux_plugin.h>
 | 
					 | 
				
			||||||
#include <url_launcher_linux/url_launcher_plugin.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void fl_register_plugins(FlPluginRegistry* registry) {
 | 
					 | 
				
			||||||
  g_autoptr(FlPluginRegistrar) flutter_secure_storage_linux_registrar =
 | 
					 | 
				
			||||||
      fl_plugin_registry_get_registrar_for_plugin(registry, "FlutterSecureStorageLinuxPlugin");
 | 
					 | 
				
			||||||
  flutter_secure_storage_linux_plugin_register_with_registrar(flutter_secure_storage_linux_registrar);
 | 
					 | 
				
			||||||
  g_autoptr(FlPluginRegistrar) url_launcher_linux_registrar =
 | 
					 | 
				
			||||||
      fl_plugin_registry_get_registrar_for_plugin(registry, "UrlLauncherPlugin");
 | 
					 | 
				
			||||||
  url_launcher_plugin_register_with_registrar(url_launcher_linux_registrar);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -1,15 +0,0 @@
 | 
				
			|||||||
//
 | 
					 | 
				
			||||||
//  Generated file. Do not edit.
 | 
					 | 
				
			||||||
//
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// clang-format off
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifndef GENERATED_PLUGIN_REGISTRANT_
 | 
					 | 
				
			||||||
#define GENERATED_PLUGIN_REGISTRANT_
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <flutter_linux/flutter_linux.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Registers Flutter plugins.
 | 
					 | 
				
			||||||
void fl_register_plugins(FlPluginRegistry* registry);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#endif  // GENERATED_PLUGIN_REGISTRANT_
 | 
					 | 
				
			||||||
@@ -1,25 +0,0 @@
 | 
				
			|||||||
#
 | 
					 | 
				
			||||||
# Generated file, do not edit.
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
list(APPEND FLUTTER_PLUGIN_LIST
 | 
					 | 
				
			||||||
  flutter_secure_storage_linux
 | 
					 | 
				
			||||||
  url_launcher_linux
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
list(APPEND FLUTTER_FFI_PLUGIN_LIST
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
set(PLUGIN_BUNDLED_LIBRARIES)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
foreach(plugin ${FLUTTER_PLUGIN_LIST})
 | 
					 | 
				
			||||||
  add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/linux plugins/${plugin})
 | 
					 | 
				
			||||||
  target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin)
 | 
					 | 
				
			||||||
  list(APPEND PLUGIN_BUNDLED_LIBRARIES $<TARGET_FILE:${plugin}_plugin>)
 | 
					 | 
				
			||||||
  list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries})
 | 
					 | 
				
			||||||
endforeach(plugin)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST})
 | 
					 | 
				
			||||||
  add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/linux plugins/${ffi_plugin})
 | 
					 | 
				
			||||||
  list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries})
 | 
					 | 
				
			||||||
endforeach(ffi_plugin)
 | 
					 | 
				
			||||||
@@ -1,26 +0,0 @@
 | 
				
			|||||||
cmake_minimum_required(VERSION 3.13)
 | 
					 | 
				
			||||||
project(runner LANGUAGES CXX)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# Define the application target. To change its name, change BINARY_NAME in the
 | 
					 | 
				
			||||||
# top-level CMakeLists.txt, not the value here, or `flutter run` will no longer
 | 
					 | 
				
			||||||
# work.
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
# Any new source files that you add to the application should be added here.
 | 
					 | 
				
			||||||
add_executable(${BINARY_NAME}
 | 
					 | 
				
			||||||
  "main.cc"
 | 
					 | 
				
			||||||
  "my_application.cc"
 | 
					 | 
				
			||||||
  "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc"
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# Apply the standard set of build settings. This can be removed for applications
 | 
					 | 
				
			||||||
# that need different build settings.
 | 
					 | 
				
			||||||
apply_standard_settings(${BINARY_NAME})
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# Add preprocessor definitions for the application ID.
 | 
					 | 
				
			||||||
add_definitions(-DAPPLICATION_ID="${APPLICATION_ID}")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# Add dependency libraries. Add any application-specific dependencies here.
 | 
					 | 
				
			||||||
target_link_libraries(${BINARY_NAME} PRIVATE flutter)
 | 
					 | 
				
			||||||
target_link_libraries(${BINARY_NAME} PRIVATE PkgConfig::GTK)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}")
 | 
					 | 
				
			||||||
@@ -1,6 +0,0 @@
 | 
				
			|||||||
#include "my_application.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int main(int argc, char** argv) {
 | 
					 | 
				
			||||||
  g_autoptr(MyApplication) app = my_application_new();
 | 
					 | 
				
			||||||
  return g_application_run(G_APPLICATION(app), argc, argv);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -1,130 +0,0 @@
 | 
				
			|||||||
#include "my_application.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <flutter_linux/flutter_linux.h>
 | 
					 | 
				
			||||||
#ifdef GDK_WINDOWING_X11
 | 
					 | 
				
			||||||
#include <gdk/gdkx.h>
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "flutter/generated_plugin_registrant.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct _MyApplication {
 | 
					 | 
				
			||||||
  GtkApplication parent_instance;
 | 
					 | 
				
			||||||
  char** dart_entrypoint_arguments;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
G_DEFINE_TYPE(MyApplication, my_application, GTK_TYPE_APPLICATION)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Implements GApplication::activate.
 | 
					 | 
				
			||||||
static void my_application_activate(GApplication* application) {
 | 
					 | 
				
			||||||
  MyApplication* self = MY_APPLICATION(application);
 | 
					 | 
				
			||||||
  GtkWindow* window =
 | 
					 | 
				
			||||||
      GTK_WINDOW(gtk_application_window_new(GTK_APPLICATION(application)));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Use a header bar when running in GNOME as this is the common style used
 | 
					 | 
				
			||||||
  // by applications and is the setup most users will be using (e.g. Ubuntu
 | 
					 | 
				
			||||||
  // desktop).
 | 
					 | 
				
			||||||
  // If running on X and not using GNOME then just use a traditional title bar
 | 
					 | 
				
			||||||
  // in case the window manager does more exotic layout, e.g. tiling.
 | 
					 | 
				
			||||||
  // If running on Wayland assume the header bar will work (may need changing
 | 
					 | 
				
			||||||
  // if future cases occur).
 | 
					 | 
				
			||||||
  gboolean use_header_bar = TRUE;
 | 
					 | 
				
			||||||
#ifdef GDK_WINDOWING_X11
 | 
					 | 
				
			||||||
  GdkScreen* screen = gtk_window_get_screen(window);
 | 
					 | 
				
			||||||
  if (GDK_IS_X11_SCREEN(screen)) {
 | 
					 | 
				
			||||||
    const gchar* wm_name = gdk_x11_screen_get_window_manager_name(screen);
 | 
					 | 
				
			||||||
    if (g_strcmp0(wm_name, "GNOME Shell") != 0) {
 | 
					 | 
				
			||||||
      use_header_bar = FALSE;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
  if (use_header_bar) {
 | 
					 | 
				
			||||||
    GtkHeaderBar* header_bar = GTK_HEADER_BAR(gtk_header_bar_new());
 | 
					 | 
				
			||||||
    gtk_widget_show(GTK_WIDGET(header_bar));
 | 
					 | 
				
			||||||
    gtk_header_bar_set_title(header_bar, "f0ckapp");
 | 
					 | 
				
			||||||
    gtk_header_bar_set_show_close_button(header_bar, TRUE);
 | 
					 | 
				
			||||||
    gtk_window_set_titlebar(window, GTK_WIDGET(header_bar));
 | 
					 | 
				
			||||||
  } else {
 | 
					 | 
				
			||||||
    gtk_window_set_title(window, "f0ckapp");
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  gtk_window_set_default_size(window, 1280, 720);
 | 
					 | 
				
			||||||
  gtk_widget_show(GTK_WIDGET(window));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  g_autoptr(FlDartProject) project = fl_dart_project_new();
 | 
					 | 
				
			||||||
  fl_dart_project_set_dart_entrypoint_arguments(project, self->dart_entrypoint_arguments);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  FlView* view = fl_view_new(project);
 | 
					 | 
				
			||||||
  gtk_widget_show(GTK_WIDGET(view));
 | 
					 | 
				
			||||||
  gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(view));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  fl_register_plugins(FL_PLUGIN_REGISTRY(view));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  gtk_widget_grab_focus(GTK_WIDGET(view));
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Implements GApplication::local_command_line.
 | 
					 | 
				
			||||||
static gboolean my_application_local_command_line(GApplication* application, gchar*** arguments, int* exit_status) {
 | 
					 | 
				
			||||||
  MyApplication* self = MY_APPLICATION(application);
 | 
					 | 
				
			||||||
  // Strip out the first argument as it is the binary name.
 | 
					 | 
				
			||||||
  self->dart_entrypoint_arguments = g_strdupv(*arguments + 1);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  g_autoptr(GError) error = nullptr;
 | 
					 | 
				
			||||||
  if (!g_application_register(application, nullptr, &error)) {
 | 
					 | 
				
			||||||
     g_warning("Failed to register: %s", error->message);
 | 
					 | 
				
			||||||
     *exit_status = 1;
 | 
					 | 
				
			||||||
     return TRUE;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  g_application_activate(application);
 | 
					 | 
				
			||||||
  *exit_status = 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return TRUE;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Implements GApplication::startup.
 | 
					 | 
				
			||||||
static void my_application_startup(GApplication* application) {
 | 
					 | 
				
			||||||
  //MyApplication* self = MY_APPLICATION(object);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Perform any actions required at application startup.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  G_APPLICATION_CLASS(my_application_parent_class)->startup(application);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Implements GApplication::shutdown.
 | 
					 | 
				
			||||||
static void my_application_shutdown(GApplication* application) {
 | 
					 | 
				
			||||||
  //MyApplication* self = MY_APPLICATION(object);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Perform any actions required at application shutdown.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  G_APPLICATION_CLASS(my_application_parent_class)->shutdown(application);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Implements GObject::dispose.
 | 
					 | 
				
			||||||
static void my_application_dispose(GObject* object) {
 | 
					 | 
				
			||||||
  MyApplication* self = MY_APPLICATION(object);
 | 
					 | 
				
			||||||
  g_clear_pointer(&self->dart_entrypoint_arguments, g_strfreev);
 | 
					 | 
				
			||||||
  G_OBJECT_CLASS(my_application_parent_class)->dispose(object);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void my_application_class_init(MyApplicationClass* klass) {
 | 
					 | 
				
			||||||
  G_APPLICATION_CLASS(klass)->activate = my_application_activate;
 | 
					 | 
				
			||||||
  G_APPLICATION_CLASS(klass)->local_command_line = my_application_local_command_line;
 | 
					 | 
				
			||||||
  G_APPLICATION_CLASS(klass)->startup = my_application_startup;
 | 
					 | 
				
			||||||
  G_APPLICATION_CLASS(klass)->shutdown = my_application_shutdown;
 | 
					 | 
				
			||||||
  G_OBJECT_CLASS(klass)->dispose = my_application_dispose;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void my_application_init(MyApplication* self) {}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
MyApplication* my_application_new() {
 | 
					 | 
				
			||||||
  // Set the program name to the application ID, which helps various systems
 | 
					 | 
				
			||||||
  // like GTK and desktop environments map this running application to its
 | 
					 | 
				
			||||||
  // corresponding .desktop file. This ensures better integration by allowing
 | 
					 | 
				
			||||||
  // the application to be recognized beyond its binary name.
 | 
					 | 
				
			||||||
  g_set_prgname(APPLICATION_ID);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return MY_APPLICATION(g_object_new(my_application_get_type(),
 | 
					 | 
				
			||||||
                                     "application-id", APPLICATION_ID,
 | 
					 | 
				
			||||||
                                     "flags", G_APPLICATION_NON_UNIQUE,
 | 
					 | 
				
			||||||
                                     nullptr));
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -1,18 +0,0 @@
 | 
				
			|||||||
#ifndef FLUTTER_MY_APPLICATION_H_
 | 
					 | 
				
			||||||
#define FLUTTER_MY_APPLICATION_H_
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <gtk/gtk.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
G_DECLARE_FINAL_TYPE(MyApplication, my_application, MY, APPLICATION,
 | 
					 | 
				
			||||||
                     GtkApplication)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * my_application_new:
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * Creates a new Flutter-based application.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * Returns: a new #MyApplication.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
MyApplication* my_application_new();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#endif  // FLUTTER_MY_APPLICATION_H_
 | 
					 | 
				
			||||||
							
								
								
									
										7
									
								
								macos/.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						@@ -1,7 +0,0 @@
 | 
				
			|||||||
# Flutter-related
 | 
					 | 
				
			||||||
**/Flutter/ephemeral/
 | 
					 | 
				
			||||||
**/Pods/
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# Xcode-related
 | 
					 | 
				
			||||||
**/dgph
 | 
					 | 
				
			||||||
**/xcuserdata/
 | 
					 | 
				
			||||||
@@ -1 +0,0 @@
 | 
				
			|||||||
#include "ephemeral/Flutter-Generated.xcconfig"
 | 
					 | 
				
			||||||
@@ -1 +0,0 @@
 | 
				
			|||||||
#include "ephemeral/Flutter-Generated.xcconfig"
 | 
					 | 
				
			||||||
@@ -1,22 +0,0 @@
 | 
				
			|||||||
//
 | 
					 | 
				
			||||||
//  Generated file. Do not edit.
 | 
					 | 
				
			||||||
//
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import FlutterMacOS
 | 
					 | 
				
			||||||
import Foundation
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import flutter_secure_storage_macos
 | 
					 | 
				
			||||||
import package_info_plus
 | 
					 | 
				
			||||||
import path_provider_foundation
 | 
					 | 
				
			||||||
import share_plus
 | 
					 | 
				
			||||||
import sqflite_darwin
 | 
					 | 
				
			||||||
import video_player_avfoundation
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
 | 
					 | 
				
			||||||
  FlutterSecureStoragePlugin.register(with: registry.registrar(forPlugin: "FlutterSecureStoragePlugin"))
 | 
					 | 
				
			||||||
  FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin"))
 | 
					 | 
				
			||||||
  PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
 | 
					 | 
				
			||||||
  SharePlusMacosPlugin.register(with: registry.registrar(forPlugin: "SharePlusMacosPlugin"))
 | 
					 | 
				
			||||||
  SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin"))
 | 
					 | 
				
			||||||
  FVPVideoPlayerPlugin.register(with: registry.registrar(forPlugin: "FVPVideoPlayerPlugin"))
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -1,705 +0,0 @@
 | 
				
			|||||||
// !$*UTF8*$!
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	archiveVersion = 1;
 | 
					 | 
				
			||||||
	classes = {
 | 
					 | 
				
			||||||
	};
 | 
					 | 
				
			||||||
	objectVersion = 54;
 | 
					 | 
				
			||||||
	objects = {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Begin PBXAggregateTarget section */
 | 
					 | 
				
			||||||
		33CC111A2044C6BA0003C045 /* Flutter Assemble */ = {
 | 
					 | 
				
			||||||
			isa = PBXAggregateTarget;
 | 
					 | 
				
			||||||
			buildConfigurationList = 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */;
 | 
					 | 
				
			||||||
			buildPhases = (
 | 
					 | 
				
			||||||
				33CC111E2044C6BF0003C045 /* ShellScript */,
 | 
					 | 
				
			||||||
			);
 | 
					 | 
				
			||||||
			dependencies = (
 | 
					 | 
				
			||||||
			);
 | 
					 | 
				
			||||||
			name = "Flutter Assemble";
 | 
					 | 
				
			||||||
			productName = FLX;
 | 
					 | 
				
			||||||
		};
 | 
					 | 
				
			||||||
/* End PBXAggregateTarget section */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Begin PBXBuildFile section */
 | 
					 | 
				
			||||||
		331C80D8294CF71000263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C80D7294CF71000263BE5 /* RunnerTests.swift */; };
 | 
					 | 
				
			||||||
		335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */; };
 | 
					 | 
				
			||||||
		33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC10F02044A3C60003C045 /* AppDelegate.swift */; };
 | 
					 | 
				
			||||||
		33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; };
 | 
					 | 
				
			||||||
		33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; };
 | 
					 | 
				
			||||||
		33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; };
 | 
					 | 
				
			||||||
/* End PBXBuildFile section */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Begin PBXContainerItemProxy section */
 | 
					 | 
				
			||||||
		331C80D9294CF71000263BE5 /* PBXContainerItemProxy */ = {
 | 
					 | 
				
			||||||
			isa = PBXContainerItemProxy;
 | 
					 | 
				
			||||||
			containerPortal = 33CC10E52044A3C60003C045 /* Project object */;
 | 
					 | 
				
			||||||
			proxyType = 1;
 | 
					 | 
				
			||||||
			remoteGlobalIDString = 33CC10EC2044A3C60003C045;
 | 
					 | 
				
			||||||
			remoteInfo = Runner;
 | 
					 | 
				
			||||||
		};
 | 
					 | 
				
			||||||
		33CC111F2044C79F0003C045 /* PBXContainerItemProxy */ = {
 | 
					 | 
				
			||||||
			isa = PBXContainerItemProxy;
 | 
					 | 
				
			||||||
			containerPortal = 33CC10E52044A3C60003C045 /* Project object */;
 | 
					 | 
				
			||||||
			proxyType = 1;
 | 
					 | 
				
			||||||
			remoteGlobalIDString = 33CC111A2044C6BA0003C045;
 | 
					 | 
				
			||||||
			remoteInfo = FLX;
 | 
					 | 
				
			||||||
		};
 | 
					 | 
				
			||||||
/* End PBXContainerItemProxy section */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Begin PBXCopyFilesBuildPhase section */
 | 
					 | 
				
			||||||
		33CC110E2044A8840003C045 /* Bundle Framework */ = {
 | 
					 | 
				
			||||||
			isa = PBXCopyFilesBuildPhase;
 | 
					 | 
				
			||||||
			buildActionMask = 2147483647;
 | 
					 | 
				
			||||||
			dstPath = "";
 | 
					 | 
				
			||||||
			dstSubfolderSpec = 10;
 | 
					 | 
				
			||||||
			files = (
 | 
					 | 
				
			||||||
			);
 | 
					 | 
				
			||||||
			name = "Bundle Framework";
 | 
					 | 
				
			||||||
			runOnlyForDeploymentPostprocessing = 0;
 | 
					 | 
				
			||||||
		};
 | 
					 | 
				
			||||||
/* End PBXCopyFilesBuildPhase section */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Begin PBXFileReference section */
 | 
					 | 
				
			||||||
		331C80D5294CF71000263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
 | 
					 | 
				
			||||||
		331C80D7294CF71000263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = "<group>"; };
 | 
					 | 
				
			||||||
		333000ED22D3DE5D00554162 /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Warnings.xcconfig; sourceTree = "<group>"; };
 | 
					 | 
				
			||||||
		335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneratedPluginRegistrant.swift; sourceTree = "<group>"; };
 | 
					 | 
				
			||||||
		33CC10ED2044A3C60003C045 /* f0ckapp.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "f0ckapp.app"; sourceTree = BUILT_PRODUCTS_DIR; };
 | 
					 | 
				
			||||||
		33CC10F02044A3C60003C045 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
 | 
					 | 
				
			||||||
		33CC10F22044A3C60003C045 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = Runner/Assets.xcassets; sourceTree = "<group>"; };
 | 
					 | 
				
			||||||
		33CC10F52044A3C60003C045 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = "<group>"; };
 | 
					 | 
				
			||||||
		33CC10F72044A3C60003C045 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Info.plist; path = Runner/Info.plist; sourceTree = "<group>"; };
 | 
					 | 
				
			||||||
		33CC11122044BFA00003C045 /* MainFlutterWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainFlutterWindow.swift; sourceTree = "<group>"; };
 | 
					 | 
				
			||||||
		33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Debug.xcconfig"; sourceTree = "<group>"; };
 | 
					 | 
				
			||||||
		33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Release.xcconfig"; sourceTree = "<group>"; };
 | 
					 | 
				
			||||||
		33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = "Flutter-Generated.xcconfig"; path = "ephemeral/Flutter-Generated.xcconfig"; sourceTree = "<group>"; };
 | 
					 | 
				
			||||||
		33E51913231747F40026EE4D /* DebugProfile.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DebugProfile.entitlements; sourceTree = "<group>"; };
 | 
					 | 
				
			||||||
		33E51914231749380026EE4D /* Release.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Release.entitlements; sourceTree = "<group>"; };
 | 
					 | 
				
			||||||
		33E5194F232828860026EE4D /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = "<group>"; };
 | 
					 | 
				
			||||||
		7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = "<group>"; };
 | 
					 | 
				
			||||||
		9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = "<group>"; };
 | 
					 | 
				
			||||||
/* End PBXFileReference section */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Begin PBXFrameworksBuildPhase section */
 | 
					 | 
				
			||||||
		331C80D2294CF70F00263BE5 /* Frameworks */ = {
 | 
					 | 
				
			||||||
			isa = PBXFrameworksBuildPhase;
 | 
					 | 
				
			||||||
			buildActionMask = 2147483647;
 | 
					 | 
				
			||||||
			files = (
 | 
					 | 
				
			||||||
			);
 | 
					 | 
				
			||||||
			runOnlyForDeploymentPostprocessing = 0;
 | 
					 | 
				
			||||||
		};
 | 
					 | 
				
			||||||
		33CC10EA2044A3C60003C045 /* Frameworks */ = {
 | 
					 | 
				
			||||||
			isa = PBXFrameworksBuildPhase;
 | 
					 | 
				
			||||||
			buildActionMask = 2147483647;
 | 
					 | 
				
			||||||
			files = (
 | 
					 | 
				
			||||||
			);
 | 
					 | 
				
			||||||
			runOnlyForDeploymentPostprocessing = 0;
 | 
					 | 
				
			||||||
		};
 | 
					 | 
				
			||||||
/* End PBXFrameworksBuildPhase section */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Begin PBXGroup section */
 | 
					 | 
				
			||||||
		331C80D6294CF71000263BE5 /* RunnerTests */ = {
 | 
					 | 
				
			||||||
			isa = PBXGroup;
 | 
					 | 
				
			||||||
			children = (
 | 
					 | 
				
			||||||
				331C80D7294CF71000263BE5 /* RunnerTests.swift */,
 | 
					 | 
				
			||||||
			);
 | 
					 | 
				
			||||||
			path = RunnerTests;
 | 
					 | 
				
			||||||
			sourceTree = "<group>";
 | 
					 | 
				
			||||||
		};
 | 
					 | 
				
			||||||
		33BA886A226E78AF003329D5 /* Configs */ = {
 | 
					 | 
				
			||||||
			isa = PBXGroup;
 | 
					 | 
				
			||||||
			children = (
 | 
					 | 
				
			||||||
				33E5194F232828860026EE4D /* AppInfo.xcconfig */,
 | 
					 | 
				
			||||||
				9740EEB21CF90195004384FC /* Debug.xcconfig */,
 | 
					 | 
				
			||||||
				7AFA3C8E1D35360C0083082E /* Release.xcconfig */,
 | 
					 | 
				
			||||||
				333000ED22D3DE5D00554162 /* Warnings.xcconfig */,
 | 
					 | 
				
			||||||
			);
 | 
					 | 
				
			||||||
			path = Configs;
 | 
					 | 
				
			||||||
			sourceTree = "<group>";
 | 
					 | 
				
			||||||
		};
 | 
					 | 
				
			||||||
		33CC10E42044A3C60003C045 = {
 | 
					 | 
				
			||||||
			isa = PBXGroup;
 | 
					 | 
				
			||||||
			children = (
 | 
					 | 
				
			||||||
				33FAB671232836740065AC1E /* Runner */,
 | 
					 | 
				
			||||||
				33CEB47122A05771004F2AC0 /* Flutter */,
 | 
					 | 
				
			||||||
				331C80D6294CF71000263BE5 /* RunnerTests */,
 | 
					 | 
				
			||||||
				33CC10EE2044A3C60003C045 /* Products */,
 | 
					 | 
				
			||||||
				D73912EC22F37F3D000D13A0 /* Frameworks */,
 | 
					 | 
				
			||||||
			);
 | 
					 | 
				
			||||||
			sourceTree = "<group>";
 | 
					 | 
				
			||||||
		};
 | 
					 | 
				
			||||||
		33CC10EE2044A3C60003C045 /* Products */ = {
 | 
					 | 
				
			||||||
			isa = PBXGroup;
 | 
					 | 
				
			||||||
			children = (
 | 
					 | 
				
			||||||
				33CC10ED2044A3C60003C045 /* f0ckapp.app */,
 | 
					 | 
				
			||||||
				331C80D5294CF71000263BE5 /* RunnerTests.xctest */,
 | 
					 | 
				
			||||||
			);
 | 
					 | 
				
			||||||
			name = Products;
 | 
					 | 
				
			||||||
			sourceTree = "<group>";
 | 
					 | 
				
			||||||
		};
 | 
					 | 
				
			||||||
		33CC11242044D66E0003C045 /* Resources */ = {
 | 
					 | 
				
			||||||
			isa = PBXGroup;
 | 
					 | 
				
			||||||
			children = (
 | 
					 | 
				
			||||||
				33CC10F22044A3C60003C045 /* Assets.xcassets */,
 | 
					 | 
				
			||||||
				33CC10F42044A3C60003C045 /* MainMenu.xib */,
 | 
					 | 
				
			||||||
				33CC10F72044A3C60003C045 /* Info.plist */,
 | 
					 | 
				
			||||||
			);
 | 
					 | 
				
			||||||
			name = Resources;
 | 
					 | 
				
			||||||
			path = ..;
 | 
					 | 
				
			||||||
			sourceTree = "<group>";
 | 
					 | 
				
			||||||
		};
 | 
					 | 
				
			||||||
		33CEB47122A05771004F2AC0 /* Flutter */ = {
 | 
					 | 
				
			||||||
			isa = PBXGroup;
 | 
					 | 
				
			||||||
			children = (
 | 
					 | 
				
			||||||
				335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */,
 | 
					 | 
				
			||||||
				33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */,
 | 
					 | 
				
			||||||
				33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */,
 | 
					 | 
				
			||||||
				33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */,
 | 
					 | 
				
			||||||
			);
 | 
					 | 
				
			||||||
			path = Flutter;
 | 
					 | 
				
			||||||
			sourceTree = "<group>";
 | 
					 | 
				
			||||||
		};
 | 
					 | 
				
			||||||
		33FAB671232836740065AC1E /* Runner */ = {
 | 
					 | 
				
			||||||
			isa = PBXGroup;
 | 
					 | 
				
			||||||
			children = (
 | 
					 | 
				
			||||||
				33CC10F02044A3C60003C045 /* AppDelegate.swift */,
 | 
					 | 
				
			||||||
				33CC11122044BFA00003C045 /* MainFlutterWindow.swift */,
 | 
					 | 
				
			||||||
				33E51913231747F40026EE4D /* DebugProfile.entitlements */,
 | 
					 | 
				
			||||||
				33E51914231749380026EE4D /* Release.entitlements */,
 | 
					 | 
				
			||||||
				33CC11242044D66E0003C045 /* Resources */,
 | 
					 | 
				
			||||||
				33BA886A226E78AF003329D5 /* Configs */,
 | 
					 | 
				
			||||||
			);
 | 
					 | 
				
			||||||
			path = Runner;
 | 
					 | 
				
			||||||
			sourceTree = "<group>";
 | 
					 | 
				
			||||||
		};
 | 
					 | 
				
			||||||
		D73912EC22F37F3D000D13A0 /* Frameworks */ = {
 | 
					 | 
				
			||||||
			isa = PBXGroup;
 | 
					 | 
				
			||||||
			children = (
 | 
					 | 
				
			||||||
			);
 | 
					 | 
				
			||||||
			name = Frameworks;
 | 
					 | 
				
			||||||
			sourceTree = "<group>";
 | 
					 | 
				
			||||||
		};
 | 
					 | 
				
			||||||
/* End PBXGroup section */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Begin PBXNativeTarget section */
 | 
					 | 
				
			||||||
		331C80D4294CF70F00263BE5 /* RunnerTests */ = {
 | 
					 | 
				
			||||||
			isa = PBXNativeTarget;
 | 
					 | 
				
			||||||
			buildConfigurationList = 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */;
 | 
					 | 
				
			||||||
			buildPhases = (
 | 
					 | 
				
			||||||
				331C80D1294CF70F00263BE5 /* Sources */,
 | 
					 | 
				
			||||||
				331C80D2294CF70F00263BE5 /* Frameworks */,
 | 
					 | 
				
			||||||
				331C80D3294CF70F00263BE5 /* Resources */,
 | 
					 | 
				
			||||||
			);
 | 
					 | 
				
			||||||
			buildRules = (
 | 
					 | 
				
			||||||
			);
 | 
					 | 
				
			||||||
			dependencies = (
 | 
					 | 
				
			||||||
				331C80DA294CF71000263BE5 /* PBXTargetDependency */,
 | 
					 | 
				
			||||||
			);
 | 
					 | 
				
			||||||
			name = RunnerTests;
 | 
					 | 
				
			||||||
			productName = RunnerTests;
 | 
					 | 
				
			||||||
			productReference = 331C80D5294CF71000263BE5 /* RunnerTests.xctest */;
 | 
					 | 
				
			||||||
			productType = "com.apple.product-type.bundle.unit-test";
 | 
					 | 
				
			||||||
		};
 | 
					 | 
				
			||||||
		33CC10EC2044A3C60003C045 /* Runner */ = {
 | 
					 | 
				
			||||||
			isa = PBXNativeTarget;
 | 
					 | 
				
			||||||
			buildConfigurationList = 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */;
 | 
					 | 
				
			||||||
			buildPhases = (
 | 
					 | 
				
			||||||
				33CC10E92044A3C60003C045 /* Sources */,
 | 
					 | 
				
			||||||
				33CC10EA2044A3C60003C045 /* Frameworks */,
 | 
					 | 
				
			||||||
				33CC10EB2044A3C60003C045 /* Resources */,
 | 
					 | 
				
			||||||
				33CC110E2044A8840003C045 /* Bundle Framework */,
 | 
					 | 
				
			||||||
				3399D490228B24CF009A79C7 /* ShellScript */,
 | 
					 | 
				
			||||||
			);
 | 
					 | 
				
			||||||
			buildRules = (
 | 
					 | 
				
			||||||
			);
 | 
					 | 
				
			||||||
			dependencies = (
 | 
					 | 
				
			||||||
				33CC11202044C79F0003C045 /* PBXTargetDependency */,
 | 
					 | 
				
			||||||
			);
 | 
					 | 
				
			||||||
			name = Runner;
 | 
					 | 
				
			||||||
			productName = Runner;
 | 
					 | 
				
			||||||
			productReference = 33CC10ED2044A3C60003C045 /* f0ckapp.app */;
 | 
					 | 
				
			||||||
			productType = "com.apple.product-type.application";
 | 
					 | 
				
			||||||
		};
 | 
					 | 
				
			||||||
/* End PBXNativeTarget section */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Begin PBXProject section */
 | 
					 | 
				
			||||||
		33CC10E52044A3C60003C045 /* Project object */ = {
 | 
					 | 
				
			||||||
			isa = PBXProject;
 | 
					 | 
				
			||||||
			attributes = {
 | 
					 | 
				
			||||||
				BuildIndependentTargetsInParallel = YES;
 | 
					 | 
				
			||||||
				LastSwiftUpdateCheck = 0920;
 | 
					 | 
				
			||||||
				LastUpgradeCheck = 1510;
 | 
					 | 
				
			||||||
				ORGANIZATIONNAME = "";
 | 
					 | 
				
			||||||
				TargetAttributes = {
 | 
					 | 
				
			||||||
					331C80D4294CF70F00263BE5 = {
 | 
					 | 
				
			||||||
						CreatedOnToolsVersion = 14.0;
 | 
					 | 
				
			||||||
						TestTargetID = 33CC10EC2044A3C60003C045;
 | 
					 | 
				
			||||||
					};
 | 
					 | 
				
			||||||
					33CC10EC2044A3C60003C045 = {
 | 
					 | 
				
			||||||
						CreatedOnToolsVersion = 9.2;
 | 
					 | 
				
			||||||
						LastSwiftMigration = 1100;
 | 
					 | 
				
			||||||
						ProvisioningStyle = Automatic;
 | 
					 | 
				
			||||||
						SystemCapabilities = {
 | 
					 | 
				
			||||||
							com.apple.Sandbox = {
 | 
					 | 
				
			||||||
								enabled = 1;
 | 
					 | 
				
			||||||
							};
 | 
					 | 
				
			||||||
						};
 | 
					 | 
				
			||||||
					};
 | 
					 | 
				
			||||||
					33CC111A2044C6BA0003C045 = {
 | 
					 | 
				
			||||||
						CreatedOnToolsVersion = 9.2;
 | 
					 | 
				
			||||||
						ProvisioningStyle = Manual;
 | 
					 | 
				
			||||||
					};
 | 
					 | 
				
			||||||
				};
 | 
					 | 
				
			||||||
			};
 | 
					 | 
				
			||||||
			buildConfigurationList = 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */;
 | 
					 | 
				
			||||||
			compatibilityVersion = "Xcode 9.3";
 | 
					 | 
				
			||||||
			developmentRegion = en;
 | 
					 | 
				
			||||||
			hasScannedForEncodings = 0;
 | 
					 | 
				
			||||||
			knownRegions = (
 | 
					 | 
				
			||||||
				en,
 | 
					 | 
				
			||||||
				Base,
 | 
					 | 
				
			||||||
			);
 | 
					 | 
				
			||||||
			mainGroup = 33CC10E42044A3C60003C045;
 | 
					 | 
				
			||||||
			productRefGroup = 33CC10EE2044A3C60003C045 /* Products */;
 | 
					 | 
				
			||||||
			projectDirPath = "";
 | 
					 | 
				
			||||||
			projectRoot = "";
 | 
					 | 
				
			||||||
			targets = (
 | 
					 | 
				
			||||||
				33CC10EC2044A3C60003C045 /* Runner */,
 | 
					 | 
				
			||||||
				331C80D4294CF70F00263BE5 /* RunnerTests */,
 | 
					 | 
				
			||||||
				33CC111A2044C6BA0003C045 /* Flutter Assemble */,
 | 
					 | 
				
			||||||
			);
 | 
					 | 
				
			||||||
		};
 | 
					 | 
				
			||||||
/* End PBXProject section */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Begin PBXResourcesBuildPhase section */
 | 
					 | 
				
			||||||
		331C80D3294CF70F00263BE5 /* Resources */ = {
 | 
					 | 
				
			||||||
			isa = PBXResourcesBuildPhase;
 | 
					 | 
				
			||||||
			buildActionMask = 2147483647;
 | 
					 | 
				
			||||||
			files = (
 | 
					 | 
				
			||||||
			);
 | 
					 | 
				
			||||||
			runOnlyForDeploymentPostprocessing = 0;
 | 
					 | 
				
			||||||
		};
 | 
					 | 
				
			||||||
		33CC10EB2044A3C60003C045 /* Resources */ = {
 | 
					 | 
				
			||||||
			isa = PBXResourcesBuildPhase;
 | 
					 | 
				
			||||||
			buildActionMask = 2147483647;
 | 
					 | 
				
			||||||
			files = (
 | 
					 | 
				
			||||||
				33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */,
 | 
					 | 
				
			||||||
				33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */,
 | 
					 | 
				
			||||||
			);
 | 
					 | 
				
			||||||
			runOnlyForDeploymentPostprocessing = 0;
 | 
					 | 
				
			||||||
		};
 | 
					 | 
				
			||||||
/* End PBXResourcesBuildPhase section */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Begin PBXShellScriptBuildPhase section */
 | 
					 | 
				
			||||||
		3399D490228B24CF009A79C7 /* ShellScript */ = {
 | 
					 | 
				
			||||||
			isa = PBXShellScriptBuildPhase;
 | 
					 | 
				
			||||||
			alwaysOutOfDate = 1;
 | 
					 | 
				
			||||||
			buildActionMask = 2147483647;
 | 
					 | 
				
			||||||
			files = (
 | 
					 | 
				
			||||||
			);
 | 
					 | 
				
			||||||
			inputFileListPaths = (
 | 
					 | 
				
			||||||
			);
 | 
					 | 
				
			||||||
			inputPaths = (
 | 
					 | 
				
			||||||
			);
 | 
					 | 
				
			||||||
			outputFileListPaths = (
 | 
					 | 
				
			||||||
			);
 | 
					 | 
				
			||||||
			outputPaths = (
 | 
					 | 
				
			||||||
			);
 | 
					 | 
				
			||||||
			runOnlyForDeploymentPostprocessing = 0;
 | 
					 | 
				
			||||||
			shellPath = /bin/sh;
 | 
					 | 
				
			||||||
			shellScript = "echo \"$PRODUCT_NAME.app\" > \"$PROJECT_DIR\"/Flutter/ephemeral/.app_filename && \"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh embed\n";
 | 
					 | 
				
			||||||
		};
 | 
					 | 
				
			||||||
		33CC111E2044C6BF0003C045 /* ShellScript */ = {
 | 
					 | 
				
			||||||
			isa = PBXShellScriptBuildPhase;
 | 
					 | 
				
			||||||
			buildActionMask = 2147483647;
 | 
					 | 
				
			||||||
			files = (
 | 
					 | 
				
			||||||
			);
 | 
					 | 
				
			||||||
			inputFileListPaths = (
 | 
					 | 
				
			||||||
				Flutter/ephemeral/FlutterInputs.xcfilelist,
 | 
					 | 
				
			||||||
			);
 | 
					 | 
				
			||||||
			inputPaths = (
 | 
					 | 
				
			||||||
				Flutter/ephemeral/tripwire,
 | 
					 | 
				
			||||||
			);
 | 
					 | 
				
			||||||
			outputFileListPaths = (
 | 
					 | 
				
			||||||
				Flutter/ephemeral/FlutterOutputs.xcfilelist,
 | 
					 | 
				
			||||||
			);
 | 
					 | 
				
			||||||
			outputPaths = (
 | 
					 | 
				
			||||||
			);
 | 
					 | 
				
			||||||
			runOnlyForDeploymentPostprocessing = 0;
 | 
					 | 
				
			||||||
			shellPath = /bin/sh;
 | 
					 | 
				
			||||||
			shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh && touch Flutter/ephemeral/tripwire";
 | 
					 | 
				
			||||||
		};
 | 
					 | 
				
			||||||
/* End PBXShellScriptBuildPhase section */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Begin PBXSourcesBuildPhase section */
 | 
					 | 
				
			||||||
		331C80D1294CF70F00263BE5 /* Sources */ = {
 | 
					 | 
				
			||||||
			isa = PBXSourcesBuildPhase;
 | 
					 | 
				
			||||||
			buildActionMask = 2147483647;
 | 
					 | 
				
			||||||
			files = (
 | 
					 | 
				
			||||||
				331C80D8294CF71000263BE5 /* RunnerTests.swift in Sources */,
 | 
					 | 
				
			||||||
			);
 | 
					 | 
				
			||||||
			runOnlyForDeploymentPostprocessing = 0;
 | 
					 | 
				
			||||||
		};
 | 
					 | 
				
			||||||
		33CC10E92044A3C60003C045 /* Sources */ = {
 | 
					 | 
				
			||||||
			isa = PBXSourcesBuildPhase;
 | 
					 | 
				
			||||||
			buildActionMask = 2147483647;
 | 
					 | 
				
			||||||
			files = (
 | 
					 | 
				
			||||||
				33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */,
 | 
					 | 
				
			||||||
				33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */,
 | 
					 | 
				
			||||||
				335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */,
 | 
					 | 
				
			||||||
			);
 | 
					 | 
				
			||||||
			runOnlyForDeploymentPostprocessing = 0;
 | 
					 | 
				
			||||||
		};
 | 
					 | 
				
			||||||
/* End PBXSourcesBuildPhase section */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Begin PBXTargetDependency section */
 | 
					 | 
				
			||||||
		331C80DA294CF71000263BE5 /* PBXTargetDependency */ = {
 | 
					 | 
				
			||||||
			isa = PBXTargetDependency;
 | 
					 | 
				
			||||||
			target = 33CC10EC2044A3C60003C045 /* Runner */;
 | 
					 | 
				
			||||||
			targetProxy = 331C80D9294CF71000263BE5 /* PBXContainerItemProxy */;
 | 
					 | 
				
			||||||
		};
 | 
					 | 
				
			||||||
		33CC11202044C79F0003C045 /* PBXTargetDependency */ = {
 | 
					 | 
				
			||||||
			isa = PBXTargetDependency;
 | 
					 | 
				
			||||||
			target = 33CC111A2044C6BA0003C045 /* Flutter Assemble */;
 | 
					 | 
				
			||||||
			targetProxy = 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */;
 | 
					 | 
				
			||||||
		};
 | 
					 | 
				
			||||||
/* End PBXTargetDependency section */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Begin PBXVariantGroup section */
 | 
					 | 
				
			||||||
		33CC10F42044A3C60003C045 /* MainMenu.xib */ = {
 | 
					 | 
				
			||||||
			isa = PBXVariantGroup;
 | 
					 | 
				
			||||||
			children = (
 | 
					 | 
				
			||||||
				33CC10F52044A3C60003C045 /* Base */,
 | 
					 | 
				
			||||||
			);
 | 
					 | 
				
			||||||
			name = MainMenu.xib;
 | 
					 | 
				
			||||||
			path = Runner;
 | 
					 | 
				
			||||||
			sourceTree = "<group>";
 | 
					 | 
				
			||||||
		};
 | 
					 | 
				
			||||||
/* End PBXVariantGroup section */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Begin XCBuildConfiguration section */
 | 
					 | 
				
			||||||
		331C80DB294CF71000263BE5 /* Debug */ = {
 | 
					 | 
				
			||||||
			isa = XCBuildConfiguration;
 | 
					 | 
				
			||||||
			buildSettings = {
 | 
					 | 
				
			||||||
				BUNDLE_LOADER = "$(TEST_HOST)";
 | 
					 | 
				
			||||||
				CURRENT_PROJECT_VERSION = 1;
 | 
					 | 
				
			||||||
				GENERATE_INFOPLIST_FILE = YES;
 | 
					 | 
				
			||||||
				MARKETING_VERSION = 1.0;
 | 
					 | 
				
			||||||
				PRODUCT_BUNDLE_IDENTIFIER = com.example.f0ckapp.RunnerTests;
 | 
					 | 
				
			||||||
				PRODUCT_NAME = "$(TARGET_NAME)";
 | 
					 | 
				
			||||||
				SWIFT_VERSION = 5.0;
 | 
					 | 
				
			||||||
				TEST_HOST = "$(BUILT_PRODUCTS_DIR)/f0ckapp.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/f0ckapp";
 | 
					 | 
				
			||||||
			};
 | 
					 | 
				
			||||||
			name = Debug;
 | 
					 | 
				
			||||||
		};
 | 
					 | 
				
			||||||
		331C80DC294CF71000263BE5 /* Release */ = {
 | 
					 | 
				
			||||||
			isa = XCBuildConfiguration;
 | 
					 | 
				
			||||||
			buildSettings = {
 | 
					 | 
				
			||||||
				BUNDLE_LOADER = "$(TEST_HOST)";
 | 
					 | 
				
			||||||
				CURRENT_PROJECT_VERSION = 1;
 | 
					 | 
				
			||||||
				GENERATE_INFOPLIST_FILE = YES;
 | 
					 | 
				
			||||||
				MARKETING_VERSION = 1.0;
 | 
					 | 
				
			||||||
				PRODUCT_BUNDLE_IDENTIFIER = com.example.f0ckapp.RunnerTests;
 | 
					 | 
				
			||||||
				PRODUCT_NAME = "$(TARGET_NAME)";
 | 
					 | 
				
			||||||
				SWIFT_VERSION = 5.0;
 | 
					 | 
				
			||||||
				TEST_HOST = "$(BUILT_PRODUCTS_DIR)/f0ckapp.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/f0ckapp";
 | 
					 | 
				
			||||||
			};
 | 
					 | 
				
			||||||
			name = Release;
 | 
					 | 
				
			||||||
		};
 | 
					 | 
				
			||||||
		331C80DD294CF71000263BE5 /* Profile */ = {
 | 
					 | 
				
			||||||
			isa = XCBuildConfiguration;
 | 
					 | 
				
			||||||
			buildSettings = {
 | 
					 | 
				
			||||||
				BUNDLE_LOADER = "$(TEST_HOST)";
 | 
					 | 
				
			||||||
				CURRENT_PROJECT_VERSION = 1;
 | 
					 | 
				
			||||||
				GENERATE_INFOPLIST_FILE = YES;
 | 
					 | 
				
			||||||
				MARKETING_VERSION = 1.0;
 | 
					 | 
				
			||||||
				PRODUCT_BUNDLE_IDENTIFIER = com.example.f0ckapp.RunnerTests;
 | 
					 | 
				
			||||||
				PRODUCT_NAME = "$(TARGET_NAME)";
 | 
					 | 
				
			||||||
				SWIFT_VERSION = 5.0;
 | 
					 | 
				
			||||||
				TEST_HOST = "$(BUILT_PRODUCTS_DIR)/f0ckapp.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/f0ckapp";
 | 
					 | 
				
			||||||
			};
 | 
					 | 
				
			||||||
			name = Profile;
 | 
					 | 
				
			||||||
		};
 | 
					 | 
				
			||||||
		338D0CE9231458BD00FA5F75 /* Profile */ = {
 | 
					 | 
				
			||||||
			isa = XCBuildConfiguration;
 | 
					 | 
				
			||||||
			baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
 | 
					 | 
				
			||||||
			buildSettings = {
 | 
					 | 
				
			||||||
				ALWAYS_SEARCH_USER_PATHS = NO;
 | 
					 | 
				
			||||||
				ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
 | 
					 | 
				
			||||||
				CLANG_ANALYZER_NONNULL = YES;
 | 
					 | 
				
			||||||
				CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
 | 
					 | 
				
			||||||
				CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
 | 
					 | 
				
			||||||
				CLANG_CXX_LIBRARY = "libc++";
 | 
					 | 
				
			||||||
				CLANG_ENABLE_MODULES = YES;
 | 
					 | 
				
			||||||
				CLANG_ENABLE_OBJC_ARC = YES;
 | 
					 | 
				
			||||||
				CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
 | 
					 | 
				
			||||||
				CLANG_WARN_BOOL_CONVERSION = YES;
 | 
					 | 
				
			||||||
				CLANG_WARN_CONSTANT_CONVERSION = YES;
 | 
					 | 
				
			||||||
				CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
 | 
					 | 
				
			||||||
				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
 | 
					 | 
				
			||||||
				CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
 | 
					 | 
				
			||||||
				CLANG_WARN_EMPTY_BODY = YES;
 | 
					 | 
				
			||||||
				CLANG_WARN_ENUM_CONVERSION = YES;
 | 
					 | 
				
			||||||
				CLANG_WARN_INFINITE_RECURSION = YES;
 | 
					 | 
				
			||||||
				CLANG_WARN_INT_CONVERSION = YES;
 | 
					 | 
				
			||||||
				CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
 | 
					 | 
				
			||||||
				CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
 | 
					 | 
				
			||||||
				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
 | 
					 | 
				
			||||||
				CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
 | 
					 | 
				
			||||||
				CLANG_WARN_SUSPICIOUS_MOVE = YES;
 | 
					 | 
				
			||||||
				CODE_SIGN_IDENTITY = "-";
 | 
					 | 
				
			||||||
				COPY_PHASE_STRIP = NO;
 | 
					 | 
				
			||||||
				DEAD_CODE_STRIPPING = YES;
 | 
					 | 
				
			||||||
				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
 | 
					 | 
				
			||||||
				ENABLE_NS_ASSERTIONS = NO;
 | 
					 | 
				
			||||||
				ENABLE_STRICT_OBJC_MSGSEND = YES;
 | 
					 | 
				
			||||||
				ENABLE_USER_SCRIPT_SANDBOXING = NO;
 | 
					 | 
				
			||||||
				GCC_C_LANGUAGE_STANDARD = gnu11;
 | 
					 | 
				
			||||||
				GCC_NO_COMMON_BLOCKS = YES;
 | 
					 | 
				
			||||||
				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
 | 
					 | 
				
			||||||
				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
 | 
					 | 
				
			||||||
				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
 | 
					 | 
				
			||||||
				GCC_WARN_UNUSED_FUNCTION = YES;
 | 
					 | 
				
			||||||
				GCC_WARN_UNUSED_VARIABLE = YES;
 | 
					 | 
				
			||||||
				MACOSX_DEPLOYMENT_TARGET = 10.15;
 | 
					 | 
				
			||||||
				MTL_ENABLE_DEBUG_INFO = NO;
 | 
					 | 
				
			||||||
				SDKROOT = macosx;
 | 
					 | 
				
			||||||
				SWIFT_COMPILATION_MODE = wholemodule;
 | 
					 | 
				
			||||||
				SWIFT_OPTIMIZATION_LEVEL = "-O";
 | 
					 | 
				
			||||||
			};
 | 
					 | 
				
			||||||
			name = Profile;
 | 
					 | 
				
			||||||
		};
 | 
					 | 
				
			||||||
		338D0CEA231458BD00FA5F75 /* Profile */ = {
 | 
					 | 
				
			||||||
			isa = XCBuildConfiguration;
 | 
					 | 
				
			||||||
			baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */;
 | 
					 | 
				
			||||||
			buildSettings = {
 | 
					 | 
				
			||||||
				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
 | 
					 | 
				
			||||||
				CLANG_ENABLE_MODULES = YES;
 | 
					 | 
				
			||||||
				CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements;
 | 
					 | 
				
			||||||
				CODE_SIGN_STYLE = Automatic;
 | 
					 | 
				
			||||||
				COMBINE_HIDPI_IMAGES = YES;
 | 
					 | 
				
			||||||
				INFOPLIST_FILE = Runner/Info.plist;
 | 
					 | 
				
			||||||
				LD_RUNPATH_SEARCH_PATHS = (
 | 
					 | 
				
			||||||
					"$(inherited)",
 | 
					 | 
				
			||||||
					"@executable_path/../Frameworks",
 | 
					 | 
				
			||||||
				);
 | 
					 | 
				
			||||||
				PROVISIONING_PROFILE_SPECIFIER = "";
 | 
					 | 
				
			||||||
				SWIFT_VERSION = 5.0;
 | 
					 | 
				
			||||||
			};
 | 
					 | 
				
			||||||
			name = Profile;
 | 
					 | 
				
			||||||
		};
 | 
					 | 
				
			||||||
		338D0CEB231458BD00FA5F75 /* Profile */ = {
 | 
					 | 
				
			||||||
			isa = XCBuildConfiguration;
 | 
					 | 
				
			||||||
			buildSettings = {
 | 
					 | 
				
			||||||
				CODE_SIGN_STYLE = Manual;
 | 
					 | 
				
			||||||
				PRODUCT_NAME = "$(TARGET_NAME)";
 | 
					 | 
				
			||||||
			};
 | 
					 | 
				
			||||||
			name = Profile;
 | 
					 | 
				
			||||||
		};
 | 
					 | 
				
			||||||
		33CC10F92044A3C60003C045 /* Debug */ = {
 | 
					 | 
				
			||||||
			isa = XCBuildConfiguration;
 | 
					 | 
				
			||||||
			baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
 | 
					 | 
				
			||||||
			buildSettings = {
 | 
					 | 
				
			||||||
				ALWAYS_SEARCH_USER_PATHS = NO;
 | 
					 | 
				
			||||||
				ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
 | 
					 | 
				
			||||||
				CLANG_ANALYZER_NONNULL = YES;
 | 
					 | 
				
			||||||
				CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
 | 
					 | 
				
			||||||
				CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
 | 
					 | 
				
			||||||
				CLANG_CXX_LIBRARY = "libc++";
 | 
					 | 
				
			||||||
				CLANG_ENABLE_MODULES = YES;
 | 
					 | 
				
			||||||
				CLANG_ENABLE_OBJC_ARC = YES;
 | 
					 | 
				
			||||||
				CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
 | 
					 | 
				
			||||||
				CLANG_WARN_BOOL_CONVERSION = YES;
 | 
					 | 
				
			||||||
				CLANG_WARN_CONSTANT_CONVERSION = YES;
 | 
					 | 
				
			||||||
				CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
 | 
					 | 
				
			||||||
				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
 | 
					 | 
				
			||||||
				CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
 | 
					 | 
				
			||||||
				CLANG_WARN_EMPTY_BODY = YES;
 | 
					 | 
				
			||||||
				CLANG_WARN_ENUM_CONVERSION = YES;
 | 
					 | 
				
			||||||
				CLANG_WARN_INFINITE_RECURSION = YES;
 | 
					 | 
				
			||||||
				CLANG_WARN_INT_CONVERSION = YES;
 | 
					 | 
				
			||||||
				CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
 | 
					 | 
				
			||||||
				CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
 | 
					 | 
				
			||||||
				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
 | 
					 | 
				
			||||||
				CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
 | 
					 | 
				
			||||||
				CLANG_WARN_SUSPICIOUS_MOVE = YES;
 | 
					 | 
				
			||||||
				CODE_SIGN_IDENTITY = "-";
 | 
					 | 
				
			||||||
				COPY_PHASE_STRIP = NO;
 | 
					 | 
				
			||||||
				DEAD_CODE_STRIPPING = YES;
 | 
					 | 
				
			||||||
				DEBUG_INFORMATION_FORMAT = dwarf;
 | 
					 | 
				
			||||||
				ENABLE_STRICT_OBJC_MSGSEND = YES;
 | 
					 | 
				
			||||||
				ENABLE_TESTABILITY = YES;
 | 
					 | 
				
			||||||
				ENABLE_USER_SCRIPT_SANDBOXING = NO;
 | 
					 | 
				
			||||||
				GCC_C_LANGUAGE_STANDARD = gnu11;
 | 
					 | 
				
			||||||
				GCC_DYNAMIC_NO_PIC = NO;
 | 
					 | 
				
			||||||
				GCC_NO_COMMON_BLOCKS = YES;
 | 
					 | 
				
			||||||
				GCC_OPTIMIZATION_LEVEL = 0;
 | 
					 | 
				
			||||||
				GCC_PREPROCESSOR_DEFINITIONS = (
 | 
					 | 
				
			||||||
					"DEBUG=1",
 | 
					 | 
				
			||||||
					"$(inherited)",
 | 
					 | 
				
			||||||
				);
 | 
					 | 
				
			||||||
				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
 | 
					 | 
				
			||||||
				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
 | 
					 | 
				
			||||||
				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
 | 
					 | 
				
			||||||
				GCC_WARN_UNUSED_FUNCTION = YES;
 | 
					 | 
				
			||||||
				GCC_WARN_UNUSED_VARIABLE = YES;
 | 
					 | 
				
			||||||
				MACOSX_DEPLOYMENT_TARGET = 10.15;
 | 
					 | 
				
			||||||
				MTL_ENABLE_DEBUG_INFO = YES;
 | 
					 | 
				
			||||||
				ONLY_ACTIVE_ARCH = YES;
 | 
					 | 
				
			||||||
				SDKROOT = macosx;
 | 
					 | 
				
			||||||
				SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
 | 
					 | 
				
			||||||
				SWIFT_OPTIMIZATION_LEVEL = "-Onone";
 | 
					 | 
				
			||||||
			};
 | 
					 | 
				
			||||||
			name = Debug;
 | 
					 | 
				
			||||||
		};
 | 
					 | 
				
			||||||
		33CC10FA2044A3C60003C045 /* Release */ = {
 | 
					 | 
				
			||||||
			isa = XCBuildConfiguration;
 | 
					 | 
				
			||||||
			baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
 | 
					 | 
				
			||||||
			buildSettings = {
 | 
					 | 
				
			||||||
				ALWAYS_SEARCH_USER_PATHS = NO;
 | 
					 | 
				
			||||||
				ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
 | 
					 | 
				
			||||||
				CLANG_ANALYZER_NONNULL = YES;
 | 
					 | 
				
			||||||
				CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
 | 
					 | 
				
			||||||
				CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
 | 
					 | 
				
			||||||
				CLANG_CXX_LIBRARY = "libc++";
 | 
					 | 
				
			||||||
				CLANG_ENABLE_MODULES = YES;
 | 
					 | 
				
			||||||
				CLANG_ENABLE_OBJC_ARC = YES;
 | 
					 | 
				
			||||||
				CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
 | 
					 | 
				
			||||||
				CLANG_WARN_BOOL_CONVERSION = YES;
 | 
					 | 
				
			||||||
				CLANG_WARN_CONSTANT_CONVERSION = YES;
 | 
					 | 
				
			||||||
				CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
 | 
					 | 
				
			||||||
				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
 | 
					 | 
				
			||||||
				CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
 | 
					 | 
				
			||||||
				CLANG_WARN_EMPTY_BODY = YES;
 | 
					 | 
				
			||||||
				CLANG_WARN_ENUM_CONVERSION = YES;
 | 
					 | 
				
			||||||
				CLANG_WARN_INFINITE_RECURSION = YES;
 | 
					 | 
				
			||||||
				CLANG_WARN_INT_CONVERSION = YES;
 | 
					 | 
				
			||||||
				CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
 | 
					 | 
				
			||||||
				CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
 | 
					 | 
				
			||||||
				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
 | 
					 | 
				
			||||||
				CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
 | 
					 | 
				
			||||||
				CLANG_WARN_SUSPICIOUS_MOVE = YES;
 | 
					 | 
				
			||||||
				CODE_SIGN_IDENTITY = "-";
 | 
					 | 
				
			||||||
				COPY_PHASE_STRIP = NO;
 | 
					 | 
				
			||||||
				DEAD_CODE_STRIPPING = YES;
 | 
					 | 
				
			||||||
				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
 | 
					 | 
				
			||||||
				ENABLE_NS_ASSERTIONS = NO;
 | 
					 | 
				
			||||||
				ENABLE_STRICT_OBJC_MSGSEND = YES;
 | 
					 | 
				
			||||||
				ENABLE_USER_SCRIPT_SANDBOXING = NO;
 | 
					 | 
				
			||||||
				GCC_C_LANGUAGE_STANDARD = gnu11;
 | 
					 | 
				
			||||||
				GCC_NO_COMMON_BLOCKS = YES;
 | 
					 | 
				
			||||||
				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
 | 
					 | 
				
			||||||
				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
 | 
					 | 
				
			||||||
				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
 | 
					 | 
				
			||||||
				GCC_WARN_UNUSED_FUNCTION = YES;
 | 
					 | 
				
			||||||
				GCC_WARN_UNUSED_VARIABLE = YES;
 | 
					 | 
				
			||||||
				MACOSX_DEPLOYMENT_TARGET = 10.15;
 | 
					 | 
				
			||||||
				MTL_ENABLE_DEBUG_INFO = NO;
 | 
					 | 
				
			||||||
				SDKROOT = macosx;
 | 
					 | 
				
			||||||
				SWIFT_COMPILATION_MODE = wholemodule;
 | 
					 | 
				
			||||||
				SWIFT_OPTIMIZATION_LEVEL = "-O";
 | 
					 | 
				
			||||||
			};
 | 
					 | 
				
			||||||
			name = Release;
 | 
					 | 
				
			||||||
		};
 | 
					 | 
				
			||||||
		33CC10FC2044A3C60003C045 /* Debug */ = {
 | 
					 | 
				
			||||||
			isa = XCBuildConfiguration;
 | 
					 | 
				
			||||||
			baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */;
 | 
					 | 
				
			||||||
			buildSettings = {
 | 
					 | 
				
			||||||
				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
 | 
					 | 
				
			||||||
				CLANG_ENABLE_MODULES = YES;
 | 
					 | 
				
			||||||
				CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements;
 | 
					 | 
				
			||||||
				CODE_SIGN_STYLE = Automatic;
 | 
					 | 
				
			||||||
				COMBINE_HIDPI_IMAGES = YES;
 | 
					 | 
				
			||||||
				INFOPLIST_FILE = Runner/Info.plist;
 | 
					 | 
				
			||||||
				LD_RUNPATH_SEARCH_PATHS = (
 | 
					 | 
				
			||||||
					"$(inherited)",
 | 
					 | 
				
			||||||
					"@executable_path/../Frameworks",
 | 
					 | 
				
			||||||
				);
 | 
					 | 
				
			||||||
				PROVISIONING_PROFILE_SPECIFIER = "";
 | 
					 | 
				
			||||||
				SWIFT_OPTIMIZATION_LEVEL = "-Onone";
 | 
					 | 
				
			||||||
				SWIFT_VERSION = 5.0;
 | 
					 | 
				
			||||||
			};
 | 
					 | 
				
			||||||
			name = Debug;
 | 
					 | 
				
			||||||
		};
 | 
					 | 
				
			||||||
		33CC10FD2044A3C60003C045 /* Release */ = {
 | 
					 | 
				
			||||||
			isa = XCBuildConfiguration;
 | 
					 | 
				
			||||||
			baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */;
 | 
					 | 
				
			||||||
			buildSettings = {
 | 
					 | 
				
			||||||
				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
 | 
					 | 
				
			||||||
				CLANG_ENABLE_MODULES = YES;
 | 
					 | 
				
			||||||
				CODE_SIGN_ENTITLEMENTS = Runner/Release.entitlements;
 | 
					 | 
				
			||||||
				CODE_SIGN_STYLE = Automatic;
 | 
					 | 
				
			||||||
				COMBINE_HIDPI_IMAGES = YES;
 | 
					 | 
				
			||||||
				INFOPLIST_FILE = Runner/Info.plist;
 | 
					 | 
				
			||||||
				LD_RUNPATH_SEARCH_PATHS = (
 | 
					 | 
				
			||||||
					"$(inherited)",
 | 
					 | 
				
			||||||
					"@executable_path/../Frameworks",
 | 
					 | 
				
			||||||
				);
 | 
					 | 
				
			||||||
				PROVISIONING_PROFILE_SPECIFIER = "";
 | 
					 | 
				
			||||||
				SWIFT_VERSION = 5.0;
 | 
					 | 
				
			||||||
			};
 | 
					 | 
				
			||||||
			name = Release;
 | 
					 | 
				
			||||||
		};
 | 
					 | 
				
			||||||
		33CC111C2044C6BA0003C045 /* Debug */ = {
 | 
					 | 
				
			||||||
			isa = XCBuildConfiguration;
 | 
					 | 
				
			||||||
			buildSettings = {
 | 
					 | 
				
			||||||
				CODE_SIGN_STYLE = Manual;
 | 
					 | 
				
			||||||
				PRODUCT_NAME = "$(TARGET_NAME)";
 | 
					 | 
				
			||||||
			};
 | 
					 | 
				
			||||||
			name = Debug;
 | 
					 | 
				
			||||||
		};
 | 
					 | 
				
			||||||
		33CC111D2044C6BA0003C045 /* Release */ = {
 | 
					 | 
				
			||||||
			isa = XCBuildConfiguration;
 | 
					 | 
				
			||||||
			buildSettings = {
 | 
					 | 
				
			||||||
				CODE_SIGN_STYLE = Automatic;
 | 
					 | 
				
			||||||
				PRODUCT_NAME = "$(TARGET_NAME)";
 | 
					 | 
				
			||||||
			};
 | 
					 | 
				
			||||||
			name = Release;
 | 
					 | 
				
			||||||
		};
 | 
					 | 
				
			||||||
/* End XCBuildConfiguration section */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Begin XCConfigurationList section */
 | 
					 | 
				
			||||||
		331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = {
 | 
					 | 
				
			||||||
			isa = XCConfigurationList;
 | 
					 | 
				
			||||||
			buildConfigurations = (
 | 
					 | 
				
			||||||
				331C80DB294CF71000263BE5 /* Debug */,
 | 
					 | 
				
			||||||
				331C80DC294CF71000263BE5 /* Release */,
 | 
					 | 
				
			||||||
				331C80DD294CF71000263BE5 /* Profile */,
 | 
					 | 
				
			||||||
			);
 | 
					 | 
				
			||||||
			defaultConfigurationIsVisible = 0;
 | 
					 | 
				
			||||||
			defaultConfigurationName = Release;
 | 
					 | 
				
			||||||
		};
 | 
					 | 
				
			||||||
		33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */ = {
 | 
					 | 
				
			||||||
			isa = XCConfigurationList;
 | 
					 | 
				
			||||||
			buildConfigurations = (
 | 
					 | 
				
			||||||
				33CC10F92044A3C60003C045 /* Debug */,
 | 
					 | 
				
			||||||
				33CC10FA2044A3C60003C045 /* Release */,
 | 
					 | 
				
			||||||
				338D0CE9231458BD00FA5F75 /* Profile */,
 | 
					 | 
				
			||||||
			);
 | 
					 | 
				
			||||||
			defaultConfigurationIsVisible = 0;
 | 
					 | 
				
			||||||
			defaultConfigurationName = Release;
 | 
					 | 
				
			||||||
		};
 | 
					 | 
				
			||||||
		33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */ = {
 | 
					 | 
				
			||||||
			isa = XCConfigurationList;
 | 
					 | 
				
			||||||
			buildConfigurations = (
 | 
					 | 
				
			||||||
				33CC10FC2044A3C60003C045 /* Debug */,
 | 
					 | 
				
			||||||
				33CC10FD2044A3C60003C045 /* Release */,
 | 
					 | 
				
			||||||
				338D0CEA231458BD00FA5F75 /* Profile */,
 | 
					 | 
				
			||||||
			);
 | 
					 | 
				
			||||||
			defaultConfigurationIsVisible = 0;
 | 
					 | 
				
			||||||
			defaultConfigurationName = Release;
 | 
					 | 
				
			||||||
		};
 | 
					 | 
				
			||||||
		33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */ = {
 | 
					 | 
				
			||||||
			isa = XCConfigurationList;
 | 
					 | 
				
			||||||
			buildConfigurations = (
 | 
					 | 
				
			||||||
				33CC111C2044C6BA0003C045 /* Debug */,
 | 
					 | 
				
			||||||
				33CC111D2044C6BA0003C045 /* Release */,
 | 
					 | 
				
			||||||
				338D0CEB231458BD00FA5F75 /* Profile */,
 | 
					 | 
				
			||||||
			);
 | 
					 | 
				
			||||||
			defaultConfigurationIsVisible = 0;
 | 
					 | 
				
			||||||
			defaultConfigurationName = Release;
 | 
					 | 
				
			||||||
		};
 | 
					 | 
				
			||||||
/* End XCConfigurationList section */
 | 
					 | 
				
			||||||
	};
 | 
					 | 
				
			||||||
	rootObject = 33CC10E52044A3C60003C045 /* Project object */;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -1,8 +0,0 @@
 | 
				
			|||||||
<?xml version="1.0" encoding="UTF-8"?>
 | 
					 | 
				
			||||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
 | 
					 | 
				
			||||||
<plist version="1.0">
 | 
					 | 
				
			||||||
<dict>
 | 
					 | 
				
			||||||
	<key>IDEDidComputeMac32BitWarning</key>
 | 
					 | 
				
			||||||
	<true/>
 | 
					 | 
				
			||||||
</dict>
 | 
					 | 
				
			||||||
</plist>
 | 
					 | 
				
			||||||
@@ -1,99 +0,0 @@
 | 
				
			|||||||
<?xml version="1.0" encoding="UTF-8"?>
 | 
					 | 
				
			||||||
<Scheme
 | 
					 | 
				
			||||||
   LastUpgradeVersion = "1510"
 | 
					 | 
				
			||||||
   version = "1.3">
 | 
					 | 
				
			||||||
   <BuildAction
 | 
					 | 
				
			||||||
      parallelizeBuildables = "YES"
 | 
					 | 
				
			||||||
      buildImplicitDependencies = "YES">
 | 
					 | 
				
			||||||
      <BuildActionEntries>
 | 
					 | 
				
			||||||
         <BuildActionEntry
 | 
					 | 
				
			||||||
            buildForTesting = "YES"
 | 
					 | 
				
			||||||
            buildForRunning = "YES"
 | 
					 | 
				
			||||||
            buildForProfiling = "YES"
 | 
					 | 
				
			||||||
            buildForArchiving = "YES"
 | 
					 | 
				
			||||||
            buildForAnalyzing = "YES">
 | 
					 | 
				
			||||||
            <BuildableReference
 | 
					 | 
				
			||||||
               BuildableIdentifier = "primary"
 | 
					 | 
				
			||||||
               BlueprintIdentifier = "33CC10EC2044A3C60003C045"
 | 
					 | 
				
			||||||
               BuildableName = "f0ckapp.app"
 | 
					 | 
				
			||||||
               BlueprintName = "Runner"
 | 
					 | 
				
			||||||
               ReferencedContainer = "container:Runner.xcodeproj">
 | 
					 | 
				
			||||||
            </BuildableReference>
 | 
					 | 
				
			||||||
         </BuildActionEntry>
 | 
					 | 
				
			||||||
      </BuildActionEntries>
 | 
					 | 
				
			||||||
   </BuildAction>
 | 
					 | 
				
			||||||
   <TestAction
 | 
					 | 
				
			||||||
      buildConfiguration = "Debug"
 | 
					 | 
				
			||||||
      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
 | 
					 | 
				
			||||||
      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
 | 
					 | 
				
			||||||
      shouldUseLaunchSchemeArgsEnv = "YES">
 | 
					 | 
				
			||||||
      <MacroExpansion>
 | 
					 | 
				
			||||||
         <BuildableReference
 | 
					 | 
				
			||||||
            BuildableIdentifier = "primary"
 | 
					 | 
				
			||||||
            BlueprintIdentifier = "33CC10EC2044A3C60003C045"
 | 
					 | 
				
			||||||
            BuildableName = "f0ckapp.app"
 | 
					 | 
				
			||||||
            BlueprintName = "Runner"
 | 
					 | 
				
			||||||
            ReferencedContainer = "container:Runner.xcodeproj">
 | 
					 | 
				
			||||||
         </BuildableReference>
 | 
					 | 
				
			||||||
      </MacroExpansion>
 | 
					 | 
				
			||||||
      <Testables>
 | 
					 | 
				
			||||||
         <TestableReference
 | 
					 | 
				
			||||||
            skipped = "NO"
 | 
					 | 
				
			||||||
            parallelizable = "YES">
 | 
					 | 
				
			||||||
            <BuildableReference
 | 
					 | 
				
			||||||
               BuildableIdentifier = "primary"
 | 
					 | 
				
			||||||
               BlueprintIdentifier = "331C80D4294CF70F00263BE5"
 | 
					 | 
				
			||||||
               BuildableName = "RunnerTests.xctest"
 | 
					 | 
				
			||||||
               BlueprintName = "RunnerTests"
 | 
					 | 
				
			||||||
               ReferencedContainer = "container:Runner.xcodeproj">
 | 
					 | 
				
			||||||
            </BuildableReference>
 | 
					 | 
				
			||||||
         </TestableReference>
 | 
					 | 
				
			||||||
      </Testables>
 | 
					 | 
				
			||||||
   </TestAction>
 | 
					 | 
				
			||||||
   <LaunchAction
 | 
					 | 
				
			||||||
      buildConfiguration = "Debug"
 | 
					 | 
				
			||||||
      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
 | 
					 | 
				
			||||||
      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
 | 
					 | 
				
			||||||
      launchStyle = "0"
 | 
					 | 
				
			||||||
      useCustomWorkingDirectory = "NO"
 | 
					 | 
				
			||||||
      ignoresPersistentStateOnLaunch = "NO"
 | 
					 | 
				
			||||||
      debugDocumentVersioning = "YES"
 | 
					 | 
				
			||||||
      debugServiceExtension = "internal"
 | 
					 | 
				
			||||||
      enableGPUValidationMode = "1"
 | 
					 | 
				
			||||||
      allowLocationSimulation = "YES">
 | 
					 | 
				
			||||||
      <BuildableProductRunnable
 | 
					 | 
				
			||||||
         runnableDebuggingMode = "0">
 | 
					 | 
				
			||||||
         <BuildableReference
 | 
					 | 
				
			||||||
            BuildableIdentifier = "primary"
 | 
					 | 
				
			||||||
            BlueprintIdentifier = "33CC10EC2044A3C60003C045"
 | 
					 | 
				
			||||||
            BuildableName = "f0ckapp.app"
 | 
					 | 
				
			||||||
            BlueprintName = "Runner"
 | 
					 | 
				
			||||||
            ReferencedContainer = "container:Runner.xcodeproj">
 | 
					 | 
				
			||||||
         </BuildableReference>
 | 
					 | 
				
			||||||
      </BuildableProductRunnable>
 | 
					 | 
				
			||||||
   </LaunchAction>
 | 
					 | 
				
			||||||
   <ProfileAction
 | 
					 | 
				
			||||||
      buildConfiguration = "Profile"
 | 
					 | 
				
			||||||
      shouldUseLaunchSchemeArgsEnv = "YES"
 | 
					 | 
				
			||||||
      savedToolIdentifier = ""
 | 
					 | 
				
			||||||
      useCustomWorkingDirectory = "NO"
 | 
					 | 
				
			||||||
      debugDocumentVersioning = "YES">
 | 
					 | 
				
			||||||
      <BuildableProductRunnable
 | 
					 | 
				
			||||||
         runnableDebuggingMode = "0">
 | 
					 | 
				
			||||||
         <BuildableReference
 | 
					 | 
				
			||||||
            BuildableIdentifier = "primary"
 | 
					 | 
				
			||||||
            BlueprintIdentifier = "33CC10EC2044A3C60003C045"
 | 
					 | 
				
			||||||
            BuildableName = "f0ckapp.app"
 | 
					 | 
				
			||||||
            BlueprintName = "Runner"
 | 
					 | 
				
			||||||
            ReferencedContainer = "container:Runner.xcodeproj">
 | 
					 | 
				
			||||||
         </BuildableReference>
 | 
					 | 
				
			||||||
      </BuildableProductRunnable>
 | 
					 | 
				
			||||||
   </ProfileAction>
 | 
					 | 
				
			||||||
   <AnalyzeAction
 | 
					 | 
				
			||||||
      buildConfiguration = "Debug">
 | 
					 | 
				
			||||||
   </AnalyzeAction>
 | 
					 | 
				
			||||||
   <ArchiveAction
 | 
					 | 
				
			||||||
      buildConfiguration = "Release"
 | 
					 | 
				
			||||||
      revealArchiveInOrganizer = "YES">
 | 
					 | 
				
			||||||
   </ArchiveAction>
 | 
					 | 
				
			||||||
</Scheme>
 | 
					 | 
				
			||||||
@@ -1,7 +0,0 @@
 | 
				
			|||||||
<?xml version="1.0" encoding="UTF-8"?>
 | 
					 | 
				
			||||||
<Workspace
 | 
					 | 
				
			||||||
   version = "1.0">
 | 
					 | 
				
			||||||
   <FileRef
 | 
					 | 
				
			||||||
      location = "group:Runner.xcodeproj">
 | 
					 | 
				
			||||||
   </FileRef>
 | 
					 | 
				
			||||||
</Workspace>
 | 
					 | 
				
			||||||
@@ -1,8 +0,0 @@
 | 
				
			|||||||
<?xml version="1.0" encoding="UTF-8"?>
 | 
					 | 
				
			||||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
 | 
					 | 
				
			||||||
<plist version="1.0">
 | 
					 | 
				
			||||||
<dict>
 | 
					 | 
				
			||||||
	<key>IDEDidComputeMac32BitWarning</key>
 | 
					 | 
				
			||||||
	<true/>
 | 
					 | 
				
			||||||
</dict>
 | 
					 | 
				
			||||||
</plist>
 | 
					 | 
				
			||||||
@@ -1,13 +0,0 @@
 | 
				
			|||||||
import Cocoa
 | 
					 | 
				
			||||||
import FlutterMacOS
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
@main
 | 
					 | 
				
			||||||
class AppDelegate: FlutterAppDelegate {
 | 
					 | 
				
			||||||
  override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool {
 | 
					 | 
				
			||||||
    return true
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  override func applicationSupportsSecureRestorableState(_ app: NSApplication) -> Bool {
 | 
					 | 
				
			||||||
    return true
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -1,68 +0,0 @@
 | 
				
			|||||||
{
 | 
					 | 
				
			||||||
  "images" : [
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
      "size" : "16x16",
 | 
					 | 
				
			||||||
      "idiom" : "mac",
 | 
					 | 
				
			||||||
      "filename" : "app_icon_16.png",
 | 
					 | 
				
			||||||
      "scale" : "1x"
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
      "size" : "16x16",
 | 
					 | 
				
			||||||
      "idiom" : "mac",
 | 
					 | 
				
			||||||
      "filename" : "app_icon_32.png",
 | 
					 | 
				
			||||||
      "scale" : "2x"
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
      "size" : "32x32",
 | 
					 | 
				
			||||||
      "idiom" : "mac",
 | 
					 | 
				
			||||||
      "filename" : "app_icon_32.png",
 | 
					 | 
				
			||||||
      "scale" : "1x"
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
      "size" : "32x32",
 | 
					 | 
				
			||||||
      "idiom" : "mac",
 | 
					 | 
				
			||||||
      "filename" : "app_icon_64.png",
 | 
					 | 
				
			||||||
      "scale" : "2x"
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
      "size" : "128x128",
 | 
					 | 
				
			||||||
      "idiom" : "mac",
 | 
					 | 
				
			||||||
      "filename" : "app_icon_128.png",
 | 
					 | 
				
			||||||
      "scale" : "1x"
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
      "size" : "128x128",
 | 
					 | 
				
			||||||
      "idiom" : "mac",
 | 
					 | 
				
			||||||
      "filename" : "app_icon_256.png",
 | 
					 | 
				
			||||||
      "scale" : "2x"
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
      "size" : "256x256",
 | 
					 | 
				
			||||||
      "idiom" : "mac",
 | 
					 | 
				
			||||||
      "filename" : "app_icon_256.png",
 | 
					 | 
				
			||||||
      "scale" : "1x"
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
      "size" : "256x256",
 | 
					 | 
				
			||||||
      "idiom" : "mac",
 | 
					 | 
				
			||||||
      "filename" : "app_icon_512.png",
 | 
					 | 
				
			||||||
      "scale" : "2x"
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
      "size" : "512x512",
 | 
					 | 
				
			||||||
      "idiom" : "mac",
 | 
					 | 
				
			||||||
      "filename" : "app_icon_512.png",
 | 
					 | 
				
			||||||
      "scale" : "1x"
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
      "size" : "512x512",
 | 
					 | 
				
			||||||
      "idiom" : "mac",
 | 
					 | 
				
			||||||
      "filename" : "app_icon_1024.png",
 | 
					 | 
				
			||||||
      "scale" : "2x"
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  ],
 | 
					 | 
				
			||||||
  "info" : {
 | 
					 | 
				
			||||||
    "version" : 1,
 | 
					 | 
				
			||||||
    "author" : "xcode"
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
		 Before Width: | Height: | Size: 101 KiB  | 
| 
		 Before Width: | Height: | Size: 5.5 KiB  | 
| 
		 Before Width: | Height: | Size: 520 B  | 
| 
		 Before Width: | Height: | Size: 14 KiB  | 
| 
		 Before Width: | Height: | Size: 1.0 KiB  | 
| 
		 Before Width: | Height: | Size: 36 KiB  | 
| 
		 Before Width: | Height: | Size: 2.2 KiB  | 
@@ -1,343 +0,0 @@
 | 
				
			|||||||
<?xml version="1.0" encoding="UTF-8"?>
 | 
					 | 
				
			||||||
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="14490.70" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
 | 
					 | 
				
			||||||
    <dependencies>
 | 
					 | 
				
			||||||
        <deployment identifier="macosx"/>
 | 
					 | 
				
			||||||
        <plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="14490.70"/>
 | 
					 | 
				
			||||||
        <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
 | 
					 | 
				
			||||||
    </dependencies>
 | 
					 | 
				
			||||||
    <objects>
 | 
					 | 
				
			||||||
        <customObject id="-2" userLabel="File's Owner" customClass="NSApplication">
 | 
					 | 
				
			||||||
            <connections>
 | 
					 | 
				
			||||||
                <outlet property="delegate" destination="Voe-Tx-rLC" id="GzC-gU-4Uq"/>
 | 
					 | 
				
			||||||
            </connections>
 | 
					 | 
				
			||||||
        </customObject>
 | 
					 | 
				
			||||||
        <customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
 | 
					 | 
				
			||||||
        <customObject id="-3" userLabel="Application" customClass="NSObject"/>
 | 
					 | 
				
			||||||
        <customObject id="Voe-Tx-rLC" customClass="AppDelegate" customModule="Runner" customModuleProvider="target">
 | 
					 | 
				
			||||||
            <connections>
 | 
					 | 
				
			||||||
                <outlet property="applicationMenu" destination="uQy-DD-JDr" id="XBo-yE-nKs"/>
 | 
					 | 
				
			||||||
                <outlet property="mainFlutterWindow" destination="QvC-M9-y7g" id="gIp-Ho-8D9"/>
 | 
					 | 
				
			||||||
            </connections>
 | 
					 | 
				
			||||||
        </customObject>
 | 
					 | 
				
			||||||
        <customObject id="YLy-65-1bz" customClass="NSFontManager"/>
 | 
					 | 
				
			||||||
        <menu title="Main Menu" systemMenu="main" id="AYu-sK-qS6">
 | 
					 | 
				
			||||||
            <items>
 | 
					 | 
				
			||||||
                <menuItem title="APP_NAME" id="1Xt-HY-uBw">
 | 
					 | 
				
			||||||
                    <modifierMask key="keyEquivalentModifierMask"/>
 | 
					 | 
				
			||||||
                    <menu key="submenu" title="APP_NAME" systemMenu="apple" id="uQy-DD-JDr">
 | 
					 | 
				
			||||||
                        <items>
 | 
					 | 
				
			||||||
                            <menuItem title="About APP_NAME" id="5kV-Vb-QxS">
 | 
					 | 
				
			||||||
                                <modifierMask key="keyEquivalentModifierMask"/>
 | 
					 | 
				
			||||||
                                <connections>
 | 
					 | 
				
			||||||
                                    <action selector="orderFrontStandardAboutPanel:" target="-1" id="Exp-CZ-Vem"/>
 | 
					 | 
				
			||||||
                                </connections>
 | 
					 | 
				
			||||||
                            </menuItem>
 | 
					 | 
				
			||||||
                            <menuItem isSeparatorItem="YES" id="VOq-y0-SEH"/>
 | 
					 | 
				
			||||||
                            <menuItem title="Preferences…" keyEquivalent="," id="BOF-NM-1cW"/>
 | 
					 | 
				
			||||||
                            <menuItem isSeparatorItem="YES" id="wFC-TO-SCJ"/>
 | 
					 | 
				
			||||||
                            <menuItem title="Services" id="NMo-om-nkz">
 | 
					 | 
				
			||||||
                                <modifierMask key="keyEquivalentModifierMask"/>
 | 
					 | 
				
			||||||
                                <menu key="submenu" title="Services" systemMenu="services" id="hz9-B4-Xy5"/>
 | 
					 | 
				
			||||||
                            </menuItem>
 | 
					 | 
				
			||||||
                            <menuItem isSeparatorItem="YES" id="4je-JR-u6R"/>
 | 
					 | 
				
			||||||
                            <menuItem title="Hide APP_NAME" keyEquivalent="h" id="Olw-nP-bQN">
 | 
					 | 
				
			||||||
                                <connections>
 | 
					 | 
				
			||||||
                                    <action selector="hide:" target="-1" id="PnN-Uc-m68"/>
 | 
					 | 
				
			||||||
                                </connections>
 | 
					 | 
				
			||||||
                            </menuItem>
 | 
					 | 
				
			||||||
                            <menuItem title="Hide Others" keyEquivalent="h" id="Vdr-fp-XzO">
 | 
					 | 
				
			||||||
                                <modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
 | 
					 | 
				
			||||||
                                <connections>
 | 
					 | 
				
			||||||
                                    <action selector="hideOtherApplications:" target="-1" id="VT4-aY-XCT"/>
 | 
					 | 
				
			||||||
                                </connections>
 | 
					 | 
				
			||||||
                            </menuItem>
 | 
					 | 
				
			||||||
                            <menuItem title="Show All" id="Kd2-mp-pUS">
 | 
					 | 
				
			||||||
                                <modifierMask key="keyEquivalentModifierMask"/>
 | 
					 | 
				
			||||||
                                <connections>
 | 
					 | 
				
			||||||
                                    <action selector="unhideAllApplications:" target="-1" id="Dhg-Le-xox"/>
 | 
					 | 
				
			||||||
                                </connections>
 | 
					 | 
				
			||||||
                            </menuItem>
 | 
					 | 
				
			||||||
                            <menuItem isSeparatorItem="YES" id="kCx-OE-vgT"/>
 | 
					 | 
				
			||||||
                            <menuItem title="Quit APP_NAME" keyEquivalent="q" id="4sb-4s-VLi">
 | 
					 | 
				
			||||||
                                <connections>
 | 
					 | 
				
			||||||
                                    <action selector="terminate:" target="-1" id="Te7-pn-YzF"/>
 | 
					 | 
				
			||||||
                                </connections>
 | 
					 | 
				
			||||||
                            </menuItem>
 | 
					 | 
				
			||||||
                        </items>
 | 
					 | 
				
			||||||
                    </menu>
 | 
					 | 
				
			||||||
                </menuItem>
 | 
					 | 
				
			||||||
                <menuItem title="Edit" id="5QF-Oa-p0T">
 | 
					 | 
				
			||||||
                    <modifierMask key="keyEquivalentModifierMask"/>
 | 
					 | 
				
			||||||
                    <menu key="submenu" title="Edit" id="W48-6f-4Dl">
 | 
					 | 
				
			||||||
                        <items>
 | 
					 | 
				
			||||||
                            <menuItem title="Undo" keyEquivalent="z" id="dRJ-4n-Yzg">
 | 
					 | 
				
			||||||
                                <connections>
 | 
					 | 
				
			||||||
                                    <action selector="undo:" target="-1" id="M6e-cu-g7V"/>
 | 
					 | 
				
			||||||
                                </connections>
 | 
					 | 
				
			||||||
                            </menuItem>
 | 
					 | 
				
			||||||
                            <menuItem title="Redo" keyEquivalent="Z" id="6dh-zS-Vam">
 | 
					 | 
				
			||||||
                                <connections>
 | 
					 | 
				
			||||||
                                    <action selector="redo:" target="-1" id="oIA-Rs-6OD"/>
 | 
					 | 
				
			||||||
                                </connections>
 | 
					 | 
				
			||||||
                            </menuItem>
 | 
					 | 
				
			||||||
                            <menuItem isSeparatorItem="YES" id="WRV-NI-Exz"/>
 | 
					 | 
				
			||||||
                            <menuItem title="Cut" keyEquivalent="x" id="uRl-iY-unG">
 | 
					 | 
				
			||||||
                                <connections>
 | 
					 | 
				
			||||||
                                    <action selector="cut:" target="-1" id="YJe-68-I9s"/>
 | 
					 | 
				
			||||||
                                </connections>
 | 
					 | 
				
			||||||
                            </menuItem>
 | 
					 | 
				
			||||||
                            <menuItem title="Copy" keyEquivalent="c" id="x3v-GG-iWU">
 | 
					 | 
				
			||||||
                                <connections>
 | 
					 | 
				
			||||||
                                    <action selector="copy:" target="-1" id="G1f-GL-Joy"/>
 | 
					 | 
				
			||||||
                                </connections>
 | 
					 | 
				
			||||||
                            </menuItem>
 | 
					 | 
				
			||||||
                            <menuItem title="Paste" keyEquivalent="v" id="gVA-U4-sdL">
 | 
					 | 
				
			||||||
                                <connections>
 | 
					 | 
				
			||||||
                                    <action selector="paste:" target="-1" id="UvS-8e-Qdg"/>
 | 
					 | 
				
			||||||
                                </connections>
 | 
					 | 
				
			||||||
                            </menuItem>
 | 
					 | 
				
			||||||
                            <menuItem title="Paste and Match Style" keyEquivalent="V" id="WeT-3V-zwk">
 | 
					 | 
				
			||||||
                                <modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
 | 
					 | 
				
			||||||
                                <connections>
 | 
					 | 
				
			||||||
                                    <action selector="pasteAsPlainText:" target="-1" id="cEh-KX-wJQ"/>
 | 
					 | 
				
			||||||
                                </connections>
 | 
					 | 
				
			||||||
                            </menuItem>
 | 
					 | 
				
			||||||
                            <menuItem title="Delete" id="pa3-QI-u2k">
 | 
					 | 
				
			||||||
                                <modifierMask key="keyEquivalentModifierMask"/>
 | 
					 | 
				
			||||||
                                <connections>
 | 
					 | 
				
			||||||
                                    <action selector="delete:" target="-1" id="0Mk-Ml-PaM"/>
 | 
					 | 
				
			||||||
                                </connections>
 | 
					 | 
				
			||||||
                            </menuItem>
 | 
					 | 
				
			||||||
                            <menuItem title="Select All" keyEquivalent="a" id="Ruw-6m-B2m">
 | 
					 | 
				
			||||||
                                <connections>
 | 
					 | 
				
			||||||
                                    <action selector="selectAll:" target="-1" id="VNm-Mi-diN"/>
 | 
					 | 
				
			||||||
                                </connections>
 | 
					 | 
				
			||||||
                            </menuItem>
 | 
					 | 
				
			||||||
                            <menuItem isSeparatorItem="YES" id="uyl-h8-XO2"/>
 | 
					 | 
				
			||||||
                            <menuItem title="Find" id="4EN-yA-p0u">
 | 
					 | 
				
			||||||
                                <modifierMask key="keyEquivalentModifierMask"/>
 | 
					 | 
				
			||||||
                                <menu key="submenu" title="Find" id="1b7-l0-nxx">
 | 
					 | 
				
			||||||
                                    <items>
 | 
					 | 
				
			||||||
                                        <menuItem title="Find…" tag="1" keyEquivalent="f" id="Xz5-n4-O0W">
 | 
					 | 
				
			||||||
                                            <connections>
 | 
					 | 
				
			||||||
                                                <action selector="performFindPanelAction:" target="-1" id="cD7-Qs-BN4"/>
 | 
					 | 
				
			||||||
                                            </connections>
 | 
					 | 
				
			||||||
                                        </menuItem>
 | 
					 | 
				
			||||||
                                        <menuItem title="Find and Replace…" tag="12" keyEquivalent="f" id="YEy-JH-Tfz">
 | 
					 | 
				
			||||||
                                            <modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
 | 
					 | 
				
			||||||
                                            <connections>
 | 
					 | 
				
			||||||
                                                <action selector="performFindPanelAction:" target="-1" id="WD3-Gg-5AJ"/>
 | 
					 | 
				
			||||||
                                            </connections>
 | 
					 | 
				
			||||||
                                        </menuItem>
 | 
					 | 
				
			||||||
                                        <menuItem title="Find Next" tag="2" keyEquivalent="g" id="q09-fT-Sye">
 | 
					 | 
				
			||||||
                                            <connections>
 | 
					 | 
				
			||||||
                                                <action selector="performFindPanelAction:" target="-1" id="NDo-RZ-v9R"/>
 | 
					 | 
				
			||||||
                                            </connections>
 | 
					 | 
				
			||||||
                                        </menuItem>
 | 
					 | 
				
			||||||
                                        <menuItem title="Find Previous" tag="3" keyEquivalent="G" id="OwM-mh-QMV">
 | 
					 | 
				
			||||||
                                            <connections>
 | 
					 | 
				
			||||||
                                                <action selector="performFindPanelAction:" target="-1" id="HOh-sY-3ay"/>
 | 
					 | 
				
			||||||
                                            </connections>
 | 
					 | 
				
			||||||
                                        </menuItem>
 | 
					 | 
				
			||||||
                                        <menuItem title="Use Selection for Find" tag="7" keyEquivalent="e" id="buJ-ug-pKt">
 | 
					 | 
				
			||||||
                                            <connections>
 | 
					 | 
				
			||||||
                                                <action selector="performFindPanelAction:" target="-1" id="U76-nv-p5D"/>
 | 
					 | 
				
			||||||
                                            </connections>
 | 
					 | 
				
			||||||
                                        </menuItem>
 | 
					 | 
				
			||||||
                                        <menuItem title="Jump to Selection" keyEquivalent="j" id="S0p-oC-mLd">
 | 
					 | 
				
			||||||
                                            <connections>
 | 
					 | 
				
			||||||
                                                <action selector="centerSelectionInVisibleArea:" target="-1" id="IOG-6D-g5B"/>
 | 
					 | 
				
			||||||
                                            </connections>
 | 
					 | 
				
			||||||
                                        </menuItem>
 | 
					 | 
				
			||||||
                                    </items>
 | 
					 | 
				
			||||||
                                </menu>
 | 
					 | 
				
			||||||
                            </menuItem>
 | 
					 | 
				
			||||||
                            <menuItem title="Spelling and Grammar" id="Dv1-io-Yv7">
 | 
					 | 
				
			||||||
                                <modifierMask key="keyEquivalentModifierMask"/>
 | 
					 | 
				
			||||||
                                <menu key="submenu" title="Spelling" id="3IN-sU-3Bg">
 | 
					 | 
				
			||||||
                                    <items>
 | 
					 | 
				
			||||||
                                        <menuItem title="Show Spelling and Grammar" keyEquivalent=":" id="HFo-cy-zxI">
 | 
					 | 
				
			||||||
                                            <connections>
 | 
					 | 
				
			||||||
                                                <action selector="showGuessPanel:" target="-1" id="vFj-Ks-hy3"/>
 | 
					 | 
				
			||||||
                                            </connections>
 | 
					 | 
				
			||||||
                                        </menuItem>
 | 
					 | 
				
			||||||
                                        <menuItem title="Check Document Now" keyEquivalent=";" id="hz2-CU-CR7">
 | 
					 | 
				
			||||||
                                            <connections>
 | 
					 | 
				
			||||||
                                                <action selector="checkSpelling:" target="-1" id="fz7-VC-reM"/>
 | 
					 | 
				
			||||||
                                            </connections>
 | 
					 | 
				
			||||||
                                        </menuItem>
 | 
					 | 
				
			||||||
                                        <menuItem isSeparatorItem="YES" id="bNw-od-mp5"/>
 | 
					 | 
				
			||||||
                                        <menuItem title="Check Spelling While Typing" id="rbD-Rh-wIN">
 | 
					 | 
				
			||||||
                                            <modifierMask key="keyEquivalentModifierMask"/>
 | 
					 | 
				
			||||||
                                            <connections>
 | 
					 | 
				
			||||||
                                                <action selector="toggleContinuousSpellChecking:" target="-1" id="7w6-Qz-0kB"/>
 | 
					 | 
				
			||||||
                                            </connections>
 | 
					 | 
				
			||||||
                                        </menuItem>
 | 
					 | 
				
			||||||
                                        <menuItem title="Check Grammar With Spelling" id="mK6-2p-4JG">
 | 
					 | 
				
			||||||
                                            <modifierMask key="keyEquivalentModifierMask"/>
 | 
					 | 
				
			||||||
                                            <connections>
 | 
					 | 
				
			||||||
                                                <action selector="toggleGrammarChecking:" target="-1" id="muD-Qn-j4w"/>
 | 
					 | 
				
			||||||
                                            </connections>
 | 
					 | 
				
			||||||
                                        </menuItem>
 | 
					 | 
				
			||||||
                                        <menuItem title="Correct Spelling Automatically" id="78Y-hA-62v">
 | 
					 | 
				
			||||||
                                            <modifierMask key="keyEquivalentModifierMask"/>
 | 
					 | 
				
			||||||
                                            <connections>
 | 
					 | 
				
			||||||
                                                <action selector="toggleAutomaticSpellingCorrection:" target="-1" id="2lM-Qi-WAP"/>
 | 
					 | 
				
			||||||
                                            </connections>
 | 
					 | 
				
			||||||
                                        </menuItem>
 | 
					 | 
				
			||||||
                                    </items>
 | 
					 | 
				
			||||||
                                </menu>
 | 
					 | 
				
			||||||
                            </menuItem>
 | 
					 | 
				
			||||||
                            <menuItem title="Substitutions" id="9ic-FL-obx">
 | 
					 | 
				
			||||||
                                <modifierMask key="keyEquivalentModifierMask"/>
 | 
					 | 
				
			||||||
                                <menu key="submenu" title="Substitutions" id="FeM-D8-WVr">
 | 
					 | 
				
			||||||
                                    <items>
 | 
					 | 
				
			||||||
                                        <menuItem title="Show Substitutions" id="z6F-FW-3nz">
 | 
					 | 
				
			||||||
                                            <modifierMask key="keyEquivalentModifierMask"/>
 | 
					 | 
				
			||||||
                                            <connections>
 | 
					 | 
				
			||||||
                                                <action selector="orderFrontSubstitutionsPanel:" target="-1" id="oku-mr-iSq"/>
 | 
					 | 
				
			||||||
                                            </connections>
 | 
					 | 
				
			||||||
                                        </menuItem>
 | 
					 | 
				
			||||||
                                        <menuItem isSeparatorItem="YES" id="gPx-C9-uUO"/>
 | 
					 | 
				
			||||||
                                        <menuItem title="Smart Copy/Paste" id="9yt-4B-nSM">
 | 
					 | 
				
			||||||
                                            <modifierMask key="keyEquivalentModifierMask"/>
 | 
					 | 
				
			||||||
                                            <connections>
 | 
					 | 
				
			||||||
                                                <action selector="toggleSmartInsertDelete:" target="-1" id="3IJ-Se-DZD"/>
 | 
					 | 
				
			||||||
                                            </connections>
 | 
					 | 
				
			||||||
                                        </menuItem>
 | 
					 | 
				
			||||||
                                        <menuItem title="Smart Quotes" id="hQb-2v-fYv">
 | 
					 | 
				
			||||||
                                            <modifierMask key="keyEquivalentModifierMask"/>
 | 
					 | 
				
			||||||
                                            <connections>
 | 
					 | 
				
			||||||
                                                <action selector="toggleAutomaticQuoteSubstitution:" target="-1" id="ptq-xd-QOA"/>
 | 
					 | 
				
			||||||
                                            </connections>
 | 
					 | 
				
			||||||
                                        </menuItem>
 | 
					 | 
				
			||||||
                                        <menuItem title="Smart Dashes" id="rgM-f4-ycn">
 | 
					 | 
				
			||||||
                                            <modifierMask key="keyEquivalentModifierMask"/>
 | 
					 | 
				
			||||||
                                            <connections>
 | 
					 | 
				
			||||||
                                                <action selector="toggleAutomaticDashSubstitution:" target="-1" id="oCt-pO-9gS"/>
 | 
					 | 
				
			||||||
                                            </connections>
 | 
					 | 
				
			||||||
                                        </menuItem>
 | 
					 | 
				
			||||||
                                        <menuItem title="Smart Links" id="cwL-P1-jid">
 | 
					 | 
				
			||||||
                                            <modifierMask key="keyEquivalentModifierMask"/>
 | 
					 | 
				
			||||||
                                            <connections>
 | 
					 | 
				
			||||||
                                                <action selector="toggleAutomaticLinkDetection:" target="-1" id="Gip-E3-Fov"/>
 | 
					 | 
				
			||||||
                                            </connections>
 | 
					 | 
				
			||||||
                                        </menuItem>
 | 
					 | 
				
			||||||
                                        <menuItem title="Data Detectors" id="tRr-pd-1PS">
 | 
					 | 
				
			||||||
                                            <modifierMask key="keyEquivalentModifierMask"/>
 | 
					 | 
				
			||||||
                                            <connections>
 | 
					 | 
				
			||||||
                                                <action selector="toggleAutomaticDataDetection:" target="-1" id="R1I-Nq-Kbl"/>
 | 
					 | 
				
			||||||
                                            </connections>
 | 
					 | 
				
			||||||
                                        </menuItem>
 | 
					 | 
				
			||||||
                                        <menuItem title="Text Replacement" id="HFQ-gK-NFA">
 | 
					 | 
				
			||||||
                                            <modifierMask key="keyEquivalentModifierMask"/>
 | 
					 | 
				
			||||||
                                            <connections>
 | 
					 | 
				
			||||||
                                                <action selector="toggleAutomaticTextReplacement:" target="-1" id="DvP-Fe-Py6"/>
 | 
					 | 
				
			||||||
                                            </connections>
 | 
					 | 
				
			||||||
                                        </menuItem>
 | 
					 | 
				
			||||||
                                    </items>
 | 
					 | 
				
			||||||
                                </menu>
 | 
					 | 
				
			||||||
                            </menuItem>
 | 
					 | 
				
			||||||
                            <menuItem title="Transformations" id="2oI-Rn-ZJC">
 | 
					 | 
				
			||||||
                                <modifierMask key="keyEquivalentModifierMask"/>
 | 
					 | 
				
			||||||
                                <menu key="submenu" title="Transformations" id="c8a-y6-VQd">
 | 
					 | 
				
			||||||
                                    <items>
 | 
					 | 
				
			||||||
                                        <menuItem title="Make Upper Case" id="vmV-6d-7jI">
 | 
					 | 
				
			||||||
                                            <modifierMask key="keyEquivalentModifierMask"/>
 | 
					 | 
				
			||||||
                                            <connections>
 | 
					 | 
				
			||||||
                                                <action selector="uppercaseWord:" target="-1" id="sPh-Tk-edu"/>
 | 
					 | 
				
			||||||
                                            </connections>
 | 
					 | 
				
			||||||
                                        </menuItem>
 | 
					 | 
				
			||||||
                                        <menuItem title="Make Lower Case" id="d9M-CD-aMd">
 | 
					 | 
				
			||||||
                                            <modifierMask key="keyEquivalentModifierMask"/>
 | 
					 | 
				
			||||||
                                            <connections>
 | 
					 | 
				
			||||||
                                                <action selector="lowercaseWord:" target="-1" id="iUZ-b5-hil"/>
 | 
					 | 
				
			||||||
                                            </connections>
 | 
					 | 
				
			||||||
                                        </menuItem>
 | 
					 | 
				
			||||||
                                        <menuItem title="Capitalize" id="UEZ-Bs-lqG">
 | 
					 | 
				
			||||||
                                            <modifierMask key="keyEquivalentModifierMask"/>
 | 
					 | 
				
			||||||
                                            <connections>
 | 
					 | 
				
			||||||
                                                <action selector="capitalizeWord:" target="-1" id="26H-TL-nsh"/>
 | 
					 | 
				
			||||||
                                            </connections>
 | 
					 | 
				
			||||||
                                        </menuItem>
 | 
					 | 
				
			||||||
                                    </items>
 | 
					 | 
				
			||||||
                                </menu>
 | 
					 | 
				
			||||||
                            </menuItem>
 | 
					 | 
				
			||||||
                            <menuItem title="Speech" id="xrE-MZ-jX0">
 | 
					 | 
				
			||||||
                                <modifierMask key="keyEquivalentModifierMask"/>
 | 
					 | 
				
			||||||
                                <menu key="submenu" title="Speech" id="3rS-ZA-NoH">
 | 
					 | 
				
			||||||
                                    <items>
 | 
					 | 
				
			||||||
                                        <menuItem title="Start Speaking" id="Ynk-f8-cLZ">
 | 
					 | 
				
			||||||
                                            <modifierMask key="keyEquivalentModifierMask"/>
 | 
					 | 
				
			||||||
                                            <connections>
 | 
					 | 
				
			||||||
                                                <action selector="startSpeaking:" target="-1" id="654-Ng-kyl"/>
 | 
					 | 
				
			||||||
                                            </connections>
 | 
					 | 
				
			||||||
                                        </menuItem>
 | 
					 | 
				
			||||||
                                        <menuItem title="Stop Speaking" id="Oyz-dy-DGm">
 | 
					 | 
				
			||||||
                                            <modifierMask key="keyEquivalentModifierMask"/>
 | 
					 | 
				
			||||||
                                            <connections>
 | 
					 | 
				
			||||||
                                                <action selector="stopSpeaking:" target="-1" id="dX8-6p-jy9"/>
 | 
					 | 
				
			||||||
                                            </connections>
 | 
					 | 
				
			||||||
                                        </menuItem>
 | 
					 | 
				
			||||||
                                    </items>
 | 
					 | 
				
			||||||
                                </menu>
 | 
					 | 
				
			||||||
                            </menuItem>
 | 
					 | 
				
			||||||
                        </items>
 | 
					 | 
				
			||||||
                    </menu>
 | 
					 | 
				
			||||||
                </menuItem>
 | 
					 | 
				
			||||||
                <menuItem title="View" id="H8h-7b-M4v">
 | 
					 | 
				
			||||||
                    <modifierMask key="keyEquivalentModifierMask"/>
 | 
					 | 
				
			||||||
                    <menu key="submenu" title="View" id="HyV-fh-RgO">
 | 
					 | 
				
			||||||
                        <items>
 | 
					 | 
				
			||||||
                            <menuItem title="Enter Full Screen" keyEquivalent="f" id="4J7-dP-txa">
 | 
					 | 
				
			||||||
                                <modifierMask key="keyEquivalentModifierMask" control="YES" command="YES"/>
 | 
					 | 
				
			||||||
                                <connections>
 | 
					 | 
				
			||||||
                                    <action selector="toggleFullScreen:" target="-1" id="dU3-MA-1Rq"/>
 | 
					 | 
				
			||||||
                                </connections>
 | 
					 | 
				
			||||||
                            </menuItem>
 | 
					 | 
				
			||||||
                        </items>
 | 
					 | 
				
			||||||
                    </menu>
 | 
					 | 
				
			||||||
                </menuItem>
 | 
					 | 
				
			||||||
                <menuItem title="Window" id="aUF-d1-5bR">
 | 
					 | 
				
			||||||
                    <modifierMask key="keyEquivalentModifierMask"/>
 | 
					 | 
				
			||||||
                    <menu key="submenu" title="Window" systemMenu="window" id="Td7-aD-5lo">
 | 
					 | 
				
			||||||
                        <items>
 | 
					 | 
				
			||||||
                            <menuItem title="Minimize" keyEquivalent="m" id="OY7-WF-poV">
 | 
					 | 
				
			||||||
                                <connections>
 | 
					 | 
				
			||||||
                                    <action selector="performMiniaturize:" target="-1" id="VwT-WD-YPe"/>
 | 
					 | 
				
			||||||
                                </connections>
 | 
					 | 
				
			||||||
                            </menuItem>
 | 
					 | 
				
			||||||
                            <menuItem title="Zoom" id="R4o-n2-Eq4">
 | 
					 | 
				
			||||||
                                <modifierMask key="keyEquivalentModifierMask"/>
 | 
					 | 
				
			||||||
                                <connections>
 | 
					 | 
				
			||||||
                                    <action selector="performZoom:" target="-1" id="DIl-cC-cCs"/>
 | 
					 | 
				
			||||||
                                </connections>
 | 
					 | 
				
			||||||
                            </menuItem>
 | 
					 | 
				
			||||||
                            <menuItem isSeparatorItem="YES" id="eu3-7i-yIM"/>
 | 
					 | 
				
			||||||
                            <menuItem title="Bring All to Front" id="LE2-aR-0XJ">
 | 
					 | 
				
			||||||
                                <modifierMask key="keyEquivalentModifierMask"/>
 | 
					 | 
				
			||||||
                                <connections>
 | 
					 | 
				
			||||||
                                    <action selector="arrangeInFront:" target="-1" id="DRN-fu-gQh"/>
 | 
					 | 
				
			||||||
                                </connections>
 | 
					 | 
				
			||||||
                            </menuItem>
 | 
					 | 
				
			||||||
                        </items>
 | 
					 | 
				
			||||||
                    </menu>
 | 
					 | 
				
			||||||
                </menuItem>
 | 
					 | 
				
			||||||
                <menuItem title="Help" id="EPT-qC-fAb">
 | 
					 | 
				
			||||||
                    <modifierMask key="keyEquivalentModifierMask"/>
 | 
					 | 
				
			||||||
                    <menu key="submenu" title="Help" systemMenu="help" id="rJ0-wn-3NY"/>
 | 
					 | 
				
			||||||
                </menuItem>
 | 
					 | 
				
			||||||
            </items>
 | 
					 | 
				
			||||||
            <point key="canvasLocation" x="142" y="-258"/>
 | 
					 | 
				
			||||||
        </menu>
 | 
					 | 
				
			||||||
        <window title="APP_NAME" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" animationBehavior="default" id="QvC-M9-y7g" customClass="MainFlutterWindow" customModule="Runner" customModuleProvider="target">
 | 
					 | 
				
			||||||
            <windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" resizable="YES"/>
 | 
					 | 
				
			||||||
            <rect key="contentRect" x="335" y="390" width="800" height="600"/>
 | 
					 | 
				
			||||||
            <rect key="screenRect" x="0.0" y="0.0" width="2560" height="1577"/>
 | 
					 | 
				
			||||||
            <view key="contentView" wantsLayer="YES" id="EiT-Mj-1SZ">
 | 
					 | 
				
			||||||
                <rect key="frame" x="0.0" y="0.0" width="800" height="600"/>
 | 
					 | 
				
			||||||
                <autoresizingMask key="autoresizingMask"/>
 | 
					 | 
				
			||||||
            </view>
 | 
					 | 
				
			||||||
        </window>
 | 
					 | 
				
			||||||
    </objects>
 | 
					 | 
				
			||||||
</document>
 | 
					 | 
				
			||||||
@@ -1,14 +0,0 @@
 | 
				
			|||||||
// Application-level settings for the Runner target.
 | 
					 | 
				
			||||||
//
 | 
					 | 
				
			||||||
// This may be replaced with something auto-generated from metadata (e.g., pubspec.yaml) in the
 | 
					 | 
				
			||||||
// future. If not, the values below would default to using the project name when this becomes a
 | 
					 | 
				
			||||||
// 'flutter create' template.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// The application's name. By default this is also the title of the Flutter window.
 | 
					 | 
				
			||||||
PRODUCT_NAME = f0ckapp
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// The application's bundle identifier
 | 
					 | 
				
			||||||
PRODUCT_BUNDLE_IDENTIFIER = com.example.f0ckapp
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// The copyright displayed in application information
 | 
					 | 
				
			||||||
PRODUCT_COPYRIGHT = Copyright © 2025 com.example. All rights reserved.
 | 
					 | 
				
			||||||
@@ -1,2 +0,0 @@
 | 
				
			|||||||
#include "../../Flutter/Flutter-Debug.xcconfig"
 | 
					 | 
				
			||||||
#include "Warnings.xcconfig"
 | 
					 | 
				
			||||||
@@ -1,2 +0,0 @@
 | 
				
			|||||||
#include "../../Flutter/Flutter-Release.xcconfig"
 | 
					 | 
				
			||||||
#include "Warnings.xcconfig"
 | 
					 | 
				
			||||||
@@ -1,13 +0,0 @@
 | 
				
			|||||||
WARNING_CFLAGS = -Wall -Wconditional-uninitialized -Wnullable-to-nonnull-conversion -Wmissing-method-return-type -Woverlength-strings
 | 
					 | 
				
			||||||
GCC_WARN_UNDECLARED_SELECTOR = YES
 | 
					 | 
				
			||||||
CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES
 | 
					 | 
				
			||||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE
 | 
					 | 
				
			||||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES
 | 
					 | 
				
			||||||
CLANG_WARN_PRAGMA_PACK = YES
 | 
					 | 
				
			||||||
CLANG_WARN_STRICT_PROTOTYPES = YES
 | 
					 | 
				
			||||||
CLANG_WARN_COMMA = YES
 | 
					 | 
				
			||||||
GCC_WARN_STRICT_SELECTOR_MATCH = YES
 | 
					 | 
				
			||||||
CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES
 | 
					 | 
				
			||||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES
 | 
					 | 
				
			||||||
GCC_WARN_SHADOW = YES
 | 
					 | 
				
			||||||
CLANG_WARN_UNREACHABLE_CODE = YES
 | 
					 | 
				
			||||||
@@ -1,12 +0,0 @@
 | 
				
			|||||||
<?xml version="1.0" encoding="UTF-8"?>
 | 
					 | 
				
			||||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
 | 
					 | 
				
			||||||
<plist version="1.0">
 | 
					 | 
				
			||||||
<dict>
 | 
					 | 
				
			||||||
	<key>com.apple.security.app-sandbox</key>
 | 
					 | 
				
			||||||
	<true/>
 | 
					 | 
				
			||||||
	<key>com.apple.security.cs.allow-jit</key>
 | 
					 | 
				
			||||||
	<true/>
 | 
					 | 
				
			||||||
	<key>com.apple.security.network.server</key>
 | 
					 | 
				
			||||||
	<true/>
 | 
					 | 
				
			||||||
</dict>
 | 
					 | 
				
			||||||
</plist>
 | 
					 | 
				
			||||||
@@ -1,32 +0,0 @@
 | 
				
			|||||||
<?xml version="1.0" encoding="UTF-8"?>
 | 
					 | 
				
			||||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
 | 
					 | 
				
			||||||
<plist version="1.0">
 | 
					 | 
				
			||||||
<dict>
 | 
					 | 
				
			||||||
	<key>CFBundleDevelopmentRegion</key>
 | 
					 | 
				
			||||||
	<string>$(DEVELOPMENT_LANGUAGE)</string>
 | 
					 | 
				
			||||||
	<key>CFBundleExecutable</key>
 | 
					 | 
				
			||||||
	<string>$(EXECUTABLE_NAME)</string>
 | 
					 | 
				
			||||||
	<key>CFBundleIconFile</key>
 | 
					 | 
				
			||||||
	<string></string>
 | 
					 | 
				
			||||||
	<key>CFBundleIdentifier</key>
 | 
					 | 
				
			||||||
	<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
 | 
					 | 
				
			||||||
	<key>CFBundleInfoDictionaryVersion</key>
 | 
					 | 
				
			||||||
	<string>6.0</string>
 | 
					 | 
				
			||||||
	<key>CFBundleName</key>
 | 
					 | 
				
			||||||
	<string>$(PRODUCT_NAME)</string>
 | 
					 | 
				
			||||||
	<key>CFBundlePackageType</key>
 | 
					 | 
				
			||||||
	<string>APPL</string>
 | 
					 | 
				
			||||||
	<key>CFBundleShortVersionString</key>
 | 
					 | 
				
			||||||
	<string>$(FLUTTER_BUILD_NAME)</string>
 | 
					 | 
				
			||||||
	<key>CFBundleVersion</key>
 | 
					 | 
				
			||||||
	<string>$(FLUTTER_BUILD_NUMBER)</string>
 | 
					 | 
				
			||||||
	<key>LSMinimumSystemVersion</key>
 | 
					 | 
				
			||||||
	<string>$(MACOSX_DEPLOYMENT_TARGET)</string>
 | 
					 | 
				
			||||||
	<key>NSHumanReadableCopyright</key>
 | 
					 | 
				
			||||||
	<string>$(PRODUCT_COPYRIGHT)</string>
 | 
					 | 
				
			||||||
	<key>NSMainNibFile</key>
 | 
					 | 
				
			||||||
	<string>MainMenu</string>
 | 
					 | 
				
			||||||
	<key>NSPrincipalClass</key>
 | 
					 | 
				
			||||||
	<string>NSApplication</string>
 | 
					 | 
				
			||||||
</dict>
 | 
					 | 
				
			||||||
</plist>
 | 
					 | 
				
			||||||
@@ -1,15 +0,0 @@
 | 
				
			|||||||
import Cocoa
 | 
					 | 
				
			||||||
import FlutterMacOS
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class MainFlutterWindow: NSWindow {
 | 
					 | 
				
			||||||
  override func awakeFromNib() {
 | 
					 | 
				
			||||||
    let flutterViewController = FlutterViewController()
 | 
					 | 
				
			||||||
    let windowFrame = self.frame
 | 
					 | 
				
			||||||
    self.contentViewController = flutterViewController
 | 
					 | 
				
			||||||
    self.setFrame(windowFrame, display: true)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    RegisterGeneratedPlugins(registry: flutterViewController)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    super.awakeFromNib()
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -1,8 +0,0 @@
 | 
				
			|||||||
<?xml version="1.0" encoding="UTF-8"?>
 | 
					 | 
				
			||||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
 | 
					 | 
				
			||||||
<plist version="1.0">
 | 
					 | 
				
			||||||
<dict>
 | 
					 | 
				
			||||||
	<key>com.apple.security.app-sandbox</key>
 | 
					 | 
				
			||||||
	<true/>
 | 
					 | 
				
			||||||
</dict>
 | 
					 | 
				
			||||||
</plist>
 | 
					 | 
				
			||||||
@@ -1,12 +0,0 @@
 | 
				
			|||||||
import Cocoa
 | 
					 | 
				
			||||||
import FlutterMacOS
 | 
					 | 
				
			||||||
import XCTest
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class RunnerTests: XCTestCase {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  func testExample() {
 | 
					 | 
				
			||||||
    // If you add code to the Runner application, consider adding tests here.
 | 
					 | 
				
			||||||
    // See https://developer.apple.com/documentation/xctest for more information about using XCTest.
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
							
								
								
									
										34
									
								
								pubspec.lock
									
									
									
									
									
								
							
							
						
						@@ -158,6 +158,14 @@ packages:
 | 
				
			|||||||
      url: "https://pub.dev"
 | 
					      url: "https://pub.dev"
 | 
				
			||||||
    source: hosted
 | 
					    source: hosted
 | 
				
			||||||
    version: "6.0.0"
 | 
					    version: "6.0.0"
 | 
				
			||||||
 | 
					  flutter_riverpod:
 | 
				
			||||||
 | 
					    dependency: "direct main"
 | 
				
			||||||
 | 
					    description:
 | 
				
			||||||
 | 
					      name: flutter_riverpod
 | 
				
			||||||
 | 
					      sha256: "9532ee6db4a943a1ed8383072a2e3eeda041db5657cdf6d2acecf3c21ecbe7e1"
 | 
				
			||||||
 | 
					      url: "https://pub.dev"
 | 
				
			||||||
 | 
					    source: hosted
 | 
				
			||||||
 | 
					    version: "2.6.1"
 | 
				
			||||||
  flutter_secure_storage:
 | 
					  flutter_secure_storage:
 | 
				
			||||||
    dependency: "direct main"
 | 
					    dependency: "direct main"
 | 
				
			||||||
    description:
 | 
					    description:
 | 
				
			||||||
@@ -328,14 +336,6 @@ packages:
 | 
				
			|||||||
      url: "https://pub.dev"
 | 
					      url: "https://pub.dev"
 | 
				
			||||||
    source: hosted
 | 
					    source: hosted
 | 
				
			||||||
    version: "2.0.0"
 | 
					    version: "2.0.0"
 | 
				
			||||||
  nested:
 | 
					 | 
				
			||||||
    dependency: transitive
 | 
					 | 
				
			||||||
    description:
 | 
					 | 
				
			||||||
      name: nested
 | 
					 | 
				
			||||||
      sha256: "03bac4c528c64c95c722ec99280375a6f2fc708eec17c7b3f07253b626cd2a20"
 | 
					 | 
				
			||||||
      url: "https://pub.dev"
 | 
					 | 
				
			||||||
    source: hosted
 | 
					 | 
				
			||||||
    version: "1.0.0"
 | 
					 | 
				
			||||||
  octo_image:
 | 
					  octo_image:
 | 
				
			||||||
    dependency: transitive
 | 
					    dependency: transitive
 | 
				
			||||||
    description:
 | 
					    description:
 | 
				
			||||||
@@ -432,14 +432,14 @@ packages:
 | 
				
			|||||||
      url: "https://pub.dev"
 | 
					      url: "https://pub.dev"
 | 
				
			||||||
    source: hosted
 | 
					    source: hosted
 | 
				
			||||||
    version: "2.1.8"
 | 
					    version: "2.1.8"
 | 
				
			||||||
  provider:
 | 
					  riverpod:
 | 
				
			||||||
    dependency: "direct main"
 | 
					    dependency: transitive
 | 
				
			||||||
    description:
 | 
					    description:
 | 
				
			||||||
      name: provider
 | 
					      name: riverpod
 | 
				
			||||||
      sha256: "4abbd070a04e9ddc287673bf5a030c7ca8b685ff70218720abab8b092f53dd84"
 | 
					      sha256: "59062512288d3056b2321804332a13ffdd1bf16df70dcc8e506e411280a72959"
 | 
				
			||||||
      url: "https://pub.dev"
 | 
					      url: "https://pub.dev"
 | 
				
			||||||
    source: hosted
 | 
					    source: hosted
 | 
				
			||||||
    version: "6.1.5"
 | 
					    version: "2.6.1"
 | 
				
			||||||
  rxdart:
 | 
					  rxdart:
 | 
				
			||||||
    dependency: transitive
 | 
					    dependency: transitive
 | 
				
			||||||
    description:
 | 
					    description:
 | 
				
			||||||
@@ -533,6 +533,14 @@ packages:
 | 
				
			|||||||
      url: "https://pub.dev"
 | 
					      url: "https://pub.dev"
 | 
				
			||||||
    source: hosted
 | 
					    source: hosted
 | 
				
			||||||
    version: "1.12.1"
 | 
					    version: "1.12.1"
 | 
				
			||||||
 | 
					  state_notifier:
 | 
				
			||||||
 | 
					    dependency: transitive
 | 
				
			||||||
 | 
					    description:
 | 
				
			||||||
 | 
					      name: state_notifier
 | 
				
			||||||
 | 
					      sha256: b8677376aa54f2d7c58280d5a007f9e8774f1968d1fb1c096adcb4792fba29bb
 | 
				
			||||||
 | 
					      url: "https://pub.dev"
 | 
				
			||||||
 | 
					    source: hosted
 | 
				
			||||||
 | 
					    version: "1.0.0"
 | 
				
			||||||
  stream_channel:
 | 
					  stream_channel:
 | 
				
			||||||
    dependency: transitive
 | 
					    dependency: transitive
 | 
				
			||||||
    description:
 | 
					    description:
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -16,7 +16,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
 | 
				
			|||||||
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
 | 
					# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
 | 
				
			||||||
# In Windows, build-name is used as the major, minor, and patch parts
 | 
					# In Windows, build-name is used as the major, minor, and patch parts
 | 
				
			||||||
# of the product and file versions while build-number is used as the build suffix.
 | 
					# of the product and file versions while build-number is used as the build suffix.
 | 
				
			||||||
version: 1.1.1+32
 | 
					version: 1.1.3+33
 | 
				
			||||||
 | 
					
 | 
				
			||||||
environment:
 | 
					environment:
 | 
				
			||||||
  sdk: ^3.9.0-100.2.beta
 | 
					  sdk: ^3.9.0-100.2.beta
 | 
				
			||||||
@@ -37,10 +37,10 @@ dependencies:
 | 
				
			|||||||
  cupertino_icons: ^1.0.8
 | 
					  cupertino_icons: ^1.0.8
 | 
				
			||||||
  cached_network_image: ^3.4.1
 | 
					  cached_network_image: ^3.4.1
 | 
				
			||||||
  cached_video_player_plus: ^3.0.3
 | 
					  cached_video_player_plus: ^3.0.3
 | 
				
			||||||
  provider: ^6.1.5
 | 
					 | 
				
			||||||
  package_info_plus: ^8.3.0
 | 
					  package_info_plus: ^8.3.0
 | 
				
			||||||
  share_plus: ^11.0.0
 | 
					  share_plus: ^11.0.0
 | 
				
			||||||
  flutter_secure_storage: ^9.2.4
 | 
					  flutter_secure_storage: ^9.2.4
 | 
				
			||||||
 | 
					  flutter_riverpod: ^2.6.1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
dev_dependencies:
 | 
					dev_dependencies:
 | 
				
			||||||
  flutter_test:
 | 
					  flutter_test:
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										
											BIN
										
									
								
								web/favicon.png
									
									
									
									
									
								
							
							
						
						| 
		 Before Width: | Height: | Size: 917 B  | 
| 
		 Before Width: | Height: | Size: 5.2 KiB  | 
| 
		 Before Width: | Height: | Size: 8.1 KiB  | 
| 
		 Before Width: | Height: | Size: 5.5 KiB  | 
| 
		 Before Width: | Height: | Size: 20 KiB  | 
@@ -1,38 +0,0 @@
 | 
				
			|||||||
<!DOCTYPE html>
 | 
					 | 
				
			||||||
<html>
 | 
					 | 
				
			||||||
<head>
 | 
					 | 
				
			||||||
  <!--
 | 
					 | 
				
			||||||
    If you are serving your web app in a path other than the root, change the
 | 
					 | 
				
			||||||
    href value below to reflect the base path you are serving from.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    The path provided below has to start and end with a slash "/" in order for
 | 
					 | 
				
			||||||
    it to work correctly.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    For more details:
 | 
					 | 
				
			||||||
    * https://developer.mozilla.org/en-US/docs/Web/HTML/Element/base
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    This is a placeholder for base href that will be replaced by the value of
 | 
					 | 
				
			||||||
    the `--base-href` argument provided to `flutter build`.
 | 
					 | 
				
			||||||
  -->
 | 
					 | 
				
			||||||
  <base href="$FLUTTER_BASE_HREF">
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  <meta charset="UTF-8">
 | 
					 | 
				
			||||||
  <meta content="IE=Edge" http-equiv="X-UA-Compatible">
 | 
					 | 
				
			||||||
  <meta name="description" content="A new Flutter project.">
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  <!-- iOS meta tags & icons -->
 | 
					 | 
				
			||||||
  <meta name="mobile-web-app-capable" content="yes">
 | 
					 | 
				
			||||||
  <meta name="apple-mobile-web-app-status-bar-style" content="black">
 | 
					 | 
				
			||||||
  <meta name="apple-mobile-web-app-title" content="f0ckapp">
 | 
					 | 
				
			||||||
  <link rel="apple-touch-icon" href="icons/Icon-192.png">
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  <!-- Favicon -->
 | 
					 | 
				
			||||||
  <link rel="icon" type="image/png" href="favicon.png"/>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  <title>f0ckapp</title>
 | 
					 | 
				
			||||||
  <link rel="manifest" href="manifest.json">
 | 
					 | 
				
			||||||
</head>
 | 
					 | 
				
			||||||
<body>
 | 
					 | 
				
			||||||
  <script src="flutter_bootstrap.js" async></script>
 | 
					 | 
				
			||||||
</body>
 | 
					 | 
				
			||||||
</html>
 | 
					 | 
				
			||||||
@@ -1,35 +0,0 @@
 | 
				
			|||||||
{
 | 
					 | 
				
			||||||
    "name": "f0ckapp",
 | 
					 | 
				
			||||||
    "short_name": "f0ckapp",
 | 
					 | 
				
			||||||
    "start_url": ".",
 | 
					 | 
				
			||||||
    "display": "standalone",
 | 
					 | 
				
			||||||
    "background_color": "#0175C2",
 | 
					 | 
				
			||||||
    "theme_color": "#0175C2",
 | 
					 | 
				
			||||||
    "description": "A new Flutter project.",
 | 
					 | 
				
			||||||
    "orientation": "portrait-primary",
 | 
					 | 
				
			||||||
    "prefer_related_applications": false,
 | 
					 | 
				
			||||||
    "icons": [
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            "src": "icons/Icon-192.png",
 | 
					 | 
				
			||||||
            "sizes": "192x192",
 | 
					 | 
				
			||||||
            "type": "image/png"
 | 
					 | 
				
			||||||
        },
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            "src": "icons/Icon-512.png",
 | 
					 | 
				
			||||||
            "sizes": "512x512",
 | 
					 | 
				
			||||||
            "type": "image/png"
 | 
					 | 
				
			||||||
        },
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            "src": "icons/Icon-maskable-192.png",
 | 
					 | 
				
			||||||
            "sizes": "192x192",
 | 
					 | 
				
			||||||
            "type": "image/png",
 | 
					 | 
				
			||||||
            "purpose": "maskable"
 | 
					 | 
				
			||||||
        },
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            "src": "icons/Icon-maskable-512.png",
 | 
					 | 
				
			||||||
            "sizes": "512x512",
 | 
					 | 
				
			||||||
            "type": "image/png",
 | 
					 | 
				
			||||||
            "purpose": "maskable"
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    ]
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
							
								
								
									
										17
									
								
								windows/.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						@@ -1,17 +0,0 @@
 | 
				
			|||||||
flutter/ephemeral/
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# Visual Studio user-specific files.
 | 
					 | 
				
			||||||
*.suo
 | 
					 | 
				
			||||||
*.user
 | 
					 | 
				
			||||||
*.userosscache
 | 
					 | 
				
			||||||
*.sln.docstates
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# Visual Studio build-related files.
 | 
					 | 
				
			||||||
x64/
 | 
					 | 
				
			||||||
x86/
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# Visual Studio cache files
 | 
					 | 
				
			||||||
# files ending in .cache can be ignored
 | 
					 | 
				
			||||||
*.[Cc]ache
 | 
					 | 
				
			||||||
# but keep track of directories ending in .cache
 | 
					 | 
				
			||||||
!*.[Cc]ache/
 | 
					 | 
				
			||||||
@@ -1,108 +0,0 @@
 | 
				
			|||||||
# Project-level configuration.
 | 
					 | 
				
			||||||
cmake_minimum_required(VERSION 3.14)
 | 
					 | 
				
			||||||
project(f0ckapp LANGUAGES CXX)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# The name of the executable created for the application. Change this to change
 | 
					 | 
				
			||||||
# the on-disk name of your application.
 | 
					 | 
				
			||||||
set(BINARY_NAME "f0ckapp")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# Explicitly opt in to modern CMake behaviors to avoid warnings with recent
 | 
					 | 
				
			||||||
# versions of CMake.
 | 
					 | 
				
			||||||
cmake_policy(VERSION 3.14...3.25)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# Define build configuration option.
 | 
					 | 
				
			||||||
get_property(IS_MULTICONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
 | 
					 | 
				
			||||||
if(IS_MULTICONFIG)
 | 
					 | 
				
			||||||
  set(CMAKE_CONFIGURATION_TYPES "Debug;Profile;Release"
 | 
					 | 
				
			||||||
    CACHE STRING "" FORCE)
 | 
					 | 
				
			||||||
else()
 | 
					 | 
				
			||||||
  if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
 | 
					 | 
				
			||||||
    set(CMAKE_BUILD_TYPE "Debug" CACHE
 | 
					 | 
				
			||||||
      STRING "Flutter build mode" FORCE)
 | 
					 | 
				
			||||||
    set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS
 | 
					 | 
				
			||||||
      "Debug" "Profile" "Release")
 | 
					 | 
				
			||||||
  endif()
 | 
					 | 
				
			||||||
endif()
 | 
					 | 
				
			||||||
# Define settings for the Profile build mode.
 | 
					 | 
				
			||||||
set(CMAKE_EXE_LINKER_FLAGS_PROFILE "${CMAKE_EXE_LINKER_FLAGS_RELEASE}")
 | 
					 | 
				
			||||||
set(CMAKE_SHARED_LINKER_FLAGS_PROFILE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE}")
 | 
					 | 
				
			||||||
set(CMAKE_C_FLAGS_PROFILE "${CMAKE_C_FLAGS_RELEASE}")
 | 
					 | 
				
			||||||
set(CMAKE_CXX_FLAGS_PROFILE "${CMAKE_CXX_FLAGS_RELEASE}")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# Use Unicode for all projects.
 | 
					 | 
				
			||||||
add_definitions(-DUNICODE -D_UNICODE)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# Compilation settings that should be applied to most targets.
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
# Be cautious about adding new options here, as plugins use this function by
 | 
					 | 
				
			||||||
# default. In most cases, you should add new options to specific targets instead
 | 
					 | 
				
			||||||
# of modifying this function.
 | 
					 | 
				
			||||||
function(APPLY_STANDARD_SETTINGS TARGET)
 | 
					 | 
				
			||||||
  target_compile_features(${TARGET} PUBLIC cxx_std_17)
 | 
					 | 
				
			||||||
  target_compile_options(${TARGET} PRIVATE /W4 /WX /wd"4100")
 | 
					 | 
				
			||||||
  target_compile_options(${TARGET} PRIVATE /EHsc)
 | 
					 | 
				
			||||||
  target_compile_definitions(${TARGET} PRIVATE "_HAS_EXCEPTIONS=0")
 | 
					 | 
				
			||||||
  target_compile_definitions(${TARGET} PRIVATE "$<$<CONFIG:Debug>:_DEBUG>")
 | 
					 | 
				
			||||||
endfunction()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# Flutter library and tool build rules.
 | 
					 | 
				
			||||||
set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter")
 | 
					 | 
				
			||||||
add_subdirectory(${FLUTTER_MANAGED_DIR})
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# Application build; see runner/CMakeLists.txt.
 | 
					 | 
				
			||||||
add_subdirectory("runner")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# Generated plugin build rules, which manage building the plugins and adding
 | 
					 | 
				
			||||||
# them to the application.
 | 
					 | 
				
			||||||
include(flutter/generated_plugins.cmake)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# === Installation ===
 | 
					 | 
				
			||||||
# Support files are copied into place next to the executable, so that it can
 | 
					 | 
				
			||||||
# run in place. This is done instead of making a separate bundle (as on Linux)
 | 
					 | 
				
			||||||
# so that building and running from within Visual Studio will work.
 | 
					 | 
				
			||||||
set(BUILD_BUNDLE_DIR "$<TARGET_FILE_DIR:${BINARY_NAME}>")
 | 
					 | 
				
			||||||
# Make the "install" step default, as it's required to run.
 | 
					 | 
				
			||||||
set(CMAKE_VS_INCLUDE_INSTALL_TO_DEFAULT_BUILD 1)
 | 
					 | 
				
			||||||
if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
 | 
					 | 
				
			||||||
  set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE)
 | 
					 | 
				
			||||||
endif()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data")
 | 
					 | 
				
			||||||
set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}"
 | 
					 | 
				
			||||||
  COMPONENT Runtime)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}"
 | 
					 | 
				
			||||||
  COMPONENT Runtime)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
 | 
					 | 
				
			||||||
  COMPONENT Runtime)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
if(PLUGIN_BUNDLED_LIBRARIES)
 | 
					 | 
				
			||||||
  install(FILES "${PLUGIN_BUNDLED_LIBRARIES}"
 | 
					 | 
				
			||||||
    DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
 | 
					 | 
				
			||||||
    COMPONENT Runtime)
 | 
					 | 
				
			||||||
endif()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# Copy the native assets provided by the build.dart from all packages.
 | 
					 | 
				
			||||||
set(NATIVE_ASSETS_DIR "${PROJECT_BUILD_DIR}native_assets/windows/")
 | 
					 | 
				
			||||||
install(DIRECTORY "${NATIVE_ASSETS_DIR}"
 | 
					 | 
				
			||||||
   DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
 | 
					 | 
				
			||||||
   COMPONENT Runtime)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# Fully re-copy the assets directory on each build to avoid having stale files
 | 
					 | 
				
			||||||
# from a previous install.
 | 
					 | 
				
			||||||
set(FLUTTER_ASSET_DIR_NAME "flutter_assets")
 | 
					 | 
				
			||||||
install(CODE "
 | 
					 | 
				
			||||||
  file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\")
 | 
					 | 
				
			||||||
  " COMPONENT Runtime)
 | 
					 | 
				
			||||||
install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}"
 | 
					 | 
				
			||||||
  DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# Install the AOT library on non-Debug builds only.
 | 
					 | 
				
			||||||
install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}"
 | 
					 | 
				
			||||||
  CONFIGURATIONS Profile;Release
 | 
					 | 
				
			||||||
  COMPONENT Runtime)
 | 
					 | 
				
			||||||
@@ -1,109 +0,0 @@
 | 
				
			|||||||
# This file controls Flutter-level build steps. It should not be edited.
 | 
					 | 
				
			||||||
cmake_minimum_required(VERSION 3.14)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# Configuration provided via flutter tool.
 | 
					 | 
				
			||||||
include(${EPHEMERAL_DIR}/generated_config.cmake)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# TODO: Move the rest of this into files in ephemeral. See
 | 
					 | 
				
			||||||
# https://github.com/flutter/flutter/issues/57146.
 | 
					 | 
				
			||||||
set(WRAPPER_ROOT "${EPHEMERAL_DIR}/cpp_client_wrapper")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# Set fallback configurations for older versions of the flutter tool.
 | 
					 | 
				
			||||||
if (NOT DEFINED FLUTTER_TARGET_PLATFORM)
 | 
					 | 
				
			||||||
  set(FLUTTER_TARGET_PLATFORM "windows-x64")
 | 
					 | 
				
			||||||
endif()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# === Flutter Library ===
 | 
					 | 
				
			||||||
set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/flutter_windows.dll")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# Published to parent scope for install step.
 | 
					 | 
				
			||||||
set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE)
 | 
					 | 
				
			||||||
set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE)
 | 
					 | 
				
			||||||
set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE)
 | 
					 | 
				
			||||||
set(AOT_LIBRARY "${PROJECT_DIR}/build/windows/app.so" PARENT_SCOPE)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
list(APPEND FLUTTER_LIBRARY_HEADERS
 | 
					 | 
				
			||||||
  "flutter_export.h"
 | 
					 | 
				
			||||||
  "flutter_windows.h"
 | 
					 | 
				
			||||||
  "flutter_messenger.h"
 | 
					 | 
				
			||||||
  "flutter_plugin_registrar.h"
 | 
					 | 
				
			||||||
  "flutter_texture_registrar.h"
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
list(TRANSFORM FLUTTER_LIBRARY_HEADERS PREPEND "${EPHEMERAL_DIR}/")
 | 
					 | 
				
			||||||
add_library(flutter INTERFACE)
 | 
					 | 
				
			||||||
target_include_directories(flutter INTERFACE
 | 
					 | 
				
			||||||
  "${EPHEMERAL_DIR}"
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}.lib")
 | 
					 | 
				
			||||||
add_dependencies(flutter flutter_assemble)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# === Wrapper ===
 | 
					 | 
				
			||||||
list(APPEND CPP_WRAPPER_SOURCES_CORE
 | 
					 | 
				
			||||||
  "core_implementations.cc"
 | 
					 | 
				
			||||||
  "standard_codec.cc"
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
list(TRANSFORM CPP_WRAPPER_SOURCES_CORE PREPEND "${WRAPPER_ROOT}/")
 | 
					 | 
				
			||||||
list(APPEND CPP_WRAPPER_SOURCES_PLUGIN
 | 
					 | 
				
			||||||
  "plugin_registrar.cc"
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
list(TRANSFORM CPP_WRAPPER_SOURCES_PLUGIN PREPEND "${WRAPPER_ROOT}/")
 | 
					 | 
				
			||||||
list(APPEND CPP_WRAPPER_SOURCES_APP
 | 
					 | 
				
			||||||
  "flutter_engine.cc"
 | 
					 | 
				
			||||||
  "flutter_view_controller.cc"
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
list(TRANSFORM CPP_WRAPPER_SOURCES_APP PREPEND "${WRAPPER_ROOT}/")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# Wrapper sources needed for a plugin.
 | 
					 | 
				
			||||||
add_library(flutter_wrapper_plugin STATIC
 | 
					 | 
				
			||||||
  ${CPP_WRAPPER_SOURCES_CORE}
 | 
					 | 
				
			||||||
  ${CPP_WRAPPER_SOURCES_PLUGIN}
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
apply_standard_settings(flutter_wrapper_plugin)
 | 
					 | 
				
			||||||
set_target_properties(flutter_wrapper_plugin PROPERTIES
 | 
					 | 
				
			||||||
  POSITION_INDEPENDENT_CODE ON)
 | 
					 | 
				
			||||||
set_target_properties(flutter_wrapper_plugin PROPERTIES
 | 
					 | 
				
			||||||
  CXX_VISIBILITY_PRESET hidden)
 | 
					 | 
				
			||||||
target_link_libraries(flutter_wrapper_plugin PUBLIC flutter)
 | 
					 | 
				
			||||||
target_include_directories(flutter_wrapper_plugin PUBLIC
 | 
					 | 
				
			||||||
  "${WRAPPER_ROOT}/include"
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
add_dependencies(flutter_wrapper_plugin flutter_assemble)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# Wrapper sources needed for the runner.
 | 
					 | 
				
			||||||
add_library(flutter_wrapper_app STATIC
 | 
					 | 
				
			||||||
  ${CPP_WRAPPER_SOURCES_CORE}
 | 
					 | 
				
			||||||
  ${CPP_WRAPPER_SOURCES_APP}
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
apply_standard_settings(flutter_wrapper_app)
 | 
					 | 
				
			||||||
target_link_libraries(flutter_wrapper_app PUBLIC flutter)
 | 
					 | 
				
			||||||
target_include_directories(flutter_wrapper_app PUBLIC
 | 
					 | 
				
			||||||
  "${WRAPPER_ROOT}/include"
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
add_dependencies(flutter_wrapper_app flutter_assemble)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# === Flutter tool backend ===
 | 
					 | 
				
			||||||
# _phony_ is a non-existent file to force this command to run every time,
 | 
					 | 
				
			||||||
# since currently there's no way to get a full input/output list from the
 | 
					 | 
				
			||||||
# flutter tool.
 | 
					 | 
				
			||||||
set(PHONY_OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/_phony_")
 | 
					 | 
				
			||||||
set_source_files_properties("${PHONY_OUTPUT}" PROPERTIES SYMBOLIC TRUE)
 | 
					 | 
				
			||||||
add_custom_command(
 | 
					 | 
				
			||||||
  OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS}
 | 
					 | 
				
			||||||
    ${CPP_WRAPPER_SOURCES_CORE} ${CPP_WRAPPER_SOURCES_PLUGIN}
 | 
					 | 
				
			||||||
    ${CPP_WRAPPER_SOURCES_APP}
 | 
					 | 
				
			||||||
    ${PHONY_OUTPUT}
 | 
					 | 
				
			||||||
  COMMAND ${CMAKE_COMMAND} -E env
 | 
					 | 
				
			||||||
    ${FLUTTER_TOOL_ENVIRONMENT}
 | 
					 | 
				
			||||||
    "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.bat"
 | 
					 | 
				
			||||||
      ${FLUTTER_TARGET_PLATFORM} $<CONFIG>
 | 
					 | 
				
			||||||
  VERBATIM
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
add_custom_target(flutter_assemble DEPENDS
 | 
					 | 
				
			||||||
  "${FLUTTER_LIBRARY}"
 | 
					 | 
				
			||||||
  ${FLUTTER_LIBRARY_HEADERS}
 | 
					 | 
				
			||||||
  ${CPP_WRAPPER_SOURCES_CORE}
 | 
					 | 
				
			||||||
  ${CPP_WRAPPER_SOURCES_PLUGIN}
 | 
					 | 
				
			||||||
  ${CPP_WRAPPER_SOURCES_APP}
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
@@ -1,20 +0,0 @@
 | 
				
			|||||||
//
 | 
					 | 
				
			||||||
//  Generated file. Do not edit.
 | 
					 | 
				
			||||||
//
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// clang-format off
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "generated_plugin_registrant.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <flutter_secure_storage_windows/flutter_secure_storage_windows_plugin.h>
 | 
					 | 
				
			||||||
#include <share_plus/share_plus_windows_plugin_c_api.h>
 | 
					 | 
				
			||||||
#include <url_launcher_windows/url_launcher_windows.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void RegisterPlugins(flutter::PluginRegistry* registry) {
 | 
					 | 
				
			||||||
  FlutterSecureStorageWindowsPluginRegisterWithRegistrar(
 | 
					 | 
				
			||||||
      registry->GetRegistrarForPlugin("FlutterSecureStorageWindowsPlugin"));
 | 
					 | 
				
			||||||
  SharePlusWindowsPluginCApiRegisterWithRegistrar(
 | 
					 | 
				
			||||||
      registry->GetRegistrarForPlugin("SharePlusWindowsPluginCApi"));
 | 
					 | 
				
			||||||
  UrlLauncherWindowsRegisterWithRegistrar(
 | 
					 | 
				
			||||||
      registry->GetRegistrarForPlugin("UrlLauncherWindows"));
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -1,15 +0,0 @@
 | 
				
			|||||||
//
 | 
					 | 
				
			||||||
//  Generated file. Do not edit.
 | 
					 | 
				
			||||||
//
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// clang-format off
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifndef GENERATED_PLUGIN_REGISTRANT_
 | 
					 | 
				
			||||||
#define GENERATED_PLUGIN_REGISTRANT_
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <flutter/plugin_registry.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Registers Flutter plugins.
 | 
					 | 
				
			||||||
void RegisterPlugins(flutter::PluginRegistry* registry);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#endif  // GENERATED_PLUGIN_REGISTRANT_
 | 
					 | 
				
			||||||
@@ -1,26 +0,0 @@
 | 
				
			|||||||
#
 | 
					 | 
				
			||||||
# Generated file, do not edit.
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
list(APPEND FLUTTER_PLUGIN_LIST
 | 
					 | 
				
			||||||
  flutter_secure_storage_windows
 | 
					 | 
				
			||||||
  share_plus
 | 
					 | 
				
			||||||
  url_launcher_windows
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
list(APPEND FLUTTER_FFI_PLUGIN_LIST
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
set(PLUGIN_BUNDLED_LIBRARIES)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
foreach(plugin ${FLUTTER_PLUGIN_LIST})
 | 
					 | 
				
			||||||
  add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/windows plugins/${plugin})
 | 
					 | 
				
			||||||
  target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin)
 | 
					 | 
				
			||||||
  list(APPEND PLUGIN_BUNDLED_LIBRARIES $<TARGET_FILE:${plugin}_plugin>)
 | 
					 | 
				
			||||||
  list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries})
 | 
					 | 
				
			||||||
endforeach(plugin)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST})
 | 
					 | 
				
			||||||
  add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/windows plugins/${ffi_plugin})
 | 
					 | 
				
			||||||
  list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries})
 | 
					 | 
				
			||||||
endforeach(ffi_plugin)
 | 
					 | 
				
			||||||
@@ -1,40 +0,0 @@
 | 
				
			|||||||
cmake_minimum_required(VERSION 3.14)
 | 
					 | 
				
			||||||
project(runner LANGUAGES CXX)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# Define the application target. To change its name, change BINARY_NAME in the
 | 
					 | 
				
			||||||
# top-level CMakeLists.txt, not the value here, or `flutter run` will no longer
 | 
					 | 
				
			||||||
# work.
 | 
					 | 
				
			||||||
#
 | 
					 | 
				
			||||||
# Any new source files that you add to the application should be added here.
 | 
					 | 
				
			||||||
add_executable(${BINARY_NAME} WIN32
 | 
					 | 
				
			||||||
  "flutter_window.cpp"
 | 
					 | 
				
			||||||
  "main.cpp"
 | 
					 | 
				
			||||||
  "utils.cpp"
 | 
					 | 
				
			||||||
  "win32_window.cpp"
 | 
					 | 
				
			||||||
  "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc"
 | 
					 | 
				
			||||||
  "Runner.rc"
 | 
					 | 
				
			||||||
  "runner.exe.manifest"
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# Apply the standard set of build settings. This can be removed for applications
 | 
					 | 
				
			||||||
# that need different build settings.
 | 
					 | 
				
			||||||
apply_standard_settings(${BINARY_NAME})
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# Add preprocessor definitions for the build version.
 | 
					 | 
				
			||||||
target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION=\"${FLUTTER_VERSION}\"")
 | 
					 | 
				
			||||||
target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MAJOR=${FLUTTER_VERSION_MAJOR}")
 | 
					 | 
				
			||||||
target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MINOR=${FLUTTER_VERSION_MINOR}")
 | 
					 | 
				
			||||||
target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_PATCH=${FLUTTER_VERSION_PATCH}")
 | 
					 | 
				
			||||||
target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_BUILD=${FLUTTER_VERSION_BUILD}")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# Disable Windows macros that collide with C++ standard library functions.
 | 
					 | 
				
			||||||
target_compile_definitions(${BINARY_NAME} PRIVATE "NOMINMAX")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# Add dependency libraries and include directories. Add any application-specific
 | 
					 | 
				
			||||||
# dependencies here.
 | 
					 | 
				
			||||||
target_link_libraries(${BINARY_NAME} PRIVATE flutter flutter_wrapper_app)
 | 
					 | 
				
			||||||
target_link_libraries(${BINARY_NAME} PRIVATE "dwmapi.lib")
 | 
					 | 
				
			||||||
target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# Run the Flutter tool portions of the build. This must not be removed.
 | 
					 | 
				
			||||||
add_dependencies(${BINARY_NAME} flutter_assemble)
 | 
					 | 
				
			||||||
@@ -1,121 +0,0 @@
 | 
				
			|||||||
// Microsoft Visual C++ generated resource script.
 | 
					 | 
				
			||||||
//
 | 
					 | 
				
			||||||
#pragma code_page(65001)
 | 
					 | 
				
			||||||
#include "resource.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#define APSTUDIO_READONLY_SYMBOLS
 | 
					 | 
				
			||||||
/////////////////////////////////////////////////////////////////////////////
 | 
					 | 
				
			||||||
//
 | 
					 | 
				
			||||||
// Generated from the TEXTINCLUDE 2 resource.
 | 
					 | 
				
			||||||
//
 | 
					 | 
				
			||||||
#include "winres.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/////////////////////////////////////////////////////////////////////////////
 | 
					 | 
				
			||||||
#undef APSTUDIO_READONLY_SYMBOLS
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/////////////////////////////////////////////////////////////////////////////
 | 
					 | 
				
			||||||
// English (United States) resources
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
 | 
					 | 
				
			||||||
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifdef APSTUDIO_INVOKED
 | 
					 | 
				
			||||||
/////////////////////////////////////////////////////////////////////////////
 | 
					 | 
				
			||||||
//
 | 
					 | 
				
			||||||
// TEXTINCLUDE
 | 
					 | 
				
			||||||
//
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
1 TEXTINCLUDE
 | 
					 | 
				
			||||||
BEGIN
 | 
					 | 
				
			||||||
    "resource.h\0"
 | 
					 | 
				
			||||||
END
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
2 TEXTINCLUDE
 | 
					 | 
				
			||||||
BEGIN
 | 
					 | 
				
			||||||
    "#include ""winres.h""\r\n"
 | 
					 | 
				
			||||||
    "\0"
 | 
					 | 
				
			||||||
END
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
3 TEXTINCLUDE
 | 
					 | 
				
			||||||
BEGIN
 | 
					 | 
				
			||||||
    "\r\n"
 | 
					 | 
				
			||||||
    "\0"
 | 
					 | 
				
			||||||
END
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#endif    // APSTUDIO_INVOKED
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/////////////////////////////////////////////////////////////////////////////
 | 
					 | 
				
			||||||
//
 | 
					 | 
				
			||||||
// Icon
 | 
					 | 
				
			||||||
//
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Icon with lowest ID value placed first to ensure application icon
 | 
					 | 
				
			||||||
// remains consistent on all systems.
 | 
					 | 
				
			||||||
IDI_APP_ICON            ICON                    "resources\\app_icon.ico"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/////////////////////////////////////////////////////////////////////////////
 | 
					 | 
				
			||||||
//
 | 
					 | 
				
			||||||
// Version
 | 
					 | 
				
			||||||
//
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#if defined(FLUTTER_VERSION_MAJOR) && defined(FLUTTER_VERSION_MINOR) && defined(FLUTTER_VERSION_PATCH) && defined(FLUTTER_VERSION_BUILD)
 | 
					 | 
				
			||||||
#define VERSION_AS_NUMBER FLUTTER_VERSION_MAJOR,FLUTTER_VERSION_MINOR,FLUTTER_VERSION_PATCH,FLUTTER_VERSION_BUILD
 | 
					 | 
				
			||||||
#else
 | 
					 | 
				
			||||||
#define VERSION_AS_NUMBER 1,0,0,0
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#if defined(FLUTTER_VERSION)
 | 
					 | 
				
			||||||
#define VERSION_AS_STRING FLUTTER_VERSION
 | 
					 | 
				
			||||||
#else
 | 
					 | 
				
			||||||
#define VERSION_AS_STRING "1.0.0"
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
VS_VERSION_INFO VERSIONINFO
 | 
					 | 
				
			||||||
 FILEVERSION VERSION_AS_NUMBER
 | 
					 | 
				
			||||||
 PRODUCTVERSION VERSION_AS_NUMBER
 | 
					 | 
				
			||||||
 FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
 | 
					 | 
				
			||||||
#ifdef _DEBUG
 | 
					 | 
				
			||||||
 FILEFLAGS VS_FF_DEBUG
 | 
					 | 
				
			||||||
#else
 | 
					 | 
				
			||||||
 FILEFLAGS 0x0L
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 FILEOS VOS__WINDOWS32
 | 
					 | 
				
			||||||
 FILETYPE VFT_APP
 | 
					 | 
				
			||||||
 FILESUBTYPE 0x0L
 | 
					 | 
				
			||||||
BEGIN
 | 
					 | 
				
			||||||
    BLOCK "StringFileInfo"
 | 
					 | 
				
			||||||
    BEGIN
 | 
					 | 
				
			||||||
        BLOCK "040904e4"
 | 
					 | 
				
			||||||
        BEGIN
 | 
					 | 
				
			||||||
            VALUE "CompanyName", "com.example" "\0"
 | 
					 | 
				
			||||||
            VALUE "FileDescription", "f0ckapp" "\0"
 | 
					 | 
				
			||||||
            VALUE "FileVersion", VERSION_AS_STRING "\0"
 | 
					 | 
				
			||||||
            VALUE "InternalName", "f0ckapp" "\0"
 | 
					 | 
				
			||||||
            VALUE "LegalCopyright", "Copyright (C) 2025 com.example. All rights reserved." "\0"
 | 
					 | 
				
			||||||
            VALUE "OriginalFilename", "f0ckapp.exe" "\0"
 | 
					 | 
				
			||||||
            VALUE "ProductName", "f0ckapp" "\0"
 | 
					 | 
				
			||||||
            VALUE "ProductVersion", VERSION_AS_STRING "\0"
 | 
					 | 
				
			||||||
        END
 | 
					 | 
				
			||||||
    END
 | 
					 | 
				
			||||||
    BLOCK "VarFileInfo"
 | 
					 | 
				
			||||||
    BEGIN
 | 
					 | 
				
			||||||
        VALUE "Translation", 0x409, 1252
 | 
					 | 
				
			||||||
    END
 | 
					 | 
				
			||||||
END
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#endif    // English (United States) resources
 | 
					 | 
				
			||||||
/////////////////////////////////////////////////////////////////////////////
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifndef APSTUDIO_INVOKED
 | 
					 | 
				
			||||||
/////////////////////////////////////////////////////////////////////////////
 | 
					 | 
				
			||||||
//
 | 
					 | 
				
			||||||
// Generated from the TEXTINCLUDE 3 resource.
 | 
					 | 
				
			||||||
//
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/////////////////////////////////////////////////////////////////////////////
 | 
					 | 
				
			||||||
#endif    // not APSTUDIO_INVOKED
 | 
					 | 
				
			||||||
@@ -1,71 +0,0 @@
 | 
				
			|||||||
#include "flutter_window.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <optional>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "flutter/generated_plugin_registrant.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
FlutterWindow::FlutterWindow(const flutter::DartProject& project)
 | 
					 | 
				
			||||||
    : project_(project) {}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
FlutterWindow::~FlutterWindow() {}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
bool FlutterWindow::OnCreate() {
 | 
					 | 
				
			||||||
  if (!Win32Window::OnCreate()) {
 | 
					 | 
				
			||||||
    return false;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  RECT frame = GetClientArea();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // The size here must match the window dimensions to avoid unnecessary surface
 | 
					 | 
				
			||||||
  // creation / destruction in the startup path.
 | 
					 | 
				
			||||||
  flutter_controller_ = std::make_unique<flutter::FlutterViewController>(
 | 
					 | 
				
			||||||
      frame.right - frame.left, frame.bottom - frame.top, project_);
 | 
					 | 
				
			||||||
  // Ensure that basic setup of the controller was successful.
 | 
					 | 
				
			||||||
  if (!flutter_controller_->engine() || !flutter_controller_->view()) {
 | 
					 | 
				
			||||||
    return false;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  RegisterPlugins(flutter_controller_->engine());
 | 
					 | 
				
			||||||
  SetChildContent(flutter_controller_->view()->GetNativeWindow());
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  flutter_controller_->engine()->SetNextFrameCallback([&]() {
 | 
					 | 
				
			||||||
    this->Show();
 | 
					 | 
				
			||||||
  });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Flutter can complete the first frame before the "show window" callback is
 | 
					 | 
				
			||||||
  // registered. The following call ensures a frame is pending to ensure the
 | 
					 | 
				
			||||||
  // window is shown. It is a no-op if the first frame hasn't completed yet.
 | 
					 | 
				
			||||||
  flutter_controller_->ForceRedraw();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return true;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void FlutterWindow::OnDestroy() {
 | 
					 | 
				
			||||||
  if (flutter_controller_) {
 | 
					 | 
				
			||||||
    flutter_controller_ = nullptr;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  Win32Window::OnDestroy();
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
LRESULT
 | 
					 | 
				
			||||||
FlutterWindow::MessageHandler(HWND hwnd, UINT const message,
 | 
					 | 
				
			||||||
                              WPARAM const wparam,
 | 
					 | 
				
			||||||
                              LPARAM const lparam) noexcept {
 | 
					 | 
				
			||||||
  // Give Flutter, including plugins, an opportunity to handle window messages.
 | 
					 | 
				
			||||||
  if (flutter_controller_) {
 | 
					 | 
				
			||||||
    std::optional<LRESULT> result =
 | 
					 | 
				
			||||||
        flutter_controller_->HandleTopLevelWindowProc(hwnd, message, wparam,
 | 
					 | 
				
			||||||
                                                      lparam);
 | 
					 | 
				
			||||||
    if (result) {
 | 
					 | 
				
			||||||
      return *result;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  switch (message) {
 | 
					 | 
				
			||||||
    case WM_FONTCHANGE:
 | 
					 | 
				
			||||||
      flutter_controller_->engine()->ReloadSystemFonts();
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return Win32Window::MessageHandler(hwnd, message, wparam, lparam);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -1,33 +0,0 @@
 | 
				
			|||||||
#ifndef RUNNER_FLUTTER_WINDOW_H_
 | 
					 | 
				
			||||||
#define RUNNER_FLUTTER_WINDOW_H_
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <flutter/dart_project.h>
 | 
					 | 
				
			||||||
#include <flutter/flutter_view_controller.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <memory>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "win32_window.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// A window that does nothing but host a Flutter view.
 | 
					 | 
				
			||||||
class FlutterWindow : public Win32Window {
 | 
					 | 
				
			||||||
 public:
 | 
					 | 
				
			||||||
  // Creates a new FlutterWindow hosting a Flutter view running |project|.
 | 
					 | 
				
			||||||
  explicit FlutterWindow(const flutter::DartProject& project);
 | 
					 | 
				
			||||||
  virtual ~FlutterWindow();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 protected:
 | 
					 | 
				
			||||||
  // Win32Window:
 | 
					 | 
				
			||||||
  bool OnCreate() override;
 | 
					 | 
				
			||||||
  void OnDestroy() override;
 | 
					 | 
				
			||||||
  LRESULT MessageHandler(HWND window, UINT const message, WPARAM const wparam,
 | 
					 | 
				
			||||||
                         LPARAM const lparam) noexcept override;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 private:
 | 
					 | 
				
			||||||
  // The project to run.
 | 
					 | 
				
			||||||
  flutter::DartProject project_;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // The Flutter instance hosted by this window.
 | 
					 | 
				
			||||||
  std::unique_ptr<flutter::FlutterViewController> flutter_controller_;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#endif  // RUNNER_FLUTTER_WINDOW_H_
 | 
					 | 
				
			||||||
@@ -1,43 +0,0 @@
 | 
				
			|||||||
#include <flutter/dart_project.h>
 | 
					 | 
				
			||||||
#include <flutter/flutter_view_controller.h>
 | 
					 | 
				
			||||||
#include <windows.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "flutter_window.h"
 | 
					 | 
				
			||||||
#include "utils.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev,
 | 
					 | 
				
			||||||
                      _In_ wchar_t *command_line, _In_ int show_command) {
 | 
					 | 
				
			||||||
  // Attach to console when present (e.g., 'flutter run') or create a
 | 
					 | 
				
			||||||
  // new console when running with a debugger.
 | 
					 | 
				
			||||||
  if (!::AttachConsole(ATTACH_PARENT_PROCESS) && ::IsDebuggerPresent()) {
 | 
					 | 
				
			||||||
    CreateAndAttachConsole();
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Initialize COM, so that it is available for use in the library and/or
 | 
					 | 
				
			||||||
  // plugins.
 | 
					 | 
				
			||||||
  ::CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  flutter::DartProject project(L"data");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  std::vector<std::string> command_line_arguments =
 | 
					 | 
				
			||||||
      GetCommandLineArguments();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  project.set_dart_entrypoint_arguments(std::move(command_line_arguments));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  FlutterWindow window(project);
 | 
					 | 
				
			||||||
  Win32Window::Point origin(10, 10);
 | 
					 | 
				
			||||||
  Win32Window::Size size(1280, 720);
 | 
					 | 
				
			||||||
  if (!window.Create(L"f0ckapp", origin, size)) {
 | 
					 | 
				
			||||||
    return EXIT_FAILURE;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  window.SetQuitOnClose(true);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  ::MSG msg;
 | 
					 | 
				
			||||||
  while (::GetMessage(&msg, nullptr, 0, 0)) {
 | 
					 | 
				
			||||||
    ::TranslateMessage(&msg);
 | 
					 | 
				
			||||||
    ::DispatchMessage(&msg);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  ::CoUninitialize();
 | 
					 | 
				
			||||||
  return EXIT_SUCCESS;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -1,16 +0,0 @@
 | 
				
			|||||||
//{{NO_DEPENDENCIES}}
 | 
					 | 
				
			||||||
// Microsoft Visual C++ generated include file.
 | 
					 | 
				
			||||||
// Used by Runner.rc
 | 
					 | 
				
			||||||
//
 | 
					 | 
				
			||||||
#define IDI_APP_ICON                    101
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Next default values for new objects
 | 
					 | 
				
			||||||
//
 | 
					 | 
				
			||||||
#ifdef APSTUDIO_INVOKED
 | 
					 | 
				
			||||||
#ifndef APSTUDIO_READONLY_SYMBOLS
 | 
					 | 
				
			||||||
#define _APS_NEXT_RESOURCE_VALUE        102
 | 
					 | 
				
			||||||
#define _APS_NEXT_COMMAND_VALUE         40001
 | 
					 | 
				
			||||||
#define _APS_NEXT_CONTROL_VALUE         1001
 | 
					 | 
				
			||||||
#define _APS_NEXT_SYMED_VALUE           101
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
| 
		 Before Width: | Height: | Size: 33 KiB  | 
@@ -1,14 +0,0 @@
 | 
				
			|||||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
 | 
					 | 
				
			||||||
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
 | 
					 | 
				
			||||||
  <application xmlns="urn:schemas-microsoft-com:asm.v3">
 | 
					 | 
				
			||||||
    <windowsSettings>
 | 
					 | 
				
			||||||
      <dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2</dpiAwareness>
 | 
					 | 
				
			||||||
    </windowsSettings>
 | 
					 | 
				
			||||||
  </application>
 | 
					 | 
				
			||||||
  <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
 | 
					 | 
				
			||||||
    <application>
 | 
					 | 
				
			||||||
      <!-- Windows 10 and Windows 11 -->
 | 
					 | 
				
			||||||
      <supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
 | 
					 | 
				
			||||||
    </application>
 | 
					 | 
				
			||||||
  </compatibility>
 | 
					 | 
				
			||||||
</assembly>
 | 
					 | 
				
			||||||
@@ -1,65 +0,0 @@
 | 
				
			|||||||
#include "utils.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <flutter_windows.h>
 | 
					 | 
				
			||||||
#include <io.h>
 | 
					 | 
				
			||||||
#include <stdio.h>
 | 
					 | 
				
			||||||
#include <windows.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <iostream>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void CreateAndAttachConsole() {
 | 
					 | 
				
			||||||
  if (::AllocConsole()) {
 | 
					 | 
				
			||||||
    FILE *unused;
 | 
					 | 
				
			||||||
    if (freopen_s(&unused, "CONOUT$", "w", stdout)) {
 | 
					 | 
				
			||||||
      _dup2(_fileno(stdout), 1);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    if (freopen_s(&unused, "CONOUT$", "w", stderr)) {
 | 
					 | 
				
			||||||
      _dup2(_fileno(stdout), 2);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    std::ios::sync_with_stdio();
 | 
					 | 
				
			||||||
    FlutterDesktopResyncOutputStreams();
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
std::vector<std::string> GetCommandLineArguments() {
 | 
					 | 
				
			||||||
  // Convert the UTF-16 command line arguments to UTF-8 for the Engine to use.
 | 
					 | 
				
			||||||
  int argc;
 | 
					 | 
				
			||||||
  wchar_t** argv = ::CommandLineToArgvW(::GetCommandLineW(), &argc);
 | 
					 | 
				
			||||||
  if (argv == nullptr) {
 | 
					 | 
				
			||||||
    return std::vector<std::string>();
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  std::vector<std::string> command_line_arguments;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Skip the first argument as it's the binary name.
 | 
					 | 
				
			||||||
  for (int i = 1; i < argc; i++) {
 | 
					 | 
				
			||||||
    command_line_arguments.push_back(Utf8FromUtf16(argv[i]));
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  ::LocalFree(argv);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return command_line_arguments;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
std::string Utf8FromUtf16(const wchar_t* utf16_string) {
 | 
					 | 
				
			||||||
  if (utf16_string == nullptr) {
 | 
					 | 
				
			||||||
    return std::string();
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  unsigned int target_length = ::WideCharToMultiByte(
 | 
					 | 
				
			||||||
      CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string,
 | 
					 | 
				
			||||||
      -1, nullptr, 0, nullptr, nullptr)
 | 
					 | 
				
			||||||
    -1; // remove the trailing null character
 | 
					 | 
				
			||||||
  int input_length = (int)wcslen(utf16_string);
 | 
					 | 
				
			||||||
  std::string utf8_string;
 | 
					 | 
				
			||||||
  if (target_length == 0 || target_length > utf8_string.max_size()) {
 | 
					 | 
				
			||||||
    return utf8_string;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  utf8_string.resize(target_length);
 | 
					 | 
				
			||||||
  int converted_length = ::WideCharToMultiByte(
 | 
					 | 
				
			||||||
      CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string,
 | 
					 | 
				
			||||||
      input_length, utf8_string.data(), target_length, nullptr, nullptr);
 | 
					 | 
				
			||||||
  if (converted_length == 0) {
 | 
					 | 
				
			||||||
    return std::string();
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  return utf8_string;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -1,19 +0,0 @@
 | 
				
			|||||||
#ifndef RUNNER_UTILS_H_
 | 
					 | 
				
			||||||
#define RUNNER_UTILS_H_
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <string>
 | 
					 | 
				
			||||||
#include <vector>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Creates a console for the process, and redirects stdout and stderr to
 | 
					 | 
				
			||||||
// it for both the runner and the Flutter library.
 | 
					 | 
				
			||||||
void CreateAndAttachConsole();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Takes a null-terminated wchar_t* encoded in UTF-16 and returns a std::string
 | 
					 | 
				
			||||||
// encoded in UTF-8. Returns an empty std::string on failure.
 | 
					 | 
				
			||||||
std::string Utf8FromUtf16(const wchar_t* utf16_string);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Gets the command line arguments passed in as a std::vector<std::string>,
 | 
					 | 
				
			||||||
// encoded in UTF-8. Returns an empty std::vector<std::string> on failure.
 | 
					 | 
				
			||||||
std::vector<std::string> GetCommandLineArguments();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#endif  // RUNNER_UTILS_H_
 | 
					 | 
				
			||||||
@@ -1,288 +0,0 @@
 | 
				
			|||||||
#include "win32_window.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <dwmapi.h>
 | 
					 | 
				
			||||||
#include <flutter_windows.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "resource.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// Window attribute that enables dark mode window decorations.
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// Redefined in case the developer's machine has a Windows SDK older than
 | 
					 | 
				
			||||||
/// version 10.0.22000.0.
 | 
					 | 
				
			||||||
/// See: https://docs.microsoft.com/windows/win32/api/dwmapi/ne-dwmapi-dwmwindowattribute
 | 
					 | 
				
			||||||
#ifndef DWMWA_USE_IMMERSIVE_DARK_MODE
 | 
					 | 
				
			||||||
#define DWMWA_USE_IMMERSIVE_DARK_MODE 20
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
constexpr const wchar_t kWindowClassName[] = L"FLUTTER_RUNNER_WIN32_WINDOW";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// Registry key for app theme preference.
 | 
					 | 
				
			||||||
///
 | 
					 | 
				
			||||||
/// A value of 0 indicates apps should use dark mode. A non-zero or missing
 | 
					 | 
				
			||||||
/// value indicates apps should use light mode.
 | 
					 | 
				
			||||||
constexpr const wchar_t kGetPreferredBrightnessRegKey[] =
 | 
					 | 
				
			||||||
  L"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize";
 | 
					 | 
				
			||||||
constexpr const wchar_t kGetPreferredBrightnessRegValue[] = L"AppsUseLightTheme";
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// The number of Win32Window objects that currently exist.
 | 
					 | 
				
			||||||
static int g_active_window_count = 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
using EnableNonClientDpiScaling = BOOL __stdcall(HWND hwnd);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Scale helper to convert logical scaler values to physical using passed in
 | 
					 | 
				
			||||||
// scale factor
 | 
					 | 
				
			||||||
int Scale(int source, double scale_factor) {
 | 
					 | 
				
			||||||
  return static_cast<int>(source * scale_factor);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Dynamically loads the |EnableNonClientDpiScaling| from the User32 module.
 | 
					 | 
				
			||||||
// This API is only needed for PerMonitor V1 awareness mode.
 | 
					 | 
				
			||||||
void EnableFullDpiSupportIfAvailable(HWND hwnd) {
 | 
					 | 
				
			||||||
  HMODULE user32_module = LoadLibraryA("User32.dll");
 | 
					 | 
				
			||||||
  if (!user32_module) {
 | 
					 | 
				
			||||||
    return;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  auto enable_non_client_dpi_scaling =
 | 
					 | 
				
			||||||
      reinterpret_cast<EnableNonClientDpiScaling*>(
 | 
					 | 
				
			||||||
          GetProcAddress(user32_module, "EnableNonClientDpiScaling"));
 | 
					 | 
				
			||||||
  if (enable_non_client_dpi_scaling != nullptr) {
 | 
					 | 
				
			||||||
    enable_non_client_dpi_scaling(hwnd);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  FreeLibrary(user32_module);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
}  // namespace
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Manages the Win32Window's window class registration.
 | 
					 | 
				
			||||||
class WindowClassRegistrar {
 | 
					 | 
				
			||||||
 public:
 | 
					 | 
				
			||||||
  ~WindowClassRegistrar() = default;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Returns the singleton registrar instance.
 | 
					 | 
				
			||||||
  static WindowClassRegistrar* GetInstance() {
 | 
					 | 
				
			||||||
    if (!instance_) {
 | 
					 | 
				
			||||||
      instance_ = new WindowClassRegistrar();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    return instance_;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Returns the name of the window class, registering the class if it hasn't
 | 
					 | 
				
			||||||
  // previously been registered.
 | 
					 | 
				
			||||||
  const wchar_t* GetWindowClass();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Unregisters the window class. Should only be called if there are no
 | 
					 | 
				
			||||||
  // instances of the window.
 | 
					 | 
				
			||||||
  void UnregisterWindowClass();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 private:
 | 
					 | 
				
			||||||
  WindowClassRegistrar() = default;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  static WindowClassRegistrar* instance_;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  bool class_registered_ = false;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
WindowClassRegistrar* WindowClassRegistrar::instance_ = nullptr;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const wchar_t* WindowClassRegistrar::GetWindowClass() {
 | 
					 | 
				
			||||||
  if (!class_registered_) {
 | 
					 | 
				
			||||||
    WNDCLASS window_class{};
 | 
					 | 
				
			||||||
    window_class.hCursor = LoadCursor(nullptr, IDC_ARROW);
 | 
					 | 
				
			||||||
    window_class.lpszClassName = kWindowClassName;
 | 
					 | 
				
			||||||
    window_class.style = CS_HREDRAW | CS_VREDRAW;
 | 
					 | 
				
			||||||
    window_class.cbClsExtra = 0;
 | 
					 | 
				
			||||||
    window_class.cbWndExtra = 0;
 | 
					 | 
				
			||||||
    window_class.hInstance = GetModuleHandle(nullptr);
 | 
					 | 
				
			||||||
    window_class.hIcon =
 | 
					 | 
				
			||||||
        LoadIcon(window_class.hInstance, MAKEINTRESOURCE(IDI_APP_ICON));
 | 
					 | 
				
			||||||
    window_class.hbrBackground = 0;
 | 
					 | 
				
			||||||
    window_class.lpszMenuName = nullptr;
 | 
					 | 
				
			||||||
    window_class.lpfnWndProc = Win32Window::WndProc;
 | 
					 | 
				
			||||||
    RegisterClass(&window_class);
 | 
					 | 
				
			||||||
    class_registered_ = true;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  return kWindowClassName;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void WindowClassRegistrar::UnregisterWindowClass() {
 | 
					 | 
				
			||||||
  UnregisterClass(kWindowClassName, nullptr);
 | 
					 | 
				
			||||||
  class_registered_ = false;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Win32Window::Win32Window() {
 | 
					 | 
				
			||||||
  ++g_active_window_count;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Win32Window::~Win32Window() {
 | 
					 | 
				
			||||||
  --g_active_window_count;
 | 
					 | 
				
			||||||
  Destroy();
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
bool Win32Window::Create(const std::wstring& title,
 | 
					 | 
				
			||||||
                         const Point& origin,
 | 
					 | 
				
			||||||
                         const Size& size) {
 | 
					 | 
				
			||||||
  Destroy();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const wchar_t* window_class =
 | 
					 | 
				
			||||||
      WindowClassRegistrar::GetInstance()->GetWindowClass();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  const POINT target_point = {static_cast<LONG>(origin.x),
 | 
					 | 
				
			||||||
                              static_cast<LONG>(origin.y)};
 | 
					 | 
				
			||||||
  HMONITOR monitor = MonitorFromPoint(target_point, MONITOR_DEFAULTTONEAREST);
 | 
					 | 
				
			||||||
  UINT dpi = FlutterDesktopGetDpiForMonitor(monitor);
 | 
					 | 
				
			||||||
  double scale_factor = dpi / 96.0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  HWND window = CreateWindow(
 | 
					 | 
				
			||||||
      window_class, title.c_str(), WS_OVERLAPPEDWINDOW,
 | 
					 | 
				
			||||||
      Scale(origin.x, scale_factor), Scale(origin.y, scale_factor),
 | 
					 | 
				
			||||||
      Scale(size.width, scale_factor), Scale(size.height, scale_factor),
 | 
					 | 
				
			||||||
      nullptr, nullptr, GetModuleHandle(nullptr), this);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  if (!window) {
 | 
					 | 
				
			||||||
    return false;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  UpdateTheme(window);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return OnCreate();
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
bool Win32Window::Show() {
 | 
					 | 
				
			||||||
  return ShowWindow(window_handle_, SW_SHOWNORMAL);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// static
 | 
					 | 
				
			||||||
LRESULT CALLBACK Win32Window::WndProc(HWND const window,
 | 
					 | 
				
			||||||
                                      UINT const message,
 | 
					 | 
				
			||||||
                                      WPARAM const wparam,
 | 
					 | 
				
			||||||
                                      LPARAM const lparam) noexcept {
 | 
					 | 
				
			||||||
  if (message == WM_NCCREATE) {
 | 
					 | 
				
			||||||
    auto window_struct = reinterpret_cast<CREATESTRUCT*>(lparam);
 | 
					 | 
				
			||||||
    SetWindowLongPtr(window, GWLP_USERDATA,
 | 
					 | 
				
			||||||
                     reinterpret_cast<LONG_PTR>(window_struct->lpCreateParams));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    auto that = static_cast<Win32Window*>(window_struct->lpCreateParams);
 | 
					 | 
				
			||||||
    EnableFullDpiSupportIfAvailable(window);
 | 
					 | 
				
			||||||
    that->window_handle_ = window;
 | 
					 | 
				
			||||||
  } else if (Win32Window* that = GetThisFromHandle(window)) {
 | 
					 | 
				
			||||||
    return that->MessageHandler(window, message, wparam, lparam);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return DefWindowProc(window, message, wparam, lparam);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
LRESULT
 | 
					 | 
				
			||||||
Win32Window::MessageHandler(HWND hwnd,
 | 
					 | 
				
			||||||
                            UINT const message,
 | 
					 | 
				
			||||||
                            WPARAM const wparam,
 | 
					 | 
				
			||||||
                            LPARAM const lparam) noexcept {
 | 
					 | 
				
			||||||
  switch (message) {
 | 
					 | 
				
			||||||
    case WM_DESTROY:
 | 
					 | 
				
			||||||
      window_handle_ = nullptr;
 | 
					 | 
				
			||||||
      Destroy();
 | 
					 | 
				
			||||||
      if (quit_on_close_) {
 | 
					 | 
				
			||||||
        PostQuitMessage(0);
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
      return 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    case WM_DPICHANGED: {
 | 
					 | 
				
			||||||
      auto newRectSize = reinterpret_cast<RECT*>(lparam);
 | 
					 | 
				
			||||||
      LONG newWidth = newRectSize->right - newRectSize->left;
 | 
					 | 
				
			||||||
      LONG newHeight = newRectSize->bottom - newRectSize->top;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      SetWindowPos(hwnd, nullptr, newRectSize->left, newRectSize->top, newWidth,
 | 
					 | 
				
			||||||
                   newHeight, SWP_NOZORDER | SWP_NOACTIVATE);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      return 0;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    case WM_SIZE: {
 | 
					 | 
				
			||||||
      RECT rect = GetClientArea();
 | 
					 | 
				
			||||||
      if (child_content_ != nullptr) {
 | 
					 | 
				
			||||||
        // Size and position the child window.
 | 
					 | 
				
			||||||
        MoveWindow(child_content_, rect.left, rect.top, rect.right - rect.left,
 | 
					 | 
				
			||||||
                   rect.bottom - rect.top, TRUE);
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
      return 0;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    case WM_ACTIVATE:
 | 
					 | 
				
			||||||
      if (child_content_ != nullptr) {
 | 
					 | 
				
			||||||
        SetFocus(child_content_);
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
      return 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    case WM_DWMCOLORIZATIONCOLORCHANGED:
 | 
					 | 
				
			||||||
      UpdateTheme(hwnd);
 | 
					 | 
				
			||||||
      return 0;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return DefWindowProc(window_handle_, message, wparam, lparam);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void Win32Window::Destroy() {
 | 
					 | 
				
			||||||
  OnDestroy();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  if (window_handle_) {
 | 
					 | 
				
			||||||
    DestroyWindow(window_handle_);
 | 
					 | 
				
			||||||
    window_handle_ = nullptr;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  if (g_active_window_count == 0) {
 | 
					 | 
				
			||||||
    WindowClassRegistrar::GetInstance()->UnregisterWindowClass();
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Win32Window* Win32Window::GetThisFromHandle(HWND const window) noexcept {
 | 
					 | 
				
			||||||
  return reinterpret_cast<Win32Window*>(
 | 
					 | 
				
			||||||
      GetWindowLongPtr(window, GWLP_USERDATA));
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void Win32Window::SetChildContent(HWND content) {
 | 
					 | 
				
			||||||
  child_content_ = content;
 | 
					 | 
				
			||||||
  SetParent(content, window_handle_);
 | 
					 | 
				
			||||||
  RECT frame = GetClientArea();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  MoveWindow(content, frame.left, frame.top, frame.right - frame.left,
 | 
					 | 
				
			||||||
             frame.bottom - frame.top, true);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  SetFocus(child_content_);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
RECT Win32Window::GetClientArea() {
 | 
					 | 
				
			||||||
  RECT frame;
 | 
					 | 
				
			||||||
  GetClientRect(window_handle_, &frame);
 | 
					 | 
				
			||||||
  return frame;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
HWND Win32Window::GetHandle() {
 | 
					 | 
				
			||||||
  return window_handle_;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void Win32Window::SetQuitOnClose(bool quit_on_close) {
 | 
					 | 
				
			||||||
  quit_on_close_ = quit_on_close;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
bool Win32Window::OnCreate() {
 | 
					 | 
				
			||||||
  // No-op; provided for subclasses.
 | 
					 | 
				
			||||||
  return true;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void Win32Window::OnDestroy() {
 | 
					 | 
				
			||||||
  // No-op; provided for subclasses.
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void Win32Window::UpdateTheme(HWND const window) {
 | 
					 | 
				
			||||||
  DWORD light_mode;
 | 
					 | 
				
			||||||
  DWORD light_mode_size = sizeof(light_mode);
 | 
					 | 
				
			||||||
  LSTATUS result = RegGetValue(HKEY_CURRENT_USER, kGetPreferredBrightnessRegKey,
 | 
					 | 
				
			||||||
                               kGetPreferredBrightnessRegValue,
 | 
					 | 
				
			||||||
                               RRF_RT_REG_DWORD, nullptr, &light_mode,
 | 
					 | 
				
			||||||
                               &light_mode_size);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  if (result == ERROR_SUCCESS) {
 | 
					 | 
				
			||||||
    BOOL enable_dark_mode = light_mode == 0;
 | 
					 | 
				
			||||||
    DwmSetWindowAttribute(window, DWMWA_USE_IMMERSIVE_DARK_MODE,
 | 
					 | 
				
			||||||
                          &enable_dark_mode, sizeof(enable_dark_mode));
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -1,102 +0,0 @@
 | 
				
			|||||||
#ifndef RUNNER_WIN32_WINDOW_H_
 | 
					 | 
				
			||||||
#define RUNNER_WIN32_WINDOW_H_
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <windows.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <functional>
 | 
					 | 
				
			||||||
#include <memory>
 | 
					 | 
				
			||||||
#include <string>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// A class abstraction for a high DPI-aware Win32 Window. Intended to be
 | 
					 | 
				
			||||||
// inherited from by classes that wish to specialize with custom
 | 
					 | 
				
			||||||
// rendering and input handling
 | 
					 | 
				
			||||||
class Win32Window {
 | 
					 | 
				
			||||||
 public:
 | 
					 | 
				
			||||||
  struct Point {
 | 
					 | 
				
			||||||
    unsigned int x;
 | 
					 | 
				
			||||||
    unsigned int y;
 | 
					 | 
				
			||||||
    Point(unsigned int x, unsigned int y) : x(x), y(y) {}
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  struct Size {
 | 
					 | 
				
			||||||
    unsigned int width;
 | 
					 | 
				
			||||||
    unsigned int height;
 | 
					 | 
				
			||||||
    Size(unsigned int width, unsigned int height)
 | 
					 | 
				
			||||||
        : width(width), height(height) {}
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  Win32Window();
 | 
					 | 
				
			||||||
  virtual ~Win32Window();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Creates a win32 window with |title| that is positioned and sized using
 | 
					 | 
				
			||||||
  // |origin| and |size|. New windows are created on the default monitor. Window
 | 
					 | 
				
			||||||
  // sizes are specified to the OS in physical pixels, hence to ensure a
 | 
					 | 
				
			||||||
  // consistent size this function will scale the inputted width and height as
 | 
					 | 
				
			||||||
  // as appropriate for the default monitor. The window is invisible until
 | 
					 | 
				
			||||||
  // |Show| is called. Returns true if the window was created successfully.
 | 
					 | 
				
			||||||
  bool Create(const std::wstring& title, const Point& origin, const Size& size);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Show the current window. Returns true if the window was successfully shown.
 | 
					 | 
				
			||||||
  bool Show();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Release OS resources associated with window.
 | 
					 | 
				
			||||||
  void Destroy();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Inserts |content| into the window tree.
 | 
					 | 
				
			||||||
  void SetChildContent(HWND content);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Returns the backing Window handle to enable clients to set icon and other
 | 
					 | 
				
			||||||
  // window properties. Returns nullptr if the window has been destroyed.
 | 
					 | 
				
			||||||
  HWND GetHandle();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // If true, closing this window will quit the application.
 | 
					 | 
				
			||||||
  void SetQuitOnClose(bool quit_on_close);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Return a RECT representing the bounds of the current client area.
 | 
					 | 
				
			||||||
  RECT GetClientArea();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 protected:
 | 
					 | 
				
			||||||
  // Processes and route salient window messages for mouse handling,
 | 
					 | 
				
			||||||
  // size change and DPI. Delegates handling of these to member overloads that
 | 
					 | 
				
			||||||
  // inheriting classes can handle.
 | 
					 | 
				
			||||||
  virtual LRESULT MessageHandler(HWND window,
 | 
					 | 
				
			||||||
                                 UINT const message,
 | 
					 | 
				
			||||||
                                 WPARAM const wparam,
 | 
					 | 
				
			||||||
                                 LPARAM const lparam) noexcept;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Called when CreateAndShow is called, allowing subclass window-related
 | 
					 | 
				
			||||||
  // setup. Subclasses should return false if setup fails.
 | 
					 | 
				
			||||||
  virtual bool OnCreate();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Called when Destroy is called.
 | 
					 | 
				
			||||||
  virtual void OnDestroy();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 private:
 | 
					 | 
				
			||||||
  friend class WindowClassRegistrar;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // OS callback called by message pump. Handles the WM_NCCREATE message which
 | 
					 | 
				
			||||||
  // is passed when the non-client area is being created and enables automatic
 | 
					 | 
				
			||||||
  // non-client DPI scaling so that the non-client area automatically
 | 
					 | 
				
			||||||
  // responds to changes in DPI. All other messages are handled by
 | 
					 | 
				
			||||||
  // MessageHandler.
 | 
					 | 
				
			||||||
  static LRESULT CALLBACK WndProc(HWND const window,
 | 
					 | 
				
			||||||
                                  UINT const message,
 | 
					 | 
				
			||||||
                                  WPARAM const wparam,
 | 
					 | 
				
			||||||
                                  LPARAM const lparam) noexcept;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Retrieves a class instance pointer for |window|
 | 
					 | 
				
			||||||
  static Win32Window* GetThisFromHandle(HWND const window) noexcept;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Update the window frame's theme to match the system theme.
 | 
					 | 
				
			||||||
  static void UpdateTheme(HWND const window);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  bool quit_on_close_ = false;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // window handle for top level window.
 | 
					 | 
				
			||||||
  HWND window_handle_ = nullptr;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // window handle for hosted content.
 | 
					 | 
				
			||||||
  HWND child_content_ = nullptr;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#endif  // RUNNER_WIN32_WINDOW_H_
 | 
					 | 
				
			||||||