- new appicon
- smartRefreshIndicator (https://github.com/flutter/flutter/issues/65356#issuecomment-2410727567)
This commit is contained in:
Flummi 2025-06-03 10:03:20 +02:00
parent e24a2122a5
commit 800df72a33
48 changed files with 206 additions and 185 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.2 KiB

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.5 KiB

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 9.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 680 KiB

After

Width:  |  Height:  |  Size: 447 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 906 B

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 43 KiB

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 45 KiB

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 55 KiB

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 63 KiB

After

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 71 KiB

After

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 82 KiB

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 83 KiB

After

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 KiB

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.3 KiB

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.8 KiB

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.2 KiB

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 234 KiB

After

Width:  |  Height:  |  Size: 192 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.3 KiB

After

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.7 KiB

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.0 KiB

After

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.4 KiB

After

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.4 KiB

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.9 KiB

After

Width:  |  Height:  |  Size: 8.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 9.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 14 KiB

View File

@ -15,6 +15,7 @@ class F0ckApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
theme: ThemeData(
scaffoldBackgroundColor: const Color.fromARGB(255, 23, 23, 23),
),

View File

@ -13,7 +13,7 @@ class MediaGrid extends StatefulWidget {
class _MediaGridState extends State<MediaGrid> {
final ScrollController _scrollController = ScrollController();
final String _version = '1.0.15';
final String _version = '1.0.17';
List<MediaItem> mediaItems = [];
bool isLoading = false;
Timer? _debounceTimer;

View File

@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
import 'package:f0ckapp/models/mediaitem.dart';
import 'package:f0ckapp/services/api.dart';
import 'package:f0ckapp/widgets/video_widget.dart';
import 'package:f0ckapp/utils/SmartRefreshIndicator.dart';
class DetailView extends StatefulWidget {
final int initialItemId;
@ -26,23 +27,23 @@ class DetailView extends StatefulWidget {
class _DetailViewState extends State<DetailView> {
late PageController _pageController;
late List<MediaItem> mediaItems;
final List<String> _modes = ["sfw", "nsfw", "untagged", "all"];
int currentItemId = 0;
bool isLoading = false;
@override
void initState() {
super.initState();
mediaItems = widget.mediaItems;
final initialIndex = mediaItems.indexWhere(
(item) => item.id == widget.initialItemId,
);
_pageController = PageController(initialPage: initialIndex);
currentItemId = mediaItems[initialIndex].id;
_pageController.addListener(() {
_pageController.addListener(_onPageScroll);
}
void _onPageScroll() {
final newIndex = _pageController.page?.round();
if (newIndex != null && newIndex < mediaItems.length) {
setState(() => currentItemId = mediaItems[newIndex].id);
@ -52,7 +53,6 @@ class _DetailViewState extends State<DetailView> {
_pageController.position.maxScrollExtent - 100) {
_loadMoreMedia();
}
});
}
Future<void> _loadMoreMedia() async {
@ -66,15 +66,11 @@ class _DetailViewState extends State<DetailView> {
mode: widget.mode,
random: widget.random,
);
if (mounted) {
if (mounted && newMedia.isNotEmpty) {
setState(() => mediaItems.addAll(newMedia));
}
} catch (e) {
if (mounted) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Fehler beim Laden weiterer Medien: $e')),
);
}
_showError("Fehler beim Laden weiterer Medien: $e");
} finally {
setState(() => isLoading = false);
}
@ -84,22 +80,22 @@ class _DetailViewState extends State<DetailView> {
try {
final updatedItem = await fetchMediaDetail(currentItemId);
if (mounted) {
setState(() {
final index = mediaItems.indexWhere(
(item) => item.id == currentItemId,
);
final index = mediaItems.indexWhere((item) => item.id == currentItemId);
if (index != -1) {
mediaItems[index] = updatedItem;
setState(() => mediaItems[index] = updatedItem);
}
});
}
} catch (e) {
if (mounted) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Fehler beim Aktualisieren des Items: $e')),
);
_showError("Fehler beim Aktualisieren des Items: $e");
}
}
void _showError(String message) {
if (mounted) {
ScaffoldMessenger.of(
context,
).showSnackBar(SnackBar(content: Text(message)));
}
}
@override
@ -109,70 +105,60 @@ class _DetailViewState extends State<DetailView> {
appBar: AppBar(
backgroundColor: const Color(0xFF2B2B2B),
foregroundColor: Colors.white,
title: Text(
'f0ck #$currentItemId (${widget.type}, ${_modes[widget.mode]})',
),
title: Text('f0ck #$currentItemId (${widget.type})'),
centerTitle: true,
),
body: RefreshIndicator(
onRefresh: _refreshMediaItem,
child: SingleChildScrollView(
child: Column(
children: [
SizedBox(
height: MediaQuery.of(context).size.height,
child: PageView.builder(
body: PageView.builder(
controller: _pageController,
itemCount: mediaItems.length,
itemBuilder: (context, index) {
final item = mediaItems[index];
return Column(
final MediaItem item = mediaItems[index];
return Scaffold(
body: SafeArea(
child: SmartRefreshIndicator(
onRefresh: _refreshMediaItem,
child: _buildMediaItem(item)
),
),
);
},
),
);
}
Widget _buildMediaItem(MediaItem item) {
return SingleChildScrollView(
child: Column(
children: [
if (item.mime.startsWith('image'))
Image.network(item.mediaUrl, fit: BoxFit.contain)
Image.network(
item.mediaUrl,
fit: BoxFit.contain,
)
else
VideoWidget(details: item),
const SizedBox(height: 20),
Text(
item.mime,
style: const TextStyle(
color: Colors.white,
fontSize: 18,
),
style: const TextStyle(color: Colors.white, fontSize: 18),
),
const SizedBox(height: 10),
Wrap(
alignment: WrapAlignment.center,
spacing: 5.0,
children: item.tags.map((tag) {
Color tagColor;
switch (tag.id) {
case 1:
tagColor = Colors.green;
break;
case 2:
tagColor = Colors.red;
break;
default:
tagColor = const Color(0xFF090909);
}
return Chip(
label: Text(tag.tag),
backgroundColor: tagColor,
backgroundColor: {
1: Colors.green,
2: Colors.red
}[tag.id] ?? const Color(0xFF090909),
labelStyle: const TextStyle(color: Colors.white),
);
}).toList(),
),
const SizedBox(height: 40),
const SizedBox(height: 20),
],
);
},
),
),
],
),
),
),
);
}

View File

@ -0,0 +1,28 @@
import 'package:flutter/material.dart';
class SmartRefreshIndicator extends StatelessWidget {
final Future<void> Function() onRefresh;
final Widget child;
const SmartRefreshIndicator({
super.key,
required this.onRefresh,
required this.child,
});
@override
Widget build(context) {
return LayoutBuilder(
builder: (context, constraints) => RefreshIndicator(
onRefresh: onRefresh,
child: SingleChildScrollView(
physics: const AlwaysScrollableScrollPhysics(),
child: ConstrainedBox(
constraints: BoxConstraints(minHeight: constraints.maxHeight),
child: child,
),
),
),
);
}
}

View File

@ -52,7 +52,9 @@ class _VideoWidgetState extends State<VideoWidget> {
mainAxisSize: MainAxisSize.min,
children: [
AspectRatio(
aspectRatio: isAudio ? 1.0 : _controller.value.aspectRatio,
aspectRatio: _controller.value.isInitialized
? _controller.value.aspectRatio
: 9 / 16,
child: Stack(
alignment: Alignment.center,
children: [
@ -66,8 +68,11 @@ class _VideoWidgetState extends State<VideoWidget> {
},
child: isAudio
? Image.network(widget.details.coverUrl, fit: BoxFit.cover)
: VideoPlayer(_controller),
: _controller.value.isInitialized
? VideoPlayer(_controller)
: Center(child: CircularProgressIndicator()),
),
if (_controller.value.isInitialized)
Align(
alignment: Alignment.bottomCenter,
child: Stack(
@ -81,7 +86,7 @@ class _VideoWidgetState extends State<VideoWidget> {
colors: VideoProgressColors(
playedColor: Colors.red,
bufferedColor: Colors.grey,
backgroundColor: Colors.black.withValues(alpha: 0.5),
backgroundColor: Colors.black.withAlpha(128),
),
),
),
@ -108,6 +113,7 @@ class _VideoWidgetState extends State<VideoWidget> {
],
),
),
if (_controller.value.isInitialized)
SizedBox(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,

View File

@ -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
# 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.
version: 1.0.15
version: 1.0.17
environment:
sdk: ^3.9.0-172.0.dev