1

So, I'm pretty new on Flutter (just about a week) and dart but I hope this Question is not toooooo stupid:

I'm trying to create an App for an existing Website (a forum). I dont want to use the flutter WebView, because I want to create an comepletly new Interface (The Website is not optimized for mobile View, that's why I'm builing this App).

The (german) Forum: https://www.porsche-914.com/forum

I want to fetch the single forum topics as well as the posts itself including username, title and date and then map the text to a custom widget to display it. The Widget Part is no problem, it's already done but I cant figure out how to fetch that data from the website and how to store it.

I don't know, hope you can help me...

Thanks a lot for the taken time.

How the mapping should work:

fetched[index].title, fetched[index].text

Center(
                  child: NeumorphismPost(
                    title: fetched[index].title,
                    titleColor: Theme.of(context).cardColor,
                    textColor: Theme.of(context).cardColor,
                    text: fetched[index].text,
                    width: 370,
                    onTap: () {
                      _popupPage(context,
                          title: fetched[index].title,
                          child: Padding(
                            padding: const EdgeInsets.all(15.0),
                            child: Text(
                              fetched[index].text,
                              style: TextStyle(
                                  color: Theme.of(context).cardColor,
                                  fontSize: 18),
                            ),
                          ),
                       );
                    },
                  ),
                ),

This is my custom Widget:

import 'package:flutter/material.dart';

class NeumorphismPost extends StatefulWidget {
  final double width;
  final double height;
  final double borderRadius;
  final String title;
  final String text;
  final Color titleColor;
  final Color textColor;
  final double titleSize;
  final double textSize;

  final Function onTap;

  NeumorphismPost({
    this.width = 185,
    this.height = 185,
    this.title = "Title",
    this.text = "",
    this.borderRadius = 20,
    this.titleColor = const Color(0xFF424242),
    this.textColor = const Color(0xFF424242),
    this.titleSize = 22,
    this.textSize = 18,
    required this.onTap,
  });

  @override
  State<NeumorphismPost> createState() => _NeumorphismPostState();
}

class _NeumorphismPostState extends State<NeumorphismPost> {
  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.all(8.0),
      child: Wrap(
        direction: Axis.vertical,
        children: [
          SingleChildScrollView(
            child: SizedBox(
              height: widget.height,
              width: widget.width,
              child: GestureDetector(
                onTap: () {},
                child: Scaffold(
                  backgroundColor: Colors.transparent,
                  body: SizedBox(
                    height: widget.height,
                    width: widget.width,
                    child: Center(
                      child: Container(
                        height: widget.height,
                        width: widget.width,
                        decoration: BoxDecoration(
                          color: Theme.of(context).backgroundColor,
                          borderRadius:
                              BorderRadius.circular(widget.borderRadius),
                          boxShadow: [
                            BoxShadow(
                              color: Theme.of(context).hintColor,
                              offset: const Offset(5, 5),
                              blurRadius: 15,
                              spreadRadius: 1,
                            ),
                            BoxShadow(
                              color: Theme.of(context).backgroundColor,
                              offset: Offset(-5, -5),
                              blurRadius: 15,
                              spreadRadius: 1,
                            )
                          ],
                        ),
                        child: Wrap(
                          direction: Axis.horizontal,
                          children: [
                            SingleChildScrollView(
                              child: Center(
                                child: Column(
                                  mainAxisAlignment:
                                      MainAxisAlignment.spaceEvenly,
                                  children: <Widget>[
                                    Wrap(
                                      direction: Axis.horizontal,
                                      children: [
                                        SizedBox(
                                          height: widget.height / 3,
                                          child: Wrap(
                                            children: [
                                              Column(
                                                mainAxisAlignment:
                                                    MainAxisAlignment.start,
                                                crossAxisAlignment:
                                                    CrossAxisAlignment.start,
                                                children: [
                                                  Padding(
                                                    padding: const EdgeInsets
                                                            .symmetric(
                                                        horizontal: 15,
                                                        vertical: 15),
                                                    child: Text(
                                                      widget.title,
                                                      textAlign:
                                                          TextAlign.center,
                                                      overflow:
                                                          TextOverflow.fade,
                                                      style: TextStyle(
                                                        fontSize:
                                                            widget.titleSize,
                                                        fontWeight:
                                                            FontWeight.bold,
                                                        color:
                                                            widget.titleColor,
                                                      ),
                                                    ),
                                                  ),
                                                ],
                                              ),
                                            ],
                                          ),
                                        ),
                                      ],
                                    ),
                                    Wrap(
                                      direction: Axis.horizontal,
                                      children: [
                                        GestureDetector(
                                          onTap: () {
                                            widget.onTap();
                                          },
                                          child: Padding(
                                            padding: const EdgeInsets.symmetric(
                                                vertical: 5),
                                            child: SizedBox(
                                              height: widget.height / 1.38,
                                              child: Padding(
                                                padding:
                                                    const EdgeInsets.symmetric(
                                                        horizontal: 15,
                                                        vertical: 15),
                                                child: Text(
                                                  widget.text,
                                                  textAlign: TextAlign.center,
                                                  style: TextStyle(
                                                    fontSize: widget.textSize,
                                                    fontWeight:
                                                        FontWeight.normal,
                                                    color: widget.textColor,
                                                  ),
                                                ),
                                              ),
                                            ),
                                          ),
                                        ),
                                      ],
                                    ),
                                  ],
                                ),
                              ),
                            ),
                          ],
                        ),
                      ),
                    ),
                  ),
                ),
              ),
            ),
          ),
        ],
      ),
    );
  }
}

1 Answer 1

3

From my point of view, you want to create a scraper. I checked the target website (https://www.porsche-914.com/forum), it can be scraped without any special technique (they don't have many Ajax calls (you may test by using Postman)). So it is a possible task. My suggestion flow is:

  • Load the raw HTML using any technique (http, dio, inappwebview ...)
  • Parse it using BeautifulSoup (https://pub.dev/packages/beautiful_soup_dart) (or any parser; it is just my favorite parser.)
  • Map it to your existing model.

Here is some example code. Hope it helps:

import 'package:http/http.dart' as http;
import 'package:beautiful_soup_dart/beautiful_soup.dart';

class TestParse {
  excuteSample() async {
    var url = Uri.parse('https://www.porsche-914.com/forum');
    var response = await http.get(url);
    BeautifulSoup bs = BeautifulSoup(response.body);
    final allHeaderName = bs.findAll('td', attrs: {'class': 'oben'});
    allHeaderName.forEach((element) {
      print('the header: ${element.text}');
    });
  }
}

Here is the result:

enter image description here

The final result you need is a long story and long code. Hope this will give you a starting point.

UPDATE: I added the full demo code, using your requested code:

import 'package:beautiful_soup_dart/beautiful_soup.dart';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;

void main() => runApp(const MaterialApp(home: MyApp()));

class MyApp extends StatefulWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  final testparse = TestParse();
  List<String> yourModelPleaseReplaceThis = [];
  @override
  void initState() {
    super.initState();
    excuteRequestAndParse();
  }

  excuteRequestAndParse() async {
    final result =
        await testparse.excuteSample(); //[1] i guess you missing this await
    setState(() {
      yourModelPleaseReplaceThis = result;
    });
  }

  @override
  Widget build(BuildContext context) {
    return ListView.builder(
      itemBuilder: (context, index) {
        return Center(
          child: NeumorphismPost(
            title: yourModelPleaseReplaceThis[index],
            titleColor: Theme.of(context).cardColor,
            textColor: Theme.of(context).cardColor,
            text: yourModelPleaseReplaceThis[index],
            width: 370,
            onTap: () {
              //THIS CODE BELOW IS YOUR CODE....
            },
          ),
        );
      },
      itemCount: yourModelPleaseReplaceThis.length,
    );
  }
}

// BELOW IS TESTING CODE....
class TestParse {
  Future<List<String>> excuteSample() async {
    var url = Uri.parse('https://www.porsche-914.com/forum');
    var response = await http.get(url);
    BeautifulSoup bs = BeautifulSoup(response.body);
    final allHeaderName = bs.findAll('td', attrs: {'class': 'oben'});
    allHeaderName.forEach((element) {
      print('the header: ${element.text}');
    });
    return Future.value(allHeaderName.map((e) => e.text).toList());
  }
}

class NeumorphismPost extends StatefulWidget {
  final double width;
  final double height;
  final double borderRadius;
  final String title;
  final String text;
  final Color titleColor;
  final Color textColor;
  final double titleSize;
  final double textSize;

  final Function onTap;

  NeumorphismPost({
    this.width = 185,
    this.height = 185,
    this.title = "Title",
    this.text = "",
    this.borderRadius = 20,
    this.titleColor = const Color(0xFF424242),
    this.textColor = const Color(0xFF424242),
    this.titleSize = 22,
    this.textSize = 18,
    required this.onTap,
  });

  @override
  State<NeumorphismPost> createState() => _NeumorphismPostState();
}

class _NeumorphismPostState extends State<NeumorphismPost> {
  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.all(8.0),
      child: Wrap(
        direction: Axis.vertical,
        children: [
          SingleChildScrollView(
            child: SizedBox(
              height: widget.height,
              width: widget.width,
              child: GestureDetector(
                onTap: () {},
                child: Scaffold(
                  backgroundColor: Colors.transparent,
                  body: SizedBox(
                    height: widget.height,
                    width: widget.width,
                    child: Center(
                      child: Container(
                        height: widget.height,
                        width: widget.width,
                        decoration: BoxDecoration(
                          color: Theme.of(context).backgroundColor,
                          borderRadius:
                              BorderRadius.circular(widget.borderRadius),
                          boxShadow: [
                            BoxShadow(
                              color: Theme.of(context).hintColor,
                              offset: const Offset(5, 5),
                              blurRadius: 15,
                              spreadRadius: 1,
                            ),
                            BoxShadow(
                              color: Theme.of(context).backgroundColor,
                              offset: Offset(-5, -5),
                              blurRadius: 15,
                              spreadRadius: 1,
                            )
                          ],
                        ),
                        child: Wrap(
                          direction: Axis.horizontal,
                          children: [
                            SingleChildScrollView(
                              child: Center(
                                child: Column(
                                  mainAxisAlignment:
                                      MainAxisAlignment.spaceEvenly,
                                  children: <Widget>[
                                    Wrap(
                                      direction: Axis.horizontal,
                                      children: [
                                        SizedBox(
                                          height: widget.height / 3,
                                          child: Wrap(
                                            children: [
                                              Column(
                                                mainAxisAlignment:
                                                    MainAxisAlignment.start,
                                                crossAxisAlignment:
                                                    CrossAxisAlignment.start,
                                                children: [
                                                  Padding(
                                                    padding: const EdgeInsets
                                                            .symmetric(
                                                        horizontal: 15,
                                                        vertical: 15),
                                                    child: Text(
                                                      widget.title,
                                                      textAlign:
                                                          TextAlign.center,
                                                      overflow:
                                                          TextOverflow.fade,
                                                      style: TextStyle(
                                                        fontSize:
                                                            widget.titleSize,
                                                        fontWeight:
                                                            FontWeight.bold,
                                                        color:
                                                            widget.titleColor,
                                                      ),
                                                    ),
                                                  ),
                                                ],
                                              ),
                                            ],
                                          ),
                                        ),
                                      ],
                                    ),
                                    Wrap(
                                      direction: Axis.horizontal,
                                      children: [
                                        GestureDetector(
                                          onTap: () {
                                            widget.onTap();
                                          },
                                          child: Padding(
                                            padding: const EdgeInsets.symmetric(
                                                vertical: 5),
                                            child: SizedBox(
                                              height: widget.height / 1.38,
                                              child: Padding(
                                                padding:
                                                    const EdgeInsets.symmetric(
                                                        horizontal: 15,
                                                        vertical: 15),
                                                child: Text(
                                                  widget.text,
                                                  textAlign: TextAlign.center,
                                                  style: TextStyle(
                                                    fontSize: widget.textSize,
                                                    fontWeight:
                                                        FontWeight.normal,
                                                    color: widget.textColor,
                                                  ),
                                                ),
                                              ),
                                            ),
                                          ),
                                        ),
                                      ],
                                    ),
                                  ],
                                ),
                              ),
                            ),
                          ],
                        ),
                      ),
                    ),
                  ),
                ),
              ),
            ),
          ),
        ],
      ),
    );
  }
}

This is the result: enter image description here

Please note:

  • This list I created is for sample, so it is just a list of Strings. You should create a complete Model.
Sign up to request clarification or add additional context in comments.

2 Comments

Ok, that was quick, thank you so much, that's a great base to build on. I got now another problemt tho, because as I try to map everything on a Widget I get the error message 'type 'Future<dynamic>' is not a subtype of type 'Widget' in type cast'... Any idea how to fix that?
I guess it may be a problem with your async/await, so I updated the full demo(using your code), It so long and I can't paste in comment, so please check section "UPDATE" in original post. Hope it help!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.