This commit is contained in:
		@@ -1,7 +1,7 @@
 | 
			
		||||
import 'package:flutter/material.dart';
 | 
			
		||||
import 'package:flutter/services.dart';
 | 
			
		||||
 | 
			
		||||
import 'package:f0ckapp/mediagrid.dart';
 | 
			
		||||
import 'package:f0ckapp/screens/MediaGrid.dart';
 | 
			
		||||
 | 
			
		||||
void main() async {
 | 
			
		||||
  WidgetsFlutterBinding.ensureInitialized();
 | 
			
		||||
 
 | 
			
		||||
@@ -1,9 +1,10 @@
 | 
			
		||||
import 'package:flutter/material.dart';
 | 
			
		||||
import 'package:cached_network_image/cached_network_image.dart';
 | 
			
		||||
import 'package:f0ckapp/models/mediaitem.dart';
 | 
			
		||||
import 'package:f0ckapp/services/api.dart';
 | 
			
		||||
import 'package:f0ckapp/widgets/video_widget.dart';
 | 
			
		||||
import 'package:f0ckapp/models/MediaItem.dart';
 | 
			
		||||
import 'package:f0ckapp/services/Api.dart';
 | 
			
		||||
import 'package:f0ckapp/widgets/VideoWidget.dart';
 | 
			
		||||
import 'package:f0ckapp/utils/SmartRefreshIndicator.dart';
 | 
			
		||||
import 'package:f0ckapp/utils/PageTransformer.dart';
 | 
			
		||||
 | 
			
		||||
class DetailView extends StatefulWidget {
 | 
			
		||||
  final int initialItemId;
 | 
			
		||||
@@ -109,20 +110,18 @@ class _DetailViewState extends State<DetailView> {
 | 
			
		||||
        title: Text('f0ck #$currentItemId (${widget.type})'),
 | 
			
		||||
        centerTitle: true,
 | 
			
		||||
      ),
 | 
			
		||||
      body: PageView.builder(
 | 
			
		||||
      body: PageTransformer(
 | 
			
		||||
        controller: _pageController,
 | 
			
		||||
        itemCount: mediaItems.length,
 | 
			
		||||
        itemBuilder: (context, index) {
 | 
			
		||||
          final MediaItem item = mediaItems[index];
 | 
			
		||||
        pages: mediaItems.map((item) {
 | 
			
		||||
          return Scaffold(
 | 
			
		||||
            body: SafeArea(
 | 
			
		||||
              child: SmartRefreshIndicator(
 | 
			
		||||
                onRefresh: _refreshMediaItem,
 | 
			
		||||
                child: _buildMediaItem(item)
 | 
			
		||||
                child: _buildMediaItem(item),
 | 
			
		||||
              ),
 | 
			
		||||
            ),
 | 
			
		||||
          );
 | 
			
		||||
        },
 | 
			
		||||
        }).toList(),
 | 
			
		||||
      ),
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
@@ -130,6 +129,7 @@ class _DetailViewState extends State<DetailView> {
 | 
			
		||||
  Widget _buildMediaItem(MediaItem item) {
 | 
			
		||||
    return SingleChildScrollView(
 | 
			
		||||
      child: Column(
 | 
			
		||||
        mainAxisAlignment: MainAxisAlignment.center,
 | 
			
		||||
        children: [
 | 
			
		||||
          if (item.mime.startsWith('image'))
 | 
			
		||||
            CachedNetworkImage(
 | 
			
		||||
@@ -145,7 +145,7 @@ class _DetailViewState extends State<DetailView> {
 | 
			
		||||
            item.mime,
 | 
			
		||||
            style: const TextStyle(color: Colors.white, fontSize: 18),
 | 
			
		||||
          ),
 | 
			
		||||
          const SizedBox(height: 10),
 | 
			
		||||
          const SizedBox(height: 10, width: double.infinity),
 | 
			
		||||
          Wrap(
 | 
			
		||||
            alignment: WrapAlignment.center,
 | 
			
		||||
            spacing: 5.0,
 | 
			
		||||
@@ -155,7 +155,7 @@ class _DetailViewState extends State<DetailView> {
 | 
			
		||||
                backgroundColor: switch (tag.id) {
 | 
			
		||||
                  1 => Colors.green,
 | 
			
		||||
                  2 => Colors.red,
 | 
			
		||||
                  _ => const Color(0xFF090909)
 | 
			
		||||
                  _ => const Color(0xFF090909),
 | 
			
		||||
                },
 | 
			
		||||
                labelStyle: const TextStyle(color: Colors.white),
 | 
			
		||||
              );
 | 
			
		||||
@@ -1,8 +1,8 @@
 | 
			
		||||
import 'package:cached_network_image/cached_network_image.dart';
 | 
			
		||||
import 'package:flutter/material.dart';
 | 
			
		||||
import 'package:f0ckapp/services/api.dart';
 | 
			
		||||
import 'package:f0ckapp/models/mediaitem.dart';
 | 
			
		||||
import 'package:f0ckapp/screens/detailview.dart';
 | 
			
		||||
import 'package:f0ckapp/services/Api.dart';
 | 
			
		||||
import 'package:f0ckapp/models/MediaItem.dart';
 | 
			
		||||
import 'package:f0ckapp/screens/DetailView.dart';
 | 
			
		||||
import 'dart:async';
 | 
			
		||||
 | 
			
		||||
class MediaGrid extends StatefulWidget {
 | 
			
		||||
@@ -14,7 +14,7 @@ class MediaGrid extends StatefulWidget {
 | 
			
		||||
 | 
			
		||||
class _MediaGridState extends State<MediaGrid> {
 | 
			
		||||
  final ScrollController _scrollController = ScrollController();
 | 
			
		||||
  final String _version = '1.0.21+21';
 | 
			
		||||
  final String _version = '1.0.22+22';
 | 
			
		||||
  List<MediaItem> mediaItems = [];
 | 
			
		||||
  bool isLoading = false;
 | 
			
		||||
  Timer? _debounceTimer;
 | 
			
		||||
@@ -252,7 +252,7 @@ class _MediaGridState extends State<MediaGrid> {
 | 
			
		||||
                  CachedNetworkImage(
 | 
			
		||||
                    imageUrl: item.thumbnailUrl,
 | 
			
		||||
                    fit: BoxFit.cover,
 | 
			
		||||
                    placeholder: (context, url) => CircularProgressIndicator(),
 | 
			
		||||
                    placeholder: (context, url) => SizedBox.shrink(),
 | 
			
		||||
                    errorWidget: (context, url, error) => Icon(Icons.error),
 | 
			
		||||
                  ),
 | 
			
		||||
                  Align(
 | 
			
		||||
@@ -1,7 +1,7 @@
 | 
			
		||||
import 'dart:convert';
 | 
			
		||||
import 'package:http/http.dart' as http;
 | 
			
		||||
 | 
			
		||||
import 'package:f0ckapp/models/mediaitem.dart';
 | 
			
		||||
import 'package:f0ckapp/models/MediaItem.dart';
 | 
			
		||||
 | 
			
		||||
Future<List<MediaItem>> fetchMedia({
 | 
			
		||||
  String? older,
 | 
			
		||||
							
								
								
									
										42
									
								
								lib/utils/PageTransformer.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								lib/utils/PageTransformer.dart
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,42 @@
 | 
			
		||||
import 'package:flutter/material.dart';
 | 
			
		||||
 | 
			
		||||
class PageTransformer extends StatelessWidget {
 | 
			
		||||
  final List<Widget> pages;
 | 
			
		||||
  final PageController controller;
 | 
			
		||||
 | 
			
		||||
  const PageTransformer({
 | 
			
		||||
    super.key,
 | 
			
		||||
    required this.pages,
 | 
			
		||||
    required this.controller,
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  Widget build(BuildContext context) {
 | 
			
		||||
    return PageView.builder(
 | 
			
		||||
      controller: controller,
 | 
			
		||||
      itemCount: pages.length,
 | 
			
		||||
      itemBuilder: (context, index) {
 | 
			
		||||
        return _buildPage(pages[index], index);
 | 
			
		||||
      },
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  Widget _buildPage(Widget page, int index) {
 | 
			
		||||
    return AnimatedBuilder(
 | 
			
		||||
      animation: controller,
 | 
			
		||||
      builder: (context, child) {
 | 
			
		||||
        double value = 1.0;
 | 
			
		||||
        if (controller.position.haveDimensions) {
 | 
			
		||||
          value = controller.page! - index;
 | 
			
		||||
          value = (1 - (value.abs() * 0.5)).clamp(0.0, 1.0);
 | 
			
		||||
        }
 | 
			
		||||
        return Transform(
 | 
			
		||||
          transform: Matrix4.identity()..scaleByDouble(value, value, value, 1),
 | 
			
		||||
          alignment: Alignment.center,
 | 
			
		||||
          child: child,
 | 
			
		||||
        );
 | 
			
		||||
      },
 | 
			
		||||
      child: page,
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@@ -3,7 +3,13 @@ import 'package:video_player/video_player.dart';
 | 
			
		||||
 | 
			
		||||
class VideoControlsOverlay extends StatelessWidget {
 | 
			
		||||
  final VideoPlayerController controller;
 | 
			
		||||
  const VideoControlsOverlay({super.key, required this.controller});
 | 
			
		||||
  final VoidCallback button;
 | 
			
		||||
 | 
			
		||||
  const VideoControlsOverlay({
 | 
			
		||||
    super.key,
 | 
			
		||||
    required this.controller,
 | 
			
		||||
    required this.button,
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  Widget build(BuildContext context) {
 | 
			
		||||
@@ -15,22 +21,25 @@ class VideoControlsOverlay extends StatelessWidget {
 | 
			
		||||
            mainAxisAlignment: MainAxisAlignment.center,
 | 
			
		||||
            children: [
 | 
			
		||||
              _ControlButton(Icons.replay_10, () {
 | 
			
		||||
                button();
 | 
			
		||||
                controller.seekTo(
 | 
			
		||||
                  controller.value.position - Duration(seconds: 10),
 | 
			
		||||
                );
 | 
			
		||||
              }),
 | 
			
		||||
              SizedBox(width: 32),
 | 
			
		||||
              SizedBox(width: 40),
 | 
			
		||||
              _ControlButton(
 | 
			
		||||
                controller.value.isPlaying ? Icons.pause : Icons.play_arrow,
 | 
			
		||||
                () {
 | 
			
		||||
                  button();
 | 
			
		||||
                  controller.value.isPlaying
 | 
			
		||||
                      ? controller.pause()
 | 
			
		||||
                      : controller.play();
 | 
			
		||||
                },
 | 
			
		||||
                size: 64,
 | 
			
		||||
              ),
 | 
			
		||||
              SizedBox(width: 32),
 | 
			
		||||
              SizedBox(width: 40),
 | 
			
		||||
              _ControlButton(Icons.forward_10, () {
 | 
			
		||||
                button();
 | 
			
		||||
                controller.seekTo(
 | 
			
		||||
                  controller.value.position + Duration(seconds: 10),
 | 
			
		||||
                );
 | 
			
		||||
@@ -38,7 +47,7 @@ class VideoControlsOverlay extends StatelessWidget {
 | 
			
		||||
            ],
 | 
			
		||||
          ),
 | 
			
		||||
        ),
 | 
			
		||||
        _ProgressIndicator(controller: controller),
 | 
			
		||||
        _ProgressIndicator(controller: controller)
 | 
			
		||||
      ],
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
@@ -68,6 +77,7 @@ class _ControlButton extends StatelessWidget {
 | 
			
		||||
 | 
			
		||||
class _ProgressIndicator extends StatelessWidget {
 | 
			
		||||
  final VideoPlayerController controller;
 | 
			
		||||
 | 
			
		||||
  const _ProgressIndicator({required this.controller});
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
@@ -77,18 +87,14 @@ class _ProgressIndicator extends StatelessWidget {
 | 
			
		||||
      child: Stack(
 | 
			
		||||
        clipBehavior: Clip.none,
 | 
			
		||||
        children: [
 | 
			
		||||
          Container(
 | 
			
		||||
            height: 20,
 | 
			
		||||
            alignment: Alignment.bottomCenter,
 | 
			
		||||
            color: Colors.transparent,
 | 
			
		||||
            child: VideoProgressIndicator(
 | 
			
		||||
              controller,
 | 
			
		||||
              allowScrubbing: true,
 | 
			
		||||
              colors: VideoProgressColors(
 | 
			
		||||
                playedColor: Colors.red,
 | 
			
		||||
                backgroundColor: Colors.grey,
 | 
			
		||||
                bufferedColor: Colors.white54,
 | 
			
		||||
              ),
 | 
			
		||||
          VideoProgressIndicator(
 | 
			
		||||
            controller,
 | 
			
		||||
            allowScrubbing: true,
 | 
			
		||||
            padding: const EdgeInsets.only(top: 25.0),
 | 
			
		||||
            colors: VideoProgressColors(
 | 
			
		||||
              playedColor: Colors.red,
 | 
			
		||||
              backgroundColor: Colors.grey,
 | 
			
		||||
              bufferedColor: Colors.white54,
 | 
			
		||||
            ),
 | 
			
		||||
          ),
 | 
			
		||||
          Positioned(
 | 
			
		||||
@@ -123,8 +129,6 @@ class _ProgressIndicator extends StatelessWidget {
 | 
			
		||||
 | 
			
		||||
  String _formatDuration(Duration duration) {
 | 
			
		||||
    String twoDigits(int n) => n.toString().padLeft(2, '0');
 | 
			
		||||
    final minutes = twoDigits(duration.inMinutes.remainder(60));
 | 
			
		||||
    final seconds = twoDigits(duration.inSeconds.remainder(60));
 | 
			
		||||
    return "$minutes:$seconds";
 | 
			
		||||
    return "${twoDigits(duration.inMinutes % 60)}:${twoDigits(duration.inSeconds % 60)}";
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@@ -3,8 +3,8 @@ import 'dart:async';
 | 
			
		||||
import 'package:flutter/material.dart';
 | 
			
		||||
import 'package:video_player/video_player.dart';
 | 
			
		||||
import 'package:cached_network_image/cached_network_image.dart';
 | 
			
		||||
import 'package:f0ckapp/models/mediaitem.dart';
 | 
			
		||||
import 'package:f0ckapp/widgets/video_overlay.dart';
 | 
			
		||||
import 'package:f0ckapp/models/MediaItem.dart';
 | 
			
		||||
import 'package:f0ckapp/widgets/VideoOverlay.dart';
 | 
			
		||||
 | 
			
		||||
class VideoWidget extends StatefulWidget {
 | 
			
		||||
  final MediaItem details;
 | 
			
		||||
@@ -17,6 +17,7 @@ class VideoWidget extends StatefulWidget {
 | 
			
		||||
class _VideoWidgetState extends State<VideoWidget> {
 | 
			
		||||
  late VideoPlayerController _controller;
 | 
			
		||||
  bool _showControls = false;
 | 
			
		||||
  Timer? _hideControlsTimer;
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  void initState() {
 | 
			
		||||
@@ -39,9 +40,23 @@ class _VideoWidgetState extends State<VideoWidget> {
 | 
			
		||||
  @override
 | 
			
		||||
  void dispose() {
 | 
			
		||||
    _controller.dispose();
 | 
			
		||||
    _hideControlsTimer?.cancel();
 | 
			
		||||
    super.dispose();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  void _onTap({bool ctrlButton = false}) {
 | 
			
		||||
    if (!ctrlButton) {
 | 
			
		||||
      setState(() => _showControls = !_showControls);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (_showControls) {
 | 
			
		||||
      _hideControlsTimer?.cancel();
 | 
			
		||||
      _hideControlsTimer = Timer(Duration(seconds: 5), () {
 | 
			
		||||
        setState(() => _showControls = false);
 | 
			
		||||
      });
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  Widget build(BuildContext context) {
 | 
			
		||||
    bool isAudio = widget.details.mime.startsWith('audio');
 | 
			
		||||
@@ -57,11 +72,7 @@ class _VideoWidgetState extends State<VideoWidget> {
 | 
			
		||||
            alignment: Alignment.center,
 | 
			
		||||
            children: [
 | 
			
		||||
              GestureDetector(
 | 
			
		||||
                onTap: () {
 | 
			
		||||
                  setState(() {
 | 
			
		||||
                    _showControls = !_showControls;
 | 
			
		||||
                  });
 | 
			
		||||
                },
 | 
			
		||||
                onTap: _onTap,
 | 
			
		||||
                child: isAudio
 | 
			
		||||
                    ? CachedNetworkImage(
 | 
			
		||||
                        imageUrl: widget.details.coverUrl,
 | 
			
		||||
@@ -78,15 +89,7 @@ class _VideoWidgetState extends State<VideoWidget> {
 | 
			
		||||
                    : Center(child: CircularProgressIndicator()),
 | 
			
		||||
              ),
 | 
			
		||||
              if (_controller.value.isInitialized && _showControls) ...[
 | 
			
		||||
                IgnorePointer(
 | 
			
		||||
                  ignoring: true,
 | 
			
		||||
                  child: Container(
 | 
			
		||||
                    color: Colors.black.withValues(alpha: 0.5),
 | 
			
		||||
                    width: double.infinity,
 | 
			
		||||
                    height: double.infinity,
 | 
			
		||||
                  ),
 | 
			
		||||
                ),
 | 
			
		||||
                VideoControlsOverlay(controller: _controller),
 | 
			
		||||
                VideoControlsOverlay(controller: _controller, button: () => _onTap(ctrlButton: true)),
 | 
			
		||||
              ],
 | 
			
		||||
            ],
 | 
			
		||||
          ),
 | 
			
		||||
		Reference in New Issue
	
	Block a user