v1.0.24+24
- tags lul
This commit is contained in:
		@@ -12,6 +12,7 @@ class DetailView extends StatefulWidget {
 | 
			
		||||
  final String type;
 | 
			
		||||
  final int mode;
 | 
			
		||||
  final bool random;
 | 
			
		||||
  final String? tagname;
 | 
			
		||||
 | 
			
		||||
  const DetailView({
 | 
			
		||||
    super.key,
 | 
			
		||||
@@ -20,6 +21,7 @@ class DetailView extends StatefulWidget {
 | 
			
		||||
    required this.type,
 | 
			
		||||
    required this.mode,
 | 
			
		||||
    required this.random,
 | 
			
		||||
    required this.tagname,
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
@@ -29,6 +31,7 @@ class DetailView extends StatefulWidget {
 | 
			
		||||
class _DetailViewState extends State<DetailView> {
 | 
			
		||||
  late PageController _pageController;
 | 
			
		||||
  late List<MediaItem> mediaItems;
 | 
			
		||||
  String? _tagname;
 | 
			
		||||
  int currentItemId = 0;
 | 
			
		||||
  bool isLoading = false;
 | 
			
		||||
 | 
			
		||||
@@ -36,6 +39,7 @@ class _DetailViewState extends State<DetailView> {
 | 
			
		||||
  void initState() {
 | 
			
		||||
    super.initState();
 | 
			
		||||
    mediaItems = widget.mediaItems;
 | 
			
		||||
    _tagname = widget.tagname;
 | 
			
		||||
    final initialIndex = mediaItems.indexWhere(
 | 
			
		||||
      (item) => item.id == widget.initialItemId,
 | 
			
		||||
    );
 | 
			
		||||
@@ -67,6 +71,7 @@ class _DetailViewState extends State<DetailView> {
 | 
			
		||||
        type: widget.type,
 | 
			
		||||
        mode: widget.mode,
 | 
			
		||||
        random: widget.random,
 | 
			
		||||
        tag: _tagname,
 | 
			
		||||
      );
 | 
			
		||||
      if (mounted && newMedia.isNotEmpty) {
 | 
			
		||||
        setState(() => mediaItems.addAll(newMedia));
 | 
			
		||||
@@ -110,18 +115,56 @@ class _DetailViewState extends State<DetailView> {
 | 
			
		||||
        title: Text('f0ck #$currentItemId (${widget.type})'),
 | 
			
		||||
        centerTitle: true,
 | 
			
		||||
      ),
 | 
			
		||||
      body: PageTransformer(
 | 
			
		||||
        controller: _pageController,
 | 
			
		||||
        pages: mediaItems.map((item) {
 | 
			
		||||
          return Scaffold(
 | 
			
		||||
            body: SafeArea(
 | 
			
		||||
              child: SmartRefreshIndicator(
 | 
			
		||||
                onRefresh: _refreshMediaItem,
 | 
			
		||||
                child: _buildMediaItem(item),
 | 
			
		||||
      body: Stack(
 | 
			
		||||
        children: [
 | 
			
		||||
          PageTransformer(
 | 
			
		||||
            controller: _pageController,
 | 
			
		||||
            pages: mediaItems.map((item) {
 | 
			
		||||
              return Scaffold(
 | 
			
		||||
                body: SafeArea(
 | 
			
		||||
                  child: SmartRefreshIndicator(
 | 
			
		||||
                    onRefresh: _refreshMediaItem,
 | 
			
		||||
                    child: _buildMediaItem(item),
 | 
			
		||||
                  ),
 | 
			
		||||
                ),
 | 
			
		||||
              );
 | 
			
		||||
            }).toList(),
 | 
			
		||||
          ),
 | 
			
		||||
          if (_tagname != null)
 | 
			
		||||
            Positioned(
 | 
			
		||||
              bottom: 60,
 | 
			
		||||
              left: MediaQuery.of(context).size.width * 0.2,
 | 
			
		||||
              right: MediaQuery.of(context).size.width * 0.2,
 | 
			
		||||
              child: Container(
 | 
			
		||||
                padding: const EdgeInsets.symmetric(
 | 
			
		||||
                  vertical: 10,
 | 
			
		||||
                  horizontal: 20,
 | 
			
		||||
                ),
 | 
			
		||||
                decoration: BoxDecoration(
 | 
			
		||||
                  color: Colors.black.withValues(alpha: 0.8),
 | 
			
		||||
                  borderRadius: BorderRadius.circular(12),
 | 
			
		||||
                ),
 | 
			
		||||
                child: Row(
 | 
			
		||||
                  mainAxisAlignment: MainAxisAlignment.spaceBetween,
 | 
			
		||||
                  children: [
 | 
			
		||||
                    Text(
 | 
			
		||||
                      'Tag: $_tagname',
 | 
			
		||||
                      style: const TextStyle(color: Colors.white),
 | 
			
		||||
                    ),
 | 
			
		||||
                    IconButton(
 | 
			
		||||
                      icon: const Icon(Icons.close, color: Colors.white),
 | 
			
		||||
                      onPressed: () {
 | 
			
		||||
                        setState(() {
 | 
			
		||||
                          _tagname = '___empty___';
 | 
			
		||||
                          Navigator.pop(context, _tagname);
 | 
			
		||||
                        });
 | 
			
		||||
                      },
 | 
			
		||||
                    ),
 | 
			
		||||
                  ],
 | 
			
		||||
                ),
 | 
			
		||||
              ),
 | 
			
		||||
            ),
 | 
			
		||||
          );
 | 
			
		||||
        }).toList(),
 | 
			
		||||
        ],
 | 
			
		||||
      ),
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
@@ -150,14 +193,23 @@ class _DetailViewState extends State<DetailView> {
 | 
			
		||||
            alignment: WrapAlignment.center,
 | 
			
		||||
            spacing: 5.0,
 | 
			
		||||
            children: item.tags.map((tag) {
 | 
			
		||||
              return Chip(
 | 
			
		||||
                label: Text(tag.tag),
 | 
			
		||||
                backgroundColor: switch (tag.id) {
 | 
			
		||||
                  1 => Colors.green,
 | 
			
		||||
                  2 => Colors.red,
 | 
			
		||||
                  _ => const Color(0xFF090909),
 | 
			
		||||
              return GestureDetector(
 | 
			
		||||
                onTap: () {
 | 
			
		||||
                  if (tag.tag == 'sfw' || tag.tag == 'nsfw') return;
 | 
			
		||||
                  setState(() {
 | 
			
		||||
                    _tagname = tag.tag;
 | 
			
		||||
                    Navigator.pop(context, _tagname);
 | 
			
		||||
                  });
 | 
			
		||||
                },
 | 
			
		||||
                labelStyle: const TextStyle(color: Colors.white),
 | 
			
		||||
                child: Chip(
 | 
			
		||||
                  label: Text(tag.tag),
 | 
			
		||||
                  backgroundColor: switch (tag.id) {
 | 
			
		||||
                    1 => Colors.green,
 | 
			
		||||
                    2 => Colors.red,
 | 
			
		||||
                    _ => const Color(0xFF090909),
 | 
			
		||||
                  },
 | 
			
		||||
                  labelStyle: const TextStyle(color: Colors.white),
 | 
			
		||||
                ),
 | 
			
		||||
              );
 | 
			
		||||
            }).toList(),
 | 
			
		||||
          ),
 | 
			
		||||
 
 | 
			
		||||
@@ -14,7 +14,7 @@ class MediaGrid extends StatefulWidget {
 | 
			
		||||
 | 
			
		||||
class _MediaGridState extends State<MediaGrid> {
 | 
			
		||||
  final ScrollController _scrollController = ScrollController();
 | 
			
		||||
  final String _version = '1.0.23+23';
 | 
			
		||||
  final String _version = '1.0.24+24';
 | 
			
		||||
  List<MediaItem> mediaItems = [];
 | 
			
		||||
  bool isLoading = false;
 | 
			
		||||
  Timer? _debounceTimer;
 | 
			
		||||
@@ -24,6 +24,7 @@ class _MediaGridState extends State<MediaGrid> {
 | 
			
		||||
  int _selectedMode = 0;
 | 
			
		||||
  bool _random = false;
 | 
			
		||||
  final List<String> _modes = ["sfw", "nsfw", "untagged", "all"];
 | 
			
		||||
  String? _selectedTag;
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  void initState() {
 | 
			
		||||
@@ -63,6 +64,7 @@ class _MediaGridState extends State<MediaGrid> {
 | 
			
		||||
        type: _selectedType,
 | 
			
		||||
        mode: _selectedMode,
 | 
			
		||||
        random: _random,
 | 
			
		||||
        tag: _selectedTag,
 | 
			
		||||
      );
 | 
			
		||||
      if (mounted) {
 | 
			
		||||
        setState(() => mediaItems.addAll(newMedia));
 | 
			
		||||
@@ -86,6 +88,7 @@ class _MediaGridState extends State<MediaGrid> {
 | 
			
		||||
        type: _selectedType,
 | 
			
		||||
        mode: _selectedMode,
 | 
			
		||||
        random: _random,
 | 
			
		||||
        tag: _selectedTag,
 | 
			
		||||
      );
 | 
			
		||||
      if (mounted) {
 | 
			
		||||
        setState(() {
 | 
			
		||||
@@ -110,7 +113,7 @@ class _MediaGridState extends State<MediaGrid> {
 | 
			
		||||
    _navigationCompleter = Completer();
 | 
			
		||||
    try {
 | 
			
		||||
      if (mounted) {
 | 
			
		||||
        await Navigator.push(
 | 
			
		||||
        final String? newTag = await Navigator.push(
 | 
			
		||||
          context,
 | 
			
		||||
          MaterialPageRoute(
 | 
			
		||||
            builder: (context) => DetailView(
 | 
			
		||||
@@ -119,9 +122,22 @@ class _MediaGridState extends State<MediaGrid> {
 | 
			
		||||
              type: _selectedType,
 | 
			
		||||
              mode: _selectedMode,
 | 
			
		||||
              random: _random,
 | 
			
		||||
              tagname: _selectedTag,
 | 
			
		||||
            ),
 | 
			
		||||
          ),
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        if (newTag != null) {
 | 
			
		||||
          setState(() {
 | 
			
		||||
            if (newTag == '___empty___') {
 | 
			
		||||
              _selectedTag = null;
 | 
			
		||||
            }
 | 
			
		||||
            else {
 | 
			
		||||
              _selectedTag = newTag;
 | 
			
		||||
            }
 | 
			
		||||
            _refreshMedia();
 | 
			
		||||
          });
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    } catch (e) {
 | 
			
		||||
      if (mounted) {
 | 
			
		||||
@@ -153,9 +169,9 @@ class _MediaGridState extends State<MediaGrid> {
 | 
			
		||||
                  _refreshMedia();
 | 
			
		||||
                });
 | 
			
		||||
              },
 | 
			
		||||
            )
 | 
			
		||||
          ]
 | 
			
		||||
        )
 | 
			
		||||
            ),
 | 
			
		||||
          ],
 | 
			
		||||
        ),
 | 
			
		||||
      ),
 | 
			
		||||
      bottomNavigationBar: BottomAppBar(
 | 
			
		||||
        color: const Color.fromARGB(255, 43, 43, 43),
 | 
			
		||||
@@ -228,51 +244,105 @@ class _MediaGridState extends State<MediaGrid> {
 | 
			
		||||
          ),
 | 
			
		||||
        ),
 | 
			
		||||
      ),
 | 
			
		||||
      body: RefreshIndicator(
 | 
			
		||||
        onRefresh: _refreshMedia,
 | 
			
		||||
        child: GridView.builder(
 | 
			
		||||
          controller: _scrollController,
 | 
			
		||||
          gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
 | 
			
		||||
            crossAxisCount: _calculateCrossAxisCount(context),
 | 
			
		||||
            crossAxisSpacing: 5.0,
 | 
			
		||||
            mainAxisSpacing: 5.0,
 | 
			
		||||
          ),
 | 
			
		||||
          itemCount: mediaItems.length + (isLoading ? 1 : 0),
 | 
			
		||||
          itemBuilder: (context, index) {
 | 
			
		||||
            if (index >= mediaItems.length) {
 | 
			
		||||
              return const Center(child: CircularProgressIndicator());
 | 
			
		||||
            }
 | 
			
		||||
            final item = mediaItems[index];
 | 
			
		||||
 | 
			
		||||
            return InkWell(
 | 
			
		||||
              onTap: () => _navigateToDetail(item),
 | 
			
		||||
              child: Stack(
 | 
			
		||||
                fit: StackFit.expand,
 | 
			
		||||
                children: <Widget>[
 | 
			
		||||
                  CachedNetworkImage(
 | 
			
		||||
                    imageUrl: item.thumbnailUrl,
 | 
			
		||||
                    fit: BoxFit.cover,
 | 
			
		||||
                    placeholder: (context, url) => SizedBox.shrink(),
 | 
			
		||||
                    errorWidget: (context, url, error) => Icon(Icons.error),
 | 
			
		||||
                  ),
 | 
			
		||||
                  Align(
 | 
			
		||||
                    alignment: FractionalOffset.bottomRight,
 | 
			
		||||
                    child: Icon(
 | 
			
		||||
                      Icons.square,
 | 
			
		||||
                      color: switch (item.mode) {
 | 
			
		||||
                        1 => Colors.green,
 | 
			
		||||
                        2 => Colors.red,
 | 
			
		||||
                        _ => Colors.yellow
 | 
			
		||||
                      },
 | 
			
		||||
                      size: 15.0
 | 
			
		||||
                    ),
 | 
			
		||||
                  ),
 | 
			
		||||
                ],
 | 
			
		||||
      body: Stack(
 | 
			
		||||
        children: [
 | 
			
		||||
          RefreshIndicator(
 | 
			
		||||
            onRefresh: _refreshMedia,
 | 
			
		||||
            child: GridView.builder(
 | 
			
		||||
              controller: _scrollController,
 | 
			
		||||
              gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
 | 
			
		||||
                crossAxisCount: _calculateCrossAxisCount(context),
 | 
			
		||||
                crossAxisSpacing: 5.0,
 | 
			
		||||
                mainAxisSpacing: 5.0,
 | 
			
		||||
              ),
 | 
			
		||||
            );
 | 
			
		||||
          },
 | 
			
		||||
        ),
 | 
			
		||||
              itemCount: mediaItems.length + (isLoading ? 1 : 0),
 | 
			
		||||
              itemBuilder: (context, index) {
 | 
			
		||||
                if (index >= mediaItems.length) {
 | 
			
		||||
                  return const Center(child: CircularProgressIndicator());
 | 
			
		||||
                }
 | 
			
		||||
                final item = mediaItems[index];
 | 
			
		||||
 | 
			
		||||
                return InkWell(
 | 
			
		||||
                  onTap: () => _navigateToDetail(item),
 | 
			
		||||
                  child: Stack(
 | 
			
		||||
                    fit: StackFit.expand,
 | 
			
		||||
                    children: <Widget>[
 | 
			
		||||
                      CachedNetworkImage(
 | 
			
		||||
                        imageUrl: item.thumbnailUrl,
 | 
			
		||||
                        fit: BoxFit.cover,
 | 
			
		||||
                        placeholder: (context, url) => SizedBox.shrink(),
 | 
			
		||||
                        errorWidget: (context, url, error) => Icon(Icons.error),
 | 
			
		||||
                      ),
 | 
			
		||||
                      Align(
 | 
			
		||||
                        alignment: FractionalOffset.bottomRight,
 | 
			
		||||
                        child: Icon(
 | 
			
		||||
                          Icons.square,
 | 
			
		||||
                          color: switch (item.mode) {
 | 
			
		||||
                            1 => Colors.green,
 | 
			
		||||
                            2 => Colors.red,
 | 
			
		||||
                            _ => Colors.yellow,
 | 
			
		||||
                          },
 | 
			
		||||
                          size: 15.0,
 | 
			
		||||
                        ),
 | 
			
		||||
                      ),
 | 
			
		||||
                    ],
 | 
			
		||||
                  ),
 | 
			
		||||
                );
 | 
			
		||||
              },
 | 
			
		||||
            ),
 | 
			
		||||
          ),
 | 
			
		||||
          if (_selectedTag != null)
 | 
			
		||||
            Positioned(
 | 
			
		||||
              bottom: 20,
 | 
			
		||||
              left: MediaQuery.of(context).size.width * 0.2,
 | 
			
		||||
              right: MediaQuery.of(context).size.width * 0.2,
 | 
			
		||||
              child: Container(
 | 
			
		||||
                padding: const EdgeInsets.symmetric(
 | 
			
		||||
                  vertical: 10,
 | 
			
		||||
                  horizontal: 20,
 | 
			
		||||
                ),
 | 
			
		||||
                decoration: BoxDecoration(
 | 
			
		||||
                  color: Colors.black.withValues(alpha: 0.8),
 | 
			
		||||
                  borderRadius: BorderRadius.circular(12),
 | 
			
		||||
                ),
 | 
			
		||||
                child: Row(
 | 
			
		||||
                  mainAxisAlignment: MainAxisAlignment.spaceBetween,
 | 
			
		||||
                  children: [
 | 
			
		||||
                    Text(
 | 
			
		||||
                      'Tag: $_selectedTag',
 | 
			
		||||
                      style: const TextStyle(color: Colors.white),
 | 
			
		||||
                    ),
 | 
			
		||||
                    IconButton(
 | 
			
		||||
                      icon: const Icon(Icons.close, color: Colors.white),
 | 
			
		||||
                      onPressed: () {
 | 
			
		||||
                        setState(() {
 | 
			
		||||
                          _selectedTag = null;
 | 
			
		||||
                          _refreshMedia();
 | 
			
		||||
                        });
 | 
			
		||||
                        _scrollController.animateTo(
 | 
			
		||||
                          0.0,
 | 
			
		||||
                          duration: const Duration(milliseconds: 500),
 | 
			
		||||
                          curve: Curves.easeOut,
 | 
			
		||||
                        );
 | 
			
		||||
                      },
 | 
			
		||||
                    ),
 | 
			
		||||
                  ],
 | 
			
		||||
                ),
 | 
			
		||||
              ),
 | 
			
		||||
            ),
 | 
			
		||||
        ],
 | 
			
		||||
      ),
 | 
			
		||||
      /*floatingActionButton: FloatingActionButton(
 | 
			
		||||
        backgroundColor: Colors.black.withValues(alpha: 0.8),
 | 
			
		||||
        child: const Icon(Icons.arrow_upward, color: Colors.white),
 | 
			
		||||
        onPressed: () {
 | 
			
		||||
          _scrollController.animateTo(
 | 
			
		||||
            0.0,
 | 
			
		||||
            duration: const Duration(milliseconds: 500),
 | 
			
		||||
            curve: Curves.easeOut,
 | 
			
		||||
          );
 | 
			
		||||
        },
 | 
			
		||||
      ),*/
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -8,12 +8,14 @@ Future<List<MediaItem>> fetchMedia({
 | 
			
		||||
  String? type,
 | 
			
		||||
  int? mode,
 | 
			
		||||
  bool? random,
 | 
			
		||||
  String? tag,
 | 
			
		||||
}) async {
 | 
			
		||||
  final Uri url = Uri.parse('https://api.f0ck.me/items/get').replace(
 | 
			
		||||
    queryParameters: {
 | 
			
		||||
      'type': type ?? 'image',
 | 
			
		||||
      'mode': (mode ?? 0).toString(),
 | 
			
		||||
      'random': (random! ? 1 : 0).toString(),
 | 
			
		||||
      if (tag != null) 'tag': tag,
 | 
			
		||||
      if (older != null) 'older': older,
 | 
			
		||||
    },
 | 
			
		||||
  );
 | 
			
		||||
 
 | 
			
		||||
@@ -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.23+23
 | 
			
		||||
version: 1.0.24+24
 | 
			
		||||
 | 
			
		||||
environment:
 | 
			
		||||
  sdk: ^3.9.0-100.2.beta
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user