0

I am trying to save a favourite list of articles in my news app in Flutter by using shared preferences, I'd need to pass data article from JSON model into the favourite article page once the article is bookmarked. Once I save the article I got this message in my terminal, but when I go to the favourite page, the page is empty.

Does anybody know how to solve this issue?

Article page once bookmarked enter image description here

Saved article message enter image description here

Empty favourite article page enter image description here

Here my code

Article model

class Article{
  String? urlImage;
  String? urlImageSource;
  String? title;
  final String? description;

  Article({
    required this.urlImage,
    this.urlImageSource,
    required this.title,
    required this.description,
  });

  factory Article.fromJson(Map<String, dynamic> json) => Article(
    urlImage:       json["_embedded"]["wp:featuredmedia"][0]["link"],
    urlImageSource: json["_embedded"]['wp:featuredmedia'][0]["media_details"]["sizes"]["thumbnail"]["source_url"],
    title:          json["title"]["rendered"],
    description:    json['content']['rendered'],
  );

  Map<String, dynamic> toJson() {
    final Map<String, dynamic> data = <String, dynamic>{};

    data['urlImage']       = urlImage;
    data['urlImageSource'] = urlImageSource;
    data['title']          = title;
    data['desciption']     = description;

    date:['urlImage'] != null ? ['urlImage'].toString().replaceFirst('https:', 'urlImageSource') : null;

    return data;
  }
}

Article page

class ArticlePage extends StatefulWidget {
  const ArticlePage({Key? key, required this.data,}) : super(key: key);
  final data;

  @override
  _ArticlePageState createState() => _ArticlePageState(data);
}

class _ArticlePageState extends State<ArticlePage> {
  final data;
  //late List _post;
  _ArticlePageState(this.data);
  /// Save article
  TextEditingController controller =  TextEditingController();
  late SharedPreferences preferences;
  late List<Article>? _posts = preferences.getStringList('articles')?.cast<Article>();
  //static const _savedArticle = "articles";
  late bool _isSaved = false;
  //late final bool _isRemoved = false;

  @override
  void initState() {
    super.initState();
    _savedArticle(Article);
    _persistentPrefences();

    // SharedPreferences.getInstance().then((preferences) {
    //   preferences.setBool("articles", _isSaved);
    //   setState(() {
    //     _isSaved = _isSaved;
    //   });
    // });
    _posts = [];
  }
  /// Save articles
  Future<void> _savedArticle(Article) async {
    preferences = await SharedPreferences.getInstance();
    preferences.setBool('_isSaved', true);
    await preferences.setStringList('articles', <String>[
      data["_embedded"]["wp:featuredmedia"][0]["link"],
      data["title"]["rendered"].replaceAll("<p>", "").replaceAll("&#8217;", "'").replaceAll("</p>", ""),
    ]);

    //Map<String, dynamic> jsonDetails = jsonDecode(preferences.getString('articles')!);
    // Article article = Article.fromJson(jsonDetails);
    //
    // if(jsonDetails.isNotEmpty){
    //   print(data["_embedded"]["wp:featuredmedia"][0]["link"],);
    //   print(data["title"]["rendered"].replaceAll("<p>", "").replaceAll("&#8217;", "'").replaceAll("</p>", ""),);
    //   data.value =  Image.network(data);
    //   data.value =  Text(data);
    // }

    SharedPreferences.getInstance().then((preferences) {
      preferences.setBool("articles", _isSaved);
      setState(() {
        _isSaved = _isSaved;
      });
    });

    if (_isSaved) {
      _isSaved = false;
      print("Ready to save article");
    } else {
      _isSaved = true;
        CoolAlert.show(
          context: context,
          type: CoolAlertType.success,
          title: "Articolo Salvato",
          text: 'Hai salvato l\'articolo nella pagina dei preferiti',
          backgroundColor: Colors.white,
          autoCloseDuration: const Duration(seconds: 3),
          confirmBtnText: "Ok",
          confirmBtnColor: const Color(0xFF0D47A1),
          confirmBtnTextStyle: const TextStyle(color: Colors.white, fontWeight:FontWeight.w600, fontSize: 18.0,fontFamily: "Raleway"),
          onConfirmBtnTap: () {
            Navigator.push(
              context,
              MaterialPageRoute(
                builder: (context) => SavedArticlesPage(data: data),
              ),
            );
          },
        );
        print("Saved article"
            "${data["_embedded"]["wp:featuredmedia"][0]["link"]},"
            "${data["title"]["rendered"].toString().replaceAll("<p>", "").replaceAll("&#8217;", "'").replaceAll("</p>", "")}",
        );
        var preferences = await SharedPreferences.getInstance(); 
    }
  }

  /// Store articles
  void _storedArticles(List<String> _posts) async {
    var preferences = await SharedPreferences.getInstance();
    late final List<String>? _posts = preferences.getStringList('articles',);
    // Retreive article
    bool status = preferences.getBool('_isSaved') ?? false;
    //var liked = preferences.getBool(_savedArticle);
    setState(() => this._isSaved = _isSaved);
  }
  /// Persistent articles
  void _persistentPrefences() async {
    setState(() => _isSaved = !_isSaved);
    var preferences = await SharedPreferences.getInstance();
    late final List<String>? _posts = preferences.getStringList('articles',);
    //preferences.setBool(_savedArticle, _isSaved);
  }


  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.white,
      body: CustomScrollView(
        slivers: <Widget>[
          SliverAppBar(
            leading: Builder(
              builder: (BuildContext context) {
                return GestureDetector(
                  child: Center(
                    child: Container(
                      color: Colors.white70.withOpacity(0),
                      child: Container(
                        height: 30,
                        width: 30,
                        decoration: const BoxDecoration(
                          image: DecorationImage(
                            image: AssetImage(
                              'assets/images/previous.png',
                            ),
                          ),
                        ),
                      ),
                    ),
                  ),
                  onTap: () {
                    Navigator.of(context).pop();
                  },
                );
              },
            ),
            flexibleSpace: FlexibleSpaceBar(
              centerTitle: true,
              background: CachedNetworkImage(
                imageUrl: data["_embedded"]['wp:featuredmedia'][0]["media_details"]["sizes"]["medium"]["source_url"],
                // data["_embedded"]["wp:featuredmedia"][0]["link"],
                fit: BoxFit.cover,
                placeholder: (context, url) => Image.asset("assets/gif/shimmer.gif", fit: BoxFit.cover,),
                errorWidget: (context, url, error) => Image.asset("assets/images/unloadedImage.png", width: 250, height: 250),
              ),
            ),
            actions: [
              Container(
                margin: const EdgeInsets.only(top: 12.0, bottom: 10.0),
                width: 35,
                decoration: BoxDecoration(
                  borderRadius: BorderRadius.circular(50),
                  color: Colors.white,
                ),
                child: Center(
                    child: IconButton(
                      icon: _isSaved
                          ? const Icon(Icons.bookmark_outlined, color: Color(0xFF0D47A1), size: 18,)
                          :  const Icon(Icons.bookmark_border_rounded, color: Color(0xFF0D47A1), size: 18,),
                      onPressed: () async {
                       await  _savedArticle(Article);
                      },
                    ),
                  ),
              ),
              const SizedBox(width: 15,),
            ],
            floating: true,
            expandedHeight: 320,
          ),
          SliverList(
            delegate: SliverChildListDelegate([
              Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: <Widget>[
                  const SizedBox(height: 20,),
                  // Title container
                  Container(
                    padding: const EdgeInsets.all(16),
                    child: Text(data["title"]["rendered"]
                        .toString()
                        .replaceAll("<p>", "")
                        .replaceAll("&#8217;", "'")
                        .replaceAll("</p>", ""),
                      style: const TextStyle(
                        fontWeight: FontWeight.w600,
                        fontSize: 20,
                        fontFamily: "Raleway",
                      ),
                    ),
                  ),
                  const SizedBox(height: 0),
                  Container(
                    padding: const EdgeInsets.all(16),
                    child: HtmlWidget(
                      data['content']['rendered']
                          .toString()
                          .replaceAll("<p>", "")
                          .replaceAll("&#8217;", "'")
                          .replaceAll("</p>", ""),
                    ),
                  ),
                  const SizedBox(height: 20),
                ],
              ),
            ],
            ),
          ),
        ],
      ),
    );
  }
}

Favourite article page

class SavedArticlesPage extends StatefulWidget {
  const SavedArticlesPage({Key? key, required this.data}) : super(key: key);
  final data;
  @override
  _SavedArticlesPageState createState() => _SavedArticlesPageState(this.data);
}

class _SavedArticlesPageState extends State<SavedArticlesPage> {
  final sharedPreferences = SharedPreferences.getInstance();
  final data;
  static var preferences;
  var i;
  _SavedArticlesPageState(this.data);

  late List _post;
  static const savedArticle = "articles";
  late bool _loadedArticle = false;
  final List<Article>? _posts = preferences?.getStringList('articles').toList();

  @override
  void initState() {
    super.initState();
    _loadArticles();
    _clearArticlePermanently();
  }
  /// Get articles list of strings from 'articles' key and Save persistent articles.
  Future<List<Article>?> _loadArticles() async {
    //preferences ??= await SharedPreferences.getInstance();
    if(sharedPreferences == null){
      preferences = await SharedPreferences.getInstance();
    }
    //var liked = preferences!.getBool(_loadedArticle);
    await preferences.getStringList(_posts);

    preferences.setBool(_loadedArticle, _loadedArticle);

    print("Article Loaded");

    setState(() {
      this._loadedArticle = true;
    });

    print("Article Loaded");
    return _posts;
  }

  /// Delete articles permanently
  void _clearArticlePermanently() async {
    //SharedPreferences preferences = await SharedPreferences.getInstance();
    final removeArticle = await preferences.remove('articles');
    final clearArticle = await preferences.clear('articles');
    setState(() {
      this._posts;
    });
    print("Article removed");
  }


  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.white,
      appBar: AppBar(
        elevation: 0,
        backgroundColor: Colors.blue[900],
        centerTitle: true,
        title: const Text("Articoli Preferiti",
          style: TextStyle(
              color: Colors.white,
              fontFamily: "Raleway",
              fontSize: 18,
              fontWeight: FontWeight.w600),
        ),
        leading: Builder(
          builder: (BuildContext context) {
            return IconButton(
              icon: const Icon(
                Icons.arrow_back_ios_rounded,
                color: Colors.white,
              ),
              onPressed: () {Navigator.pop(context);},
            );
          },
        ),
      ),
      body: Padding(
        padding: const EdgeInsets.all(12),
        child: generateArticleList(),
      ),
    );
  }

  generateArticleList() {
    return ListView.builder(
      itemCount: _posts == null ? 0 : _posts!.length,
      itemBuilder: (context, index) {
        var article  = _posts![index];

        return Dismissible(
          key: Key(_post as String),
          child: Card(
            margin: const EdgeInsets.only(top: 8),
            elevation: 5,
            shadowColor: Colors.black26,
            color: Colors.white,
            child: InkWell(
              child: ClipRRect(
                borderRadius: BorderRadius.circular(10),
                child: Column(
                  mainAxisSize: MainAxisSize.min,
                  children: [
                    SizedBox(
                      height: 190,
                      width: double.infinity,
                      child: CachedNetworkImage(
                        imageUrl: _post[i]["_embedded"]['wp:featuredmedia'][0]["media_details"]["sizes"]["medium"]["source_url"],
                        //_posts[index] as String,
                        //_posts![i] as String,
                        fit: BoxFit.cover,
                        placeholder: (context, url) => Image.asset("assets/gif/shimmer.gif",
                          width: double.infinity,
                          height: 190,
                          fit: BoxFit.cover,
                        ),
                        errorWidget: (context, url, error) => Image.asset("assets/images/unloadedImage.png",
                            width: 250, height: 250),
                      ),
                    ),
                    // Title article
                    Column(
                      children: [
                        Padding(
                          padding: const EdgeInsets.only(left:16, top: 16, bottom: 16),
                          child: Row(
                            children: [
                              Expanded(
                                child: Text(
                                  _post[i]["title"]["rendered"]
                                      .toString()
                                      .replaceAll("<p>", "")
                                      .replaceAll("&#8217;", "'")
                                      .replaceAll("</p>", "")
                                      .toString(),
                                  //_posts[index] as String,
                                  style: const TextStyle(
                                    fontWeight: FontWeight.w600,
                                    fontSize: 20,
                                    fontFamily: "Raleway",
                                  ),
                                  overflow: TextOverflow.ellipsis,
                                  maxLines: 2,
                                  //softWrap: false,
                                ),
                              ),
                            ],
                          ),
                        )
                      ],
                    ),
                  ],
                ),
              ),
              onTap: () {
                Navigator.push(
                  context,
                  MaterialPageRoute(
                    builder: (context) => ArticlePage(
                      data: data,
                        //data: _post[i]
                    ),
                  ),
                );
              }
            ),
          ),

          //background: slideRightBackground(),
          secondaryBackground: slideLeftBackground(),
          confirmDismiss: (direction) async {
            if (direction == DismissDirection.endToStart) {
              final bool res = await showDialog(
                  context: context,
                  builder: (BuildContext context) {
                    return AlertDialog(
                      content: const Text("Sei sicuro di voler eliminare l'articolo?",
                        style: TextStyle(
                          color: Color(0xFf6d6e75),
                          fontFamily: "Raleway",
                          fontWeight: FontWeight.w500,
                        ),
                      ),
                      actions: <Widget>[
                        /// Cancel btn
                        Container(
                          height: 35,
                          decoration: const BoxDecoration(
                              color: Color(0xFFeef1f7),
                              borderRadius: BorderRadius.all(Radius.circular(5))
                          ),
                          child: MaterialButton(
                            child: const Text('No',
                              style: TextStyle(
                                fontFamily: "Raleway",
                                color: Color(0xFF6b6f73),
                                fontWeight: FontWeight.w600,
                              ),
                            ),
                            onPressed: () => Navigator.of(context).pop(true),
                            elevation: 0,
                          ),
                        ),
                        /// Delete btn
                        Container(
                          height: 35,
                          decoration: const BoxDecoration(
                              color: Color(0xFF0D47A1),
                              borderRadius: BorderRadius.all(Radius.circular(5))
                          ),
                          child: MaterialButton(
                            child: const Text('Elimina',
                              style: TextStyle(
                                color: Colors.white,
                                fontFamily: "Raleway",
                                fontWeight: FontWeight.w600,
                              ),
                            ),
                            onPressed: _clearArticlePermanently,
                            elevation: 0,
                          ),
                        )
                      ],
                    );
                  });
              return res;
            }
            return null;
              // ArticlePage(data: _post[i]);
              //ArticlePage(data: data);
            //ArticlePage(data: data);
          },
        );
      },
    );
  }
  /// Empty btn
  // Widget slideRightBackground() {
  //   return Container();
  // }
  /// Right bottom delete article
  Widget slideLeftBackground() {
    return Container(
      color: Colors.red,
      child: Align(
        child: Row(
          mainAxisAlignment: MainAxisAlignment.end,
          children: const <Widget>[
            Icon(Icons.delete, color: Colors.white,),
            SizedBox(width: 10,),
            Text("Elimina",
              style: TextStyle(
                color: Colors.white,
                fontWeight: FontWeight.w700,
                fontFamily: "Raleway",
              ),
              textAlign: TextAlign.right,
            ),
            SizedBox(width: 20,),
          ],
        ),
        alignment: Alignment.centerRight,
      ),
    );
  }
}

0 Answers0