All checks were successful
Flutter Schmutter / build (push) Successful in 3m45s
- search schmearch
324 lines
11 KiB
Dart
324 lines
11 KiB
Dart
import 'package:flutter/material.dart';
|
|
|
|
import 'package:cached_network_image/cached_network_image.dart';
|
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|
import 'package:go_router/go_router.dart';
|
|
|
|
import 'package:f0ckapp/models/mediaitem_model.dart';
|
|
import 'package:f0ckapp/providers/media_provider.dart';
|
|
import 'package:f0ckapp/utils/appversion_util.dart';
|
|
import 'package:f0ckapp/providers/theme_provider.dart';
|
|
import 'package:f0ckapp/utils/customsearchdelegate_util.dart';
|
|
|
|
class MediaGrid extends ConsumerStatefulWidget {
|
|
const MediaGrid({super.key});
|
|
|
|
@override
|
|
ConsumerState<MediaGrid> createState() => _MediaGridState();
|
|
}
|
|
|
|
class _MediaGridState extends ConsumerState<MediaGrid> {
|
|
final ScrollController _scrollController = ScrollController();
|
|
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
|
|
|
|
final TextEditingController _usernameController = TextEditingController();
|
|
final TextEditingController _passwordController = TextEditingController();
|
|
|
|
int _calculateCrossAxisCount(BuildContext context, int defaultCount) {
|
|
return defaultCount == 0
|
|
? (MediaQuery.of(context).size.width / 110).clamp(3, 5).toInt()
|
|
: defaultCount;
|
|
}
|
|
|
|
@override
|
|
void initState() {
|
|
super.initState();
|
|
Future.microtask(() {
|
|
ref.read(mediaProvider.notifier).loadMedia();
|
|
});
|
|
_scrollController.addListener(() {
|
|
if (_scrollController.position.pixels >=
|
|
_scrollController.position.maxScrollExtent - 200) {
|
|
ref.read(mediaProvider.notifier).loadMedia();
|
|
}
|
|
});
|
|
}
|
|
|
|
@override
|
|
void dispose() {
|
|
_scrollController.dispose();
|
|
_usernameController.dispose();
|
|
_passwordController.dispose();
|
|
super.dispose();
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final MediaState mediaState = ref.watch(mediaProvider);
|
|
final MediaNotifier mediaNotifier = ref.read(mediaProvider.notifier);
|
|
|
|
return Scaffold(
|
|
key: _scaffoldKey,
|
|
appBar: AppBar(
|
|
title: GestureDetector(
|
|
child: Row(
|
|
spacing: 10,
|
|
children: [
|
|
Image.asset(
|
|
'assets/images/f0ck_small.webp',
|
|
fit: BoxFit.fitHeight,
|
|
),
|
|
Text('fApp', style: TextStyle(fontSize: 24)),
|
|
],
|
|
),
|
|
onTap: () {
|
|
mediaNotifier.setTag(null);
|
|
_scrollController.jumpTo(0);
|
|
},
|
|
),
|
|
actions: [
|
|
IconButton(
|
|
icon: const Icon(Icons.search),
|
|
onPressed: () async {
|
|
await showSearch(
|
|
context: context,
|
|
delegate: CustomSearchDelegate(),
|
|
);
|
|
},
|
|
),
|
|
IconButton(
|
|
icon: Icon(
|
|
mediaState.random ? Icons.shuffle_on_outlined : Icons.shuffle,
|
|
),
|
|
onPressed: () {
|
|
mediaNotifier.toggleRandom();
|
|
_scrollController.jumpTo(0);
|
|
},
|
|
),
|
|
IconButton(
|
|
icon: const Icon(Icons.menu),
|
|
onPressed: () {
|
|
_scaffoldKey.currentState?.openEndDrawer();
|
|
},
|
|
),
|
|
],
|
|
),
|
|
bottomNavigationBar: BottomAppBar(
|
|
height: 50,
|
|
child: Row(
|
|
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
|
children: [
|
|
const Text('type: '),
|
|
DropdownButton<String>(
|
|
value: mediaTypes[mediaState.typeIndex],
|
|
isDense: true,
|
|
items: mediaTypes.map((String value) {
|
|
return DropdownMenuItem<String>(
|
|
value: value,
|
|
child: Text(value),
|
|
);
|
|
}).toList(),
|
|
onChanged: (String? newValue) {
|
|
if (newValue != null) {
|
|
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);
|
|
}
|
|
},
|
|
),
|
|
],
|
|
),
|
|
),
|
|
endDrawer: Drawer(
|
|
child: ListView(
|
|
padding: EdgeInsets.zero,
|
|
children: [
|
|
DrawerHeader(
|
|
decoration: const BoxDecoration(
|
|
image: DecorationImage(
|
|
image: AssetImage('assets/images/menu.webp'),
|
|
fit: BoxFit.cover,
|
|
alignment: Alignment.topCenter,
|
|
),
|
|
),
|
|
child: null,
|
|
),
|
|
/*ExpansionTile(
|
|
title: const Text('Login'),
|
|
children: [
|
|
Padding(
|
|
padding: const EdgeInsets.all(16.0),
|
|
child: Column(
|
|
children: [
|
|
TextField(
|
|
readOnly: true,
|
|
controller: _usernameController,
|
|
decoration: const InputDecoration(
|
|
labelText: 'Benutzername',
|
|
),
|
|
),
|
|
const SizedBox(height: 10),
|
|
TextField(
|
|
readOnly: true,
|
|
controller: _passwordController,
|
|
obscureText: true,
|
|
decoration: const InputDecoration(
|
|
labelText: 'Passwort',
|
|
),
|
|
),
|
|
const SizedBox(height: 20),
|
|
ElevatedButton(
|
|
onPressed: () async {
|
|
ScaffoldMessenger.of(context).showSnackBar(
|
|
const SnackBar(
|
|
content: Text("noch nicht implementiert lol"),
|
|
),
|
|
final success = await login(
|
|
_usernameController.text,
|
|
_passwordController.text,
|
|
);
|
|
|
|
if (success) {
|
|
Navigator.pop(context);
|
|
} else {
|
|
ScaffoldMessenger.of(context).showSnackBar(
|
|
SnackBar(content: Text("Login fehlgeschlagen!")),
|
|
);
|
|
}
|
|
);
|
|
},
|
|
child: const Text('Login'),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
],
|
|
),*/
|
|
ExpansionTile(
|
|
title: const Text('Theme'),
|
|
children: [
|
|
Padding(
|
|
padding: const EdgeInsets.symmetric(horizontal: 16.0),
|
|
child: Column(
|
|
children: themeMap.entries.map((entry) {
|
|
final String themeName = entry.key;
|
|
final ThemeData themeData = entry.value;
|
|
final ThemeData currentTheme = ref.watch(themeNotifierProvider);
|
|
final bool isSelected = currentTheme == themeData;
|
|
return ListTile(
|
|
title: Text(themeName),
|
|
selected: isSelected,
|
|
selectedTileColor: Colors.blue.withValues(alpha: 0.2),
|
|
onTap: () async {
|
|
await ref
|
|
.read(themeNotifierProvider.notifier)
|
|
.updateTheme(themeName);
|
|
},
|
|
);
|
|
}).toList(),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
ListTile(
|
|
title: Text('v${AppVersion.version}'),
|
|
onTap: () {
|
|
ScaffoldMessenger.of(context).showSnackBar(
|
|
const SnackBar(
|
|
content: Text('jooong lass das, hier ist nichts'),
|
|
),
|
|
);
|
|
},
|
|
),
|
|
],
|
|
),
|
|
),
|
|
persistentFooterButtons: mediaState.tag != null
|
|
? [
|
|
Center(
|
|
child: InputChip(
|
|
label: Text(mediaState.tag!),
|
|
onDeleted: () {
|
|
mediaNotifier.setTag(null);
|
|
_scrollController.jumpTo(0);
|
|
},
|
|
),
|
|
),
|
|
]
|
|
: null,
|
|
body: RefreshIndicator(
|
|
onRefresh: () async {
|
|
mediaNotifier.resetMedia();
|
|
_scrollController.jumpTo(0);
|
|
},
|
|
child: GridView.builder(
|
|
key: const PageStorageKey('mediaGrid'),
|
|
controller: _scrollController,
|
|
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
|
|
crossAxisCount: _calculateCrossAxisCount(
|
|
context,
|
|
mediaState.crossAxisCount,
|
|
),
|
|
crossAxisSpacing: 5.0,
|
|
mainAxisSpacing: 5.0,
|
|
),
|
|
itemCount:
|
|
mediaState.mediaItems.length + (mediaState.isLoading ? 1 : 0),
|
|
itemBuilder: (BuildContext context, int index) {
|
|
if (index >= mediaState.mediaItems.length) {
|
|
return const Center(child: CircularProgressIndicator());
|
|
}
|
|
final MediaItem item = mediaState.mediaItems[index];
|
|
|
|
return InkWell(
|
|
onTap: () async {
|
|
context.push('/${item.id}', extra: true);
|
|
},
|
|
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,
|
|
),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
},
|
|
),
|
|
),
|
|
);
|
|
}
|
|
}
|