profile.ts 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. import { Component, ViewChild } from "@angular/core";
  2. import {
  3. IonicPage,
  4. NavController,
  5. NavParams,
  6. InfiniteScroll,
  7. Content,
  8. LoadingController
  9. } from "ionic-angular";
  10. import { TwitterApiProvider } from "../../providers/twitter-api/twitter-api";
  11. import { P2pStorageIpfsProvider } from "../../providers/p2p-storage-ipfs/p2p-storage-ipfs";
  12. import { P2pDatabaseGunProvider } from "../../providers/p2p-database-gun/p2p-database-gun";
  13. @IonicPage()
  14. @Component({
  15. selector: "page-profile",
  16. templateUrl: "profile.html"
  17. })
  18. export class ProfilePage {
  19. user: any = [];
  20. tweets: any[];
  21. oldestLoadedTweetId;
  22. enableRefresh: boolean = true;
  23. enableInfiniteScroll: boolean = true;
  24. @ViewChild(Content)
  25. content: Content;
  26. constructor(
  27. public navCtrl: NavController,
  28. private loadingCtrl: LoadingController,
  29. public navParams: NavParams,
  30. private twitter: TwitterApiProvider,
  31. private ipfs: P2pStorageIpfsProvider,
  32. private gun: P2pDatabaseGunProvider
  33. ) {}
  34. ionViewDidLoad() {
  35. // Show loading indicator
  36. const loading = this.loadingCtrl.create();
  37. loading.present();
  38. // Read user id
  39. const userId = this.navParams.get("userId");
  40. // Fetch user details from Twitter
  41. this.twitter.fetchUser(userId).then(res => (this.user = res));
  42. // Load user's timeline from Twitter and P2P
  43. this.loadTimeline(userId).then(res => {
  44. if (res.length > 0) {
  45. // Store tweets
  46. this.tweets = res;
  47. // Save oldest tweet's id for next load more
  48. this.oldestLoadedTweetId = res
  49. .filter(tweet => !tweet.private_tweet)
  50. .reduce((acc, cur) => (acc.id < cur.id ? acc : cur))["id"];
  51. }
  52. // Hide loading indicator
  53. loading.dismiss();
  54. });
  55. }
  56. doRefresh(refresher) {
  57. this.loadTimeline(this.user.id_str).then(res => {
  58. if (res.length > 0) {
  59. // Replace tweets
  60. this.tweets = res;
  61. // Save oldest tweet's id for next load more
  62. this.oldestLoadedTweetId = res
  63. .filter(tweet => !tweet.private_tweet)
  64. .reduce((acc, cur) => (acc.id < cur.id ? acc : cur))["id"];
  65. }
  66. // Hide loading icon
  67. refresher.complete();
  68. });
  69. }
  70. loadMore(infiniteScroll: InfiniteScroll) {
  71. if (this.enableInfiniteScroll) {
  72. this.loadTimeline(this.user.id_str, this.oldestLoadedTweetId).then(
  73. res => {
  74. if (res.length > 0) {
  75. // Append loaded tweets
  76. this.tweets = this.tweets.concat(res);
  77. // Save oldest tweet's id for next load more
  78. this.oldestLoadedTweetId = res
  79. .filter(tweet => !tweet.private_tweet)
  80. .reduce((acc, cur) => (acc.id < cur.id ? acc : cur))["id"];
  81. }
  82. // Hide loading icon
  83. infiniteScroll.complete();
  84. }
  85. );
  86. } else {
  87. // Hide loading icon
  88. infiniteScroll.complete();
  89. }
  90. }
  91. private async loadTimeline(userId, oldestLoadedTweetId?) {
  92. // Fetch tweets from Twitter
  93. const tweets = await this.twitter.fetchUserTimeline(
  94. userId,
  95. oldestLoadedTweetId
  96. );
  97. // Determine end of time interval to look for private tweets
  98. let intervalEnd: Date;
  99. if (tweets.length < 20) {
  100. // End of timeline is reached
  101. this.enableInfiniteScroll = false;
  102. intervalEnd = new Date("2018-04-01T00:00:00");
  103. } else {
  104. const lastTweetTimestamp = tweets[tweets.length - 1].created_at;
  105. intervalEnd = new Date(lastTweetTimestamp);
  106. }
  107. // Fetch private tweet hashs from P2P DB for corresponding interval
  108. const privateTweetHashs: string[] = await this.gun.fetchPrivateTweetHashsForUserInInterval(
  109. userId,
  110. // TODO: timestamp vom vorigen oldestLoadedTweet statt new Date()
  111. new Date(),
  112. intervalEnd
  113. );
  114. if (privateTweetHashs.length) {
  115. // Load private tweets from P2P storage
  116. let privateTweets = await this.ipfs.fetchTweets(privateTweetHashs);
  117. // Add user object to private tweets
  118. privateTweets = await Promise.all(
  119. privateTweets.map(async tweet => await this.addUserToTweet(tweet))
  120. );
  121. // Combine and sort tweets
  122. return tweets
  123. .concat(privateTweets)
  124. .sort((a, b) => this.sortByDateAsc(a, b));
  125. } else {
  126. return tweets;
  127. }
  128. }
  129. private sortByDateAsc(a, b) {
  130. const dateA = new Date(a.created_at);
  131. const dateB = new Date(b.created_at);
  132. if (dateA > dateB) {
  133. return -1;
  134. } else if (dateA < dateB) {
  135. return 1;
  136. } else {
  137. return 0;
  138. }
  139. }
  140. private async addUserToTweet(tweet) {
  141. tweet.user = await this.twitter.fetchUser(tweet.user_id);
  142. return tweet;
  143. }
  144. onScroll(event) {
  145. this.enableRefresh = event.scrollTop === 0;
  146. }
  147. }