This commit is contained in:
		@@ -15,6 +15,8 @@ class _LoginPageState extends State<LoginPage> {
 | 
				
			|||||||
  final TextEditingController usernameController = TextEditingController();
 | 
					  final TextEditingController usernameController = TextEditingController();
 | 
				
			||||||
  final TextEditingController passwordController = TextEditingController();
 | 
					  final TextEditingController passwordController = TextEditingController();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  bool _isLoading = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  void _showMsg(String message, {String title = ''}) {
 | 
					  void _showMsg(String message, {String title = ''}) {
 | 
				
			||||||
    Get
 | 
					    Get
 | 
				
			||||||
      ..closeAllSnackbars()
 | 
					      ..closeAllSnackbars()
 | 
				
			||||||
@@ -31,38 +33,89 @@ class _LoginPageState extends State<LoginPage> {
 | 
				
			|||||||
  @override
 | 
					  @override
 | 
				
			||||||
  Widget build(BuildContext context) {
 | 
					  Widget build(BuildContext context) {
 | 
				
			||||||
    return Scaffold(
 | 
					    return Scaffold(
 | 
				
			||||||
      body: CustomScrollView(
 | 
					      body: Center(
 | 
				
			||||||
        slivers: [
 | 
					        child: SingleChildScrollView(
 | 
				
			||||||
          SliverAppBar(floating: false, pinned: true, title: Text('Login')),
 | 
					          padding: const EdgeInsets.all(24),
 | 
				
			||||||
          SliverList(
 | 
					          child: Card(
 | 
				
			||||||
            delegate: SliverChildListDelegate([
 | 
					            elevation: 8,
 | 
				
			||||||
              ListTile(
 | 
					            shape: RoundedRectangleBorder(
 | 
				
			||||||
                title: Text('Benutzername'),
 | 
					              borderRadius: BorderRadius.circular(16),
 | 
				
			||||||
                subtitle: TextField(controller: usernameController),
 | 
					 | 
				
			||||||
            ),
 | 
					            ),
 | 
				
			||||||
              ListTile(
 | 
					            child: Padding(
 | 
				
			||||||
                title: Text('Passwort'),
 | 
					              padding: const EdgeInsets.all(24),
 | 
				
			||||||
                subtitle: TextField(
 | 
					              child: Column(
 | 
				
			||||||
 | 
					                mainAxisSize: MainAxisSize.min,
 | 
				
			||||||
 | 
					                children: [
 | 
				
			||||||
 | 
					                  Row(
 | 
				
			||||||
 | 
					                    children: [
 | 
				
			||||||
 | 
					                      IconButton(
 | 
				
			||||||
 | 
					                        icon: const Icon(Icons.arrow_back),
 | 
				
			||||||
 | 
					                        tooltip: 'Zurück',
 | 
				
			||||||
 | 
					                        onPressed: () => Get.back(),
 | 
				
			||||||
 | 
					                      ),
 | 
				
			||||||
 | 
					                      const SizedBox(width: 8),
 | 
				
			||||||
 | 
					                      Text(
 | 
				
			||||||
 | 
					                        'Login',
 | 
				
			||||||
 | 
					                        style: Theme.of(context).textTheme.headlineMedium,
 | 
				
			||||||
 | 
					                      ),
 | 
				
			||||||
 | 
					                    ],
 | 
				
			||||||
 | 
					                  ),
 | 
				
			||||||
 | 
					                  const SizedBox(height: 24),
 | 
				
			||||||
 | 
					                  TextField(
 | 
				
			||||||
 | 
					                    controller: usernameController,
 | 
				
			||||||
 | 
					                    decoration: const InputDecoration(
 | 
				
			||||||
 | 
					                      labelText: 'Benutzername',
 | 
				
			||||||
 | 
					                      prefixIcon: Icon(Icons.person),
 | 
				
			||||||
 | 
					                      border: OutlineInputBorder(),
 | 
				
			||||||
 | 
					                    ),
 | 
				
			||||||
 | 
					                  ),
 | 
				
			||||||
 | 
					                  const SizedBox(height: 16),
 | 
				
			||||||
 | 
					                  TextField(
 | 
				
			||||||
                    controller: passwordController,
 | 
					                    controller: passwordController,
 | 
				
			||||||
                    obscureText: true,
 | 
					                    obscureText: true,
 | 
				
			||||||
 | 
					                    decoration: const InputDecoration(
 | 
				
			||||||
 | 
					                      labelText: 'Passwort',
 | 
				
			||||||
 | 
					                      prefixIcon: Icon(Icons.lock),
 | 
				
			||||||
 | 
					                      border: OutlineInputBorder(),
 | 
				
			||||||
                    ),
 | 
					                    ),
 | 
				
			||||||
                  ),
 | 
					                  ),
 | 
				
			||||||
              ElevatedButton(
 | 
					                  const SizedBox(height: 24),
 | 
				
			||||||
                onPressed: () async {
 | 
					                  SizedBox(
 | 
				
			||||||
 | 
					                    width: double.infinity,
 | 
				
			||||||
 | 
					                    child: ElevatedButton(
 | 
				
			||||||
 | 
					                      onPressed: _isLoading
 | 
				
			||||||
 | 
					                          ? null
 | 
				
			||||||
 | 
					                          : () async {
 | 
				
			||||||
 | 
					                              setState(() => _isLoading = true);
 | 
				
			||||||
                              final success = await authController.login(
 | 
					                              final success = await authController.login(
 | 
				
			||||||
                                usernameController.text,
 | 
					                                usernameController.text,
 | 
				
			||||||
                                passwordController.text,
 | 
					                                passwordController.text,
 | 
				
			||||||
                              );
 | 
					                              );
 | 
				
			||||||
 | 
					                              setState(() => _isLoading = false);
 | 
				
			||||||
                              if (!success) {
 | 
					                              if (!success) {
 | 
				
			||||||
                    _showMsg('Login fehlgeschlagen!');
 | 
					                                return _showMsg('Login fehlgeschlagen!');
 | 
				
			||||||
                              }
 | 
					                              }
 | 
				
			||||||
 | 
					                              _showMsg('Erfolgreich eingeloggt.');
 | 
				
			||||||
 | 
					                              Get.back();
 | 
				
			||||||
                            },
 | 
					                            },
 | 
				
			||||||
                child: Text('Login'),
 | 
					                      child: _isLoading
 | 
				
			||||||
 | 
					                          ? const SizedBox(
 | 
				
			||||||
 | 
					                              width: 24,
 | 
				
			||||||
 | 
					                              height: 24,
 | 
				
			||||||
 | 
					                              child: CircularProgressIndicator(
 | 
				
			||||||
 | 
					                                strokeWidth: 2,
 | 
				
			||||||
 | 
					                                color: Colors.white,
 | 
				
			||||||
 | 
					                              ),
 | 
				
			||||||
 | 
					                            )
 | 
				
			||||||
 | 
					                          : const Text('Login'),
 | 
				
			||||||
                    ),
 | 
					                    ),
 | 
				
			||||||
            ]),
 | 
					 | 
				
			||||||
                  ),
 | 
					                  ),
 | 
				
			||||||
                ],
 | 
					                ],
 | 
				
			||||||
              ),
 | 
					              ),
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					          ),
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					      ),
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,3 +1,5 @@
 | 
				
			|||||||
 | 
					import 'dart:async';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import 'package:flutter/material.dart';
 | 
					import 'package:flutter/material.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import 'package:get/get.dart';
 | 
					import 'package:get/get.dart';
 | 
				
			||||||
@@ -18,6 +20,7 @@ class MediaGrid extends StatefulWidget {
 | 
				
			|||||||
class _MediaGridState extends State<MediaGrid> {
 | 
					class _MediaGridState extends State<MediaGrid> {
 | 
				
			||||||
  final MediaController controller = Get.find<MediaController>();
 | 
					  final MediaController controller = Get.find<MediaController>();
 | 
				
			||||||
  final ScrollController _scrollController = ScrollController();
 | 
					  final ScrollController _scrollController = ScrollController();
 | 
				
			||||||
 | 
					  Timer? _debounce;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @override
 | 
					  @override
 | 
				
			||||||
  void initState() {
 | 
					  void initState() {
 | 
				
			||||||
@@ -31,12 +34,15 @@ class _MediaGridState extends State<MediaGrid> {
 | 
				
			|||||||
    _scrollController.addListener(() {
 | 
					    _scrollController.addListener(() {
 | 
				
			||||||
      if (_scrollController.position.extentAfter < 200 &&
 | 
					      if (_scrollController.position.extentAfter < 200 &&
 | 
				
			||||||
          !controller.isLoading.value) {
 | 
					          !controller.isLoading.value) {
 | 
				
			||||||
 | 
					        if (_debounce?.isActive ?? false) _debounce!.cancel();
 | 
				
			||||||
 | 
					        _debounce = Timer(const Duration(milliseconds: 300), () {
 | 
				
			||||||
          controller.loadMediaItems(
 | 
					          controller.loadMediaItems(
 | 
				
			||||||
            older: controller.mediaItems.isNotEmpty
 | 
					            older: controller.mediaItems.isNotEmpty
 | 
				
			||||||
                ? controller.mediaItems.last.id
 | 
					                ? controller.mediaItems.last.id
 | 
				
			||||||
                : null,
 | 
					                : null,
 | 
				
			||||||
            append: true,
 | 
					            append: true,
 | 
				
			||||||
          );
 | 
					          );
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -89,7 +89,7 @@ class EndDrawer extends StatelessWidget {
 | 
				
			|||||||
                    ElevatedButton(
 | 
					                    ElevatedButton(
 | 
				
			||||||
                      onPressed: () {
 | 
					                      onPressed: () {
 | 
				
			||||||
                        Navigator.pop(context);
 | 
					                        Navigator.pop(context);
 | 
				
			||||||
                        Get.bottomSheet(LoginPage(), isDismissible: false);
 | 
					                        Get.to(() => LoginPage());
 | 
				
			||||||
                      },
 | 
					                      },
 | 
				
			||||||
                      child: const Text('Login'),
 | 
					                      child: const Text('Login'),
 | 
				
			||||||
                    ),
 | 
					                    ),
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -12,7 +12,8 @@ class MediaTile extends StatelessWidget {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  @override
 | 
					  @override
 | 
				
			||||||
  Widget build(BuildContext context) {
 | 
					  Widget build(BuildContext context) {
 | 
				
			||||||
    return InkWell(
 | 
					    return RepaintBoundary(
 | 
				
			||||||
 | 
					      child: InkWell(
 | 
				
			||||||
        onTap: () {
 | 
					        onTap: () {
 | 
				
			||||||
          Get.toNamed('/${item.id}');
 | 
					          Get.toNamed('/${item.id}');
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
@@ -24,6 +25,7 @@ class MediaTile extends StatelessWidget {
 | 
				
			|||||||
              child: CachedNetworkImage(
 | 
					              child: CachedNetworkImage(
 | 
				
			||||||
                imageUrl: item.thumbnailUrl,
 | 
					                imageUrl: item.thumbnailUrl,
 | 
				
			||||||
                fit: BoxFit.cover,
 | 
					                fit: BoxFit.cover,
 | 
				
			||||||
 | 
					                placeholder: (content, url) => Container(color: Colors.grey[900]),
 | 
				
			||||||
                errorWidget: (context, url, error) => const Icon(Icons.error),
 | 
					                errorWidget: (context, url, error) => const Icon(Icons.error),
 | 
				
			||||||
              ),
 | 
					              ),
 | 
				
			||||||
            ),
 | 
					            ),
 | 
				
			||||||
@@ -41,6 +43,7 @@ class MediaTile extends StatelessWidget {
 | 
				
			|||||||
            ),
 | 
					            ),
 | 
				
			||||||
          ],
 | 
					          ],
 | 
				
			||||||
        ),
 | 
					        ),
 | 
				
			||||||
 | 
					      ),
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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.3.3+59
 | 
					version: 1.3.4+60
 | 
				
			||||||
 | 
					
 | 
				
			||||||
environment:
 | 
					environment:
 | 
				
			||||||
  sdk: ^3.9.0-100.2.beta
 | 
					  sdk: ^3.9.0-100.2.beta
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user