Compare commits
14 Commits
v1.1.4+34
...
v1.1.13+43
Author | SHA1 | Date | |
---|---|---|---|
f75299f0d4 | |||
03c6431eca | |||
5876c809a5 | |||
c35308fbc1 | |||
e945844151 | |||
74eb6e3d26 | |||
9755066d1e | |||
671b3cfbe0 | |||
93fb3536ee | |||
346e447d5e | |||
f7777821fd | |||
ffbde73300 | |||
836a0886e2 | |||
1cd10b3809 |
@ -51,3 +51,6 @@ jobs:
|
||||
files: |-
|
||||
build/app/outputs/flutter-apk/app-release.apk
|
||||
token: '${{secrets.RELEASE_TOKEN}}'
|
||||
|
||||
- name: trigger fdroid puller
|
||||
run: curl https://flumm.io/pullfdroid.php?token=${{secrets.PULLER_TOKEN}}
|
||||
|
21
LICENSE
Normal file
@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2025 f0ck
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
52
README.md
@ -1,16 +1,48 @@
|
||||
# f0ckapp
|
||||
# fApp
|
||||

|
||||
## Overview
|
||||
|
||||
A new Flutter project.
|
||||
fApp is the mobile application for the website [f0ck.me](https://f0ck.me). This app provides a user-friendly interface to access the content of the website and utilize its features conveniently from your mobile device.
|
||||
|
||||
## Getting Started
|
||||
## Installation
|
||||
|
||||
This project is a starting point for a Flutter application.
|
||||
fApp is available in its own F-Droid repository.
|
||||
|
||||
A few resources to get you started if this is your first Flutter project:
|
||||
### Installation Steps
|
||||
|
||||
- [Lab: Write your first Flutter app](https://docs.flutter.dev/get-started/codelab)
|
||||
- [Cookbook: Useful Flutter samples](https://docs.flutter.dev/cookbook)
|
||||
1. Add the F-Droid repository to your F-Droid app:
|
||||
- Go to the settings in the F-Droid app.
|
||||
- Select "Repositories" and add the URL `https://fdroid.flumm.io/fdroid/repo/`.
|
||||
|
||||
For help getting started with Flutter development, view the
|
||||
[online documentation](https://docs.flutter.dev/), which offers tutorials,
|
||||
samples, guidance on mobile development, and a full API reference.
|
||||
2. Search for "f0ckapp" in the F-Droid app and install the app.
|
||||
|
||||
## Development
|
||||
|
||||
### Prerequisites
|
||||
|
||||
- Flutter SDK
|
||||
- Dart SDK
|
||||
- Android Studio or Visual Studio Code
|
||||
|
||||
### Setting Up the Project
|
||||
|
||||
1. Clone the repository:
|
||||
```bash
|
||||
git clone https://git.lat/f0ck/fApp.git
|
||||
cd fApp
|
||||
2. Install dependencies:
|
||||
```flutter pub get```
|
||||
3. Run the app:
|
||||
```flutter run```
|
||||
|
||||
### Contributing
|
||||
|
||||
don't.
|
||||
|
||||
### License
|
||||
|
||||
This project is licensed under the MIT License. See the LICENSE file for more information.
|
||||
|
||||
### Contact
|
||||
|
||||
For questions or feedback, you can reach us at [contact@f0ck.me](mailto:contact@f0ck.me).
|
||||
|
@ -1,11 +1,11 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<uses-permission android:name="android.permission.INTERNET"/>
|
||||
|
||||
<uses-permission android:name="android.permission.WAKE_LOCK"/>
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
|
||||
<application
|
||||
android:label="f0ckapp"
|
||||
android:name="${applicationName}"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:roundIcon="@mipmap/ic_launcher_round"
|
||||
android:enableOnBackInvokedCallback="true">
|
||||
<activity
|
||||
android:name=".MainActivity"
|
||||
@ -15,8 +15,7 @@
|
||||
android:theme="@style/LaunchTheme"
|
||||
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
|
||||
android:hardwareAccelerated="true"
|
||||
android:windowSoftInputMode="adjustResize"
|
||||
android:requestLegacyExternalStorage="true">
|
||||
android:windowSoftInputMode="adjustResize">
|
||||
<!-- Specifies an Android theme to apply to this Activity as soon as
|
||||
the Android process has started. This theme is visible to the user
|
||||
while the Flutter UI initializes. After that, this theme continues
|
||||
@ -29,12 +28,26 @@
|
||||
<action android:name="android.intent.action.MAIN"/>
|
||||
<category android:name="android.intent.category.LAUNCHER"/>
|
||||
</intent-filter>
|
||||
<meta-data android:name="flutter_deeplinking_enabled" android:value="false"/>
|
||||
<intent-filter android:autoVerify="true">
|
||||
<action android:name="android.intent.action.VIEW"/>
|
||||
<category android:name="android.intent.category.DEFAULT"/>
|
||||
<category android:name="android.intent.category.BROWSABLE"/>
|
||||
<data android:scheme="https" android:host="f0ck.me"/>
|
||||
</intent-filter>
|
||||
<intent-filter android:autoVerify="true">
|
||||
<action android:name="android.intent.action.VIEW"/>
|
||||
<category android:name="android.intent.category.DEFAULT"/>
|
||||
<category android:name="android.intent.category.BROWSABLE"/>
|
||||
<data android:scheme="f0ck" android:host="com.f0ck.f0ckapp"/>
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<!-- Don't delete the meta-data below.
|
||||
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
|
||||
<meta-data
|
||||
android:name="flutterEmbedding"
|
||||
android:value="2" />
|
||||
|
||||
</application>
|
||||
<!-- Required to query activities that can process text, see:
|
||||
https://developer.android.com/training/package-visibility and
|
||||
|
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@mipmap/ic_launcher_background"/>
|
||||
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
|
||||
<monochrome android:drawable="@mipmap/ic_launcher_monochrome"/>
|
||||
</adaptive-icon>
|
BIN
android/app/src/main/res/mipmap-hdpi/ic_launcher.png
Normal file
After Width: | Height: | Size: 9.5 KiB |
Before Width: | Height: | Size: 3.5 KiB |
BIN
android/app/src/main/res/mipmap-hdpi/ic_launcher_background.png
Normal file
After Width: | Height: | Size: 839 B |
BIN
android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png
Normal file
After Width: | Height: | Size: 22 KiB |
BIN
android/app/src/main/res/mipmap-hdpi/ic_launcher_monochrome.png
Normal file
After Width: | Height: | Size: 22 KiB |
Before Width: | Height: | Size: 4.5 KiB |
BIN
android/app/src/main/res/mipmap-mdpi/ic_launcher.png
Normal file
After Width: | Height: | Size: 5.0 KiB |
Before Width: | Height: | Size: 1.9 KiB |
BIN
android/app/src/main/res/mipmap-mdpi/ic_launcher_background.png
Normal file
After Width: | Height: | Size: 446 B |
BIN
android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
android/app/src/main/res/mipmap-mdpi/ic_launcher_monochrome.png
Normal file
After Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 2.4 KiB |
BIN
android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
Normal file
After Width: | Height: | Size: 15 KiB |
Before Width: | Height: | Size: 5.2 KiB |
BIN
android/app/src/main/res/mipmap-xhdpi/ic_launcher_background.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png
Normal file
After Width: | Height: | Size: 38 KiB |
BIN
android/app/src/main/res/mipmap-xhdpi/ic_launcher_monochrome.png
Normal file
After Width: | Height: | Size: 38 KiB |
Before Width: | Height: | Size: 6.4 KiB |
BIN
android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
Normal file
After Width: | Height: | Size: 30 KiB |
Before Width: | Height: | Size: 9.6 KiB |
After Width: | Height: | Size: 2.9 KiB |
After Width: | Height: | Size: 75 KiB |
After Width: | Height: | Size: 75 KiB |
Before Width: | Height: | Size: 11 KiB |
BIN
android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
Normal file
After Width: | Height: | Size: 48 KiB |
Before Width: | Height: | Size: 15 KiB |
After Width: | Height: | Size: 4.1 KiB |
After Width: | Height: | Size: 133 KiB |
After Width: | Height: | Size: 133 KiB |
Before Width: | Height: | Size: 17 KiB |
BIN
android/app/src/main/res/play_store_512.png
Normal file
After Width: | Height: | Size: 345 KiB |
Before Width: | Height: | Size: 16 KiB |
Before Width: | Height: | Size: 16 KiB |
Before Width: | Height: | Size: 447 KiB |
Before Width: | Height: | Size: 18 KiB |
Before Width: | Height: | Size: 20 KiB |
Before Width: | Height: | Size: 21 KiB |
Before Width: | Height: | Size: 23 KiB |
Before Width: | Height: | Size: 28 KiB |
Before Width: | Height: | Size: 31 KiB |
Before Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 35 KiB |
Before Width: | Height: | Size: 38 KiB |
Before Width: | Height: | Size: 40 KiB |
Before Width: | Height: | Size: 47 KiB |
Before Width: | Height: | Size: 1.8 KiB |
Before Width: | Height: | Size: 53 KiB |
Before Width: | Height: | Size: 62 KiB |
Before Width: | Height: | Size: 68 KiB |
Before Width: | Height: | Size: 72 KiB |
Before Width: | Height: | Size: 2.8 KiB |
Before Width: | Height: | Size: 2.8 KiB |
Before Width: | Height: | Size: 3.8 KiB |
Before Width: | Height: | Size: 5.0 KiB |
Before Width: | Height: | Size: 5.7 KiB |
Before Width: | Height: | Size: 192 KiB |
Before Width: | Height: | Size: 6.1 KiB |
Before Width: | Height: | Size: 6.6 KiB |
Before Width: | Height: | Size: 6.9 KiB |
Before Width: | Height: | Size: 7.3 KiB |
Before Width: | Height: | Size: 7.7 KiB |
Before Width: | Height: | Size: 8.7 KiB |
Before Width: | Height: | Size: 9.0 KiB |
Before Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 10 KiB |
Before Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 14 KiB |
BIN
ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-20@2x.png
Normal file
After Width: | Height: | Size: 3.7 KiB |
After Width: | Height: | Size: 3.7 KiB |
BIN
ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-20@3x.png
Normal file
After Width: | Height: | Size: 7.4 KiB |
After Width: | Height: | Size: 1.2 KiB |
BIN
ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-29.png
Normal file
After Width: | Height: | Size: 2.2 KiB |
BIN
ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-29@2x.png
Normal file
After Width: | Height: | Size: 7.0 KiB |
After Width: | Height: | Size: 7.0 KiB |
BIN
ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-29@3x.png
Normal file
After Width: | Height: | Size: 14 KiB |
After Width: | Height: | Size: 2.2 KiB |
BIN
ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-40@2x.png
Normal file
After Width: | Height: | Size: 12 KiB |
After Width: | Height: | Size: 12 KiB |
BIN
ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-40@3x.png
Normal file
After Width: | Height: | Size: 23 KiB |
After Width: | Height: | Size: 3.7 KiB |
After Width: | Height: | Size: 23 KiB |
After Width: | Height: | Size: 49 KiB |
After Width: | Height: | Size: 43 KiB |
BIN
ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon@2x.png
Normal file
After Width: | Height: | Size: 23 KiB |
After Width: | Height: | Size: 36 KiB |
BIN
ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon@3x.png
Normal file
After Width: | Height: | Size: 49 KiB |
After Width: | Height: | Size: 1.1 MiB |
BIN
ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon~ipad.png
Normal file
After Width: | Height: | Size: 11 KiB |
@ -1,33 +1,87 @@
|
||||
import 'package:f0ckapp/providers/media_provider.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
import 'package:f0ckapp/screens/MediaGrid.dart';
|
||||
import 'package:f0ckapp/utils/AppVersion.dart';
|
||||
import 'package:f0ckapp/providers/ThemeProvider.dart';
|
||||
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
|
||||
import 'package:f0ckapp/screens/mediagrid_screen.dart';
|
||||
import 'package:f0ckapp/screens/detailview_screen.dart';
|
||||
import 'package:f0ckapp/utils/appversion_util.dart';
|
||||
import 'package:f0ckapp/providers/theme_provider.dart';
|
||||
|
||||
void main() async {
|
||||
WidgetsFlutterBinding.ensureInitialized();
|
||||
await SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]);
|
||||
await AppVersion.init();
|
||||
|
||||
runApp(ProviderScope(child: const F0ckApp()));
|
||||
runApp(ProviderScope(child: F0ckApp()));
|
||||
}
|
||||
|
||||
class F0ckApp extends ConsumerWidget {
|
||||
const F0ckApp({super.key});
|
||||
F0ckApp({super.key});
|
||||
|
||||
final GoRouter _router = GoRouter(
|
||||
initialLocation: '/',
|
||||
routes: [
|
||||
GoRoute(
|
||||
path: '/',
|
||||
builder: (BuildContext context, GoRouterState state) {
|
||||
return const MediaGrid();
|
||||
},
|
||||
),
|
||||
GoRoute(
|
||||
path: '/:rest(.*)',
|
||||
builder: (context, state) {
|
||||
final bool isInternalLink = (state.extra is bool && state.extra == true);
|
||||
final String fullPath = state.matchedLocation;
|
||||
|
||||
final regExp = RegExp(
|
||||
r'^(?:/tag/(?<tag>.+?))?(?:/(?<mime>image|audio|video))?(?:/(?<itemid>\d+))?$',
|
||||
);
|
||||
final RegExpMatch? match = regExp.firstMatch(fullPath);
|
||||
|
||||
if (match == null) {
|
||||
return const Scaffold(body: Center(child: Text('Ungültiger Link')));
|
||||
}
|
||||
|
||||
final String? tag = match.namedGroup('tag');
|
||||
final String? mime = match.namedGroup('mime');
|
||||
final String? idStr = match.namedGroup('itemid');
|
||||
final int? itemId = idStr != null ? int.tryParse(idStr) : null;
|
||||
const int preloadOffset = 50;
|
||||
|
||||
return Consumer(
|
||||
builder: (BuildContext context, WidgetRef ref, Widget? child) {
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) async {
|
||||
final MediaNotifier mediaNotifier = ref.read(mediaProvider.notifier);
|
||||
if (!isInternalLink) {
|
||||
mediaNotifier.setType(mime ?? "alles");
|
||||
mediaNotifier.setTag(tag);
|
||||
}
|
||||
if (itemId != null) {
|
||||
await mediaNotifier.loadMedia(id: itemId + preloadOffset);
|
||||
}
|
||||
});
|
||||
if (itemId != null) {
|
||||
return DetailView(initialItemId: itemId);
|
||||
} else {
|
||||
return MediaGrid();
|
||||
}
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
return Consumer(
|
||||
builder: (context, ref, _) {
|
||||
return MaterialApp(
|
||||
debugShowCheckedModeBanner: false,
|
||||
theme: ref.watch(themeNotifierProvider),
|
||||
home: const MediaGrid(),
|
||||
);
|
||||
},
|
||||
final ThemeData theme = ref.watch(themeNotifierProvider);
|
||||
return MaterialApp.router(
|
||||
debugShowCheckedModeBanner: false,
|
||||
routerConfig: _router,
|
||||
theme: theme,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
19
lib/models/suggestion_model.dart
Normal file
@ -0,0 +1,19 @@
|
||||
class Suggestion {
|
||||
final String tag;
|
||||
final int tagged;
|
||||
final double score;
|
||||
|
||||
Suggestion({
|
||||
required this.tag,
|
||||
required this.tagged,
|
||||
required this.score,
|
||||
});
|
||||
|
||||
factory Suggestion.fromJson(Map<String, dynamic> json) {
|
||||
return Suggestion(
|
||||
tag: json['tag'].toString(),
|
||||
tagged: json['tagged'],
|
||||
score: (json['score'] as num).toDouble(),
|
||||
);
|
||||
}
|
||||
}
|
@ -1,8 +1,8 @@
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
||||
|
||||
import 'package:f0ckapp/models/MediaItem.dart';
|
||||
import 'package:f0ckapp/services/Api.dart';
|
||||
import 'package:f0ckapp/models/mediaitem_model.dart';
|
||||
import 'package:f0ckapp/services/api_service.dart';
|
||||
|
||||
const List<String> mediaTypes = ["alles", "image", "video", "audio"];
|
||||
const List<String> mediaModes = ["sfw", "nsfw", "untagged", "all"];
|
||||
@ -102,18 +102,25 @@ class MediaNotifier extends StateNotifier<MediaState> {
|
||||
}
|
||||
|
||||
void addMediaItems(List<MediaItem> newItems) {
|
||||
final updated = List<MediaItem>.from(state.mediaItems)..addAll(newItems);
|
||||
state = state.replace(mediaItems: updated);
|
||||
final Set<int> existingIds = state.mediaItems
|
||||
.map((item) => item.id)
|
||||
.toSet();
|
||||
final List<MediaItem> filteredItems = newItems
|
||||
.where((item) => !existingIds.contains(item.id))
|
||||
.toList();
|
||||
if (filteredItems.isNotEmpty) {
|
||||
final List<MediaItem> updated = List<MediaItem>.from(state.mediaItems)
|
||||
..addAll(filteredItems);
|
||||
state = state.replace(mediaItems: updated);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> loadMedia() async {
|
||||
Future<void> loadMedia({int? id}) async {
|
||||
if (state.isLoading) return;
|
||||
|
||||
state = state.replace(isLoading: true);
|
||||
try {
|
||||
final older = state.mediaItems.isNotEmpty
|
||||
? state.mediaItems.last.id
|
||||
: null;
|
||||
final older =
|
||||
id ?? (state.mediaItems.isNotEmpty ? state.mediaItems.last.id : null);
|
||||
final newMedia = await fetchMedia(
|
||||
older: older,
|
||||
type: mediaTypes[state.typeIndex],
|
@ -3,6 +3,17 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
|
||||
final Map<String, ThemeData> themeMap = {
|
||||
'f0ck': f0ckTheme,
|
||||
'P1nk': p1nkTheme, // done
|
||||
'Orange': orangeTheme,
|
||||
'Amoled': amoledTheme,
|
||||
'Paper': paperTheme,
|
||||
//'Iced': icedTheme,
|
||||
'f0ck95': f0ck95Theme,
|
||||
'f0ck95d': f0ck95dTheme,
|
||||
};
|
||||
|
||||
class ThemeNotifier extends StateNotifier<ThemeData> {
|
||||
final FlutterSecureStorage secureStorage;
|
||||
|
||||
@ -11,48 +22,37 @@ class ThemeNotifier extends StateNotifier<ThemeData> {
|
||||
}
|
||||
|
||||
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;
|
||||
try {
|
||||
String? savedThemeName = await secureStorage.read(key: 'theme');
|
||||
if (savedThemeName != null && themeMap.containsKey(savedThemeName)) {
|
||||
state = themeMap[savedThemeName]!;
|
||||
}
|
||||
} catch (error) {
|
||||
debugPrint('Fehler beim Laden des Themes: $error');
|
||||
state = f0ckTheme;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
try {
|
||||
await secureStorage.write(key: 'theme', value: themeName);
|
||||
state = themeMap[themeName] ?? f0ckTheme;
|
||||
} catch (error) {
|
||||
debugPrint('Fehler beim Aktualisieren des Themes: $error');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final themeNotifierProvider = StateNotifierProvider<ThemeNotifier, ThemeData>((
|
||||
ref,
|
||||
) {
|
||||
return ThemeNotifier(secureStorage: FlutterSecureStorage());
|
||||
return ThemeNotifier(
|
||||
secureStorage: const FlutterSecureStorage(
|
||||
aOptions: AndroidOptions(encryptedSharedPreferences: true),
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
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(
|
||||
brightness: Brightness.dark,
|
||||
primaryColor: const Color(0xFF9FFF00),
|
||||
@ -74,13 +74,53 @@ final ThemeData f0ckTheme = ThemeData(
|
||||
bodyLarge: TextStyle(color: Colors.white),
|
||||
bodyMedium: TextStyle(color: Colors.white),
|
||||
),
|
||||
buttonTheme: ButtonThemeData(
|
||||
buttonColor: const Color(0xFF9FFF00),
|
||||
textTheme: ButtonTextTheme.primary,
|
||||
elevatedButtonTheme: ElevatedButtonThemeData(
|
||||
style: ElevatedButton.styleFrom(
|
||||
foregroundColor: const Color(0xFF000000),
|
||||
backgroundColor: const Color(0xFF9FFF00),
|
||||
),
|
||||
),
|
||||
scrollbarTheme: ScrollbarThemeData(
|
||||
thumbColor: WidgetStatePropertyAll<Color>(Color(0xFF2B2B2B)),
|
||||
trackColor: WidgetStatePropertyAll<Color>(Color(0xFF424242)),
|
||||
thumbColor: WidgetStateProperty.all<Color>(const Color(0xFF2B2B2B)),
|
||||
trackColor: WidgetStateProperty.all<Color>(const Color(0xFF424242)),
|
||||
),
|
||||
);
|
||||
|
||||
final ThemeData p1nkTheme = ThemeData(
|
||||
brightness: Brightness.dark,
|
||||
primaryColor: const Color(0xFF171717),
|
||||
scaffoldBackgroundColor: const Color(0xFF171717),
|
||||
appBarTheme: const AppBarTheme(
|
||||
color: Color(0xFF2B2B2B),
|
||||
foregroundColor: Color(0xFFFF00D0),
|
||||
elevation: 2,
|
||||
),
|
||||
textTheme: const TextTheme(
|
||||
bodyLarge: TextStyle(color: Color(0xFFFFFFFF)),
|
||||
bodyMedium: TextStyle(color: Color(0xFFFFFFFF)),
|
||||
titleLarge: TextStyle(color: Color(0xFFFFFFFF)),
|
||||
),
|
||||
elevatedButtonTheme: ElevatedButtonThemeData(
|
||||
style: ElevatedButton.styleFrom(
|
||||
foregroundColor: const Color(0xFF000000),
|
||||
backgroundColor: const Color(0xFFFF00D0),
|
||||
),
|
||||
),
|
||||
progressIndicatorTheme: const ProgressIndicatorThemeData(
|
||||
color: Color(0xFFFF00D0),
|
||||
),
|
||||
scrollbarTheme: ScrollbarThemeData(
|
||||
thumbColor: WidgetStateProperty.all(const Color(0xFF2B2B2B)),
|
||||
trackColor: WidgetStateProperty.all(const Color(0xFF424242)),
|
||||
),
|
||||
colorScheme: const ColorScheme.dark(
|
||||
primary: Color(0xFF171717),
|
||||
secondary: Color(0xFFFF00D0),
|
||||
surface: Color(0xFF171717),
|
||||
onPrimary: Color(0xFFFFFFFF),
|
||||
onSecondary: Color(0xFF000000),
|
||||
onSurface: Color(0xFFFFFFFF),
|
||||
error: Color(0xFFA72828),
|
||||
),
|
||||
);
|
||||
|
||||
@ -105,9 +145,11 @@ final ThemeData paperTheme = ThemeData(
|
||||
bodyLarge: TextStyle(color: Color(0xFF000000)),
|
||||
bodyMedium: TextStyle(color: Color(0xFF000000)),
|
||||
),
|
||||
buttonTheme: ButtonThemeData(
|
||||
buttonColor: const Color(0xFF000000),
|
||||
textTheme: ButtonTextTheme.primary,
|
||||
elevatedButtonTheme: ElevatedButtonThemeData(
|
||||
style: ElevatedButton.styleFrom(
|
||||
foregroundColor: const Color(0xFFFFFFFF),
|
||||
backgroundColor: const Color(0xFF000000),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
@ -132,13 +174,15 @@ final ThemeData orangeTheme = ThemeData(
|
||||
bodyLarge: TextStyle(color: Colors.white),
|
||||
bodyMedium: TextStyle(color: Colors.white),
|
||||
),
|
||||
buttonTheme: ButtonThemeData(
|
||||
buttonColor: const Color(0xFFFF6F00),
|
||||
textTheme: ButtonTextTheme.primary,
|
||||
elevatedButtonTheme: ElevatedButtonThemeData(
|
||||
style: ElevatedButton.styleFrom(
|
||||
foregroundColor: Colors.white,
|
||||
backgroundColor: const Color(0xFFFF6F00),
|
||||
),
|
||||
),
|
||||
scrollbarTheme: ScrollbarThemeData(
|
||||
thumbColor: WidgetStatePropertyAll<Color>(Color(0xFF2B2B2B)),
|
||||
trackColor: WidgetStatePropertyAll<Color>(Color(0xFF424242)),
|
||||
thumbColor: WidgetStateProperty.all<Color>(const Color(0xFF2B2B2B)),
|
||||
trackColor: WidgetStateProperty.all<Color>(const Color(0xFF424242)),
|
||||
),
|
||||
);
|
||||
|
||||
@ -165,9 +209,11 @@ final ThemeData amoledTheme = ThemeData(
|
||||
bodyLarge: TextStyle(color: Colors.white),
|
||||
bodyMedium: TextStyle(color: Colors.white),
|
||||
),
|
||||
buttonTheme: ButtonThemeData(
|
||||
buttonColor: const Color(0xFFFFFFFF),
|
||||
textTheme: ButtonTextTheme.primary,
|
||||
elevatedButtonTheme: ElevatedButtonThemeData(
|
||||
style: ElevatedButton.styleFrom(
|
||||
foregroundColor: Colors.black,
|
||||
backgroundColor: const Color(0xFFFFFFFF),
|
||||
),
|
||||
),
|
||||
scrollbarTheme: ScrollbarThemeData(
|
||||
thumbColor: WidgetStateProperty.all<Color>(const Color(0xFF1D1C1C)),
|
||||
@ -195,13 +241,15 @@ final ThemeData f0ck95Theme = ThemeData(
|
||||
bodyLarge: TextStyle(color: Colors.black),
|
||||
bodyMedium: TextStyle(color: Colors.black),
|
||||
),
|
||||
buttonTheme: ButtonThemeData(
|
||||
buttonColor: Colors.black,
|
||||
textTheme: ButtonTextTheme.primary,
|
||||
elevatedButtonTheme: ElevatedButtonThemeData(
|
||||
style: ElevatedButton.styleFrom(
|
||||
foregroundColor: Colors.white,
|
||||
backgroundColor: Colors.black,
|
||||
),
|
||||
),
|
||||
scrollbarTheme: ScrollbarThemeData(
|
||||
thumbColor: WidgetStatePropertyAll<Color>(Color(0xFF2B2B2B)),
|
||||
trackColor: WidgetStatePropertyAll<Color>(Color(0xFF424242)),
|
||||
thumbColor: WidgetStateProperty.all<Color>(const Color(0xFF2B2B2B)),
|
||||
trackColor: WidgetStateProperty.all<Color>(const Color(0xFF424242)),
|
||||
),
|
||||
);
|
||||
|
||||
@ -225,12 +273,14 @@ final ThemeData f0ck95dTheme = ThemeData(
|
||||
bodyLarge: TextStyle(color: Colors.white),
|
||||
bodyMedium: TextStyle(color: Colors.white),
|
||||
),
|
||||
buttonTheme: ButtonThemeData(
|
||||
buttonColor: Colors.white,
|
||||
textTheme: ButtonTextTheme.primary,
|
||||
elevatedButtonTheme: ElevatedButtonThemeData(
|
||||
style: ElevatedButton.styleFrom(
|
||||
foregroundColor: Colors.black,
|
||||
backgroundColor: Colors.white,
|
||||
),
|
||||
),
|
||||
scrollbarTheme: ScrollbarThemeData(
|
||||
thumbColor: WidgetStatePropertyAll<Color>(Color(0xFF2B2B2B)),
|
||||
trackColor: WidgetStatePropertyAll<Color>(Color(0xFF424242)),
|
||||
thumbColor: WidgetStateProperty.all<Color>(const Color(0xFF2B2B2B)),
|
||||
trackColor: WidgetStateProperty.all<Color>(const Color(0xFF424242)),
|
||||
),
|
||||
);
|