浏览代码

WatermelonDB Setup and Profile Page Initialization

Savio Fernando 1 年之前
父节点
当前提交
ae84772c43

+ 23 - 24
App.js

@@ -27,33 +27,32 @@ const AppStack = createNativeStackNavigator();
 
 
 const App = () => {
-
   return (
-
-    <NavigationContainer>
-      <AppStack.Navigator headerShown={true}>
-        <AppStack.Screen
-          name="Login"
-          component={LoginPage}
-          options={{
-            headerShown: false,
-          }}
-        />
-        <AppStack.Screen
-          name="Home"
-          component={HomePageNavigator}
-          options={{ headerShown: false }}
-        />
-        <AppStack.Screen 
-          name='UnsignedLanding'
-          component={UnsignedLandingPage}
-          options={{headerShown: false}}
-        />
-      </AppStack.Navigator>
-      {/* <View style={styles.appContainer}>
+      <NavigationContainer>
+        <AppStack.Navigator headerShown={true}>
+          <AppStack.Screen
+            name="Login"
+            component={LoginPage}
+            options={{
+              headerShown: false,
+            }}
+          />
+          <AppStack.Screen
+            name="Home"
+            component={HomePageNavigator}
+            options={{ headerShown: false }}
+          />
+          <AppStack.Screen
+            name='UnsignedLanding'
+            component={UnsignedLandingPage}
+            options={{ headerShown: false }}
+          />
+        </AppStack.Navigator>
+        {/* <View style={styles.appContainer}>
         <Text>App</Text>
       </View> */}
-    </NavigationContainer>
+      </NavigationContainer>
+
 
 
   );

+ 5 - 1
POC_Documentation.md

@@ -10,4 +10,8 @@
 5. Setup React-native-linear-gradient
     <a>https://blog.logrocket.com/complex-gradients-react-native-linear-gradient/</a>
 6. Setup Experimental Android Animation on Project
-7. Use React Native Bottom Sheet for Bottom sheet Modals
+7. Use React Native Bottom Sheet for Bottom sheet Modals
+
+
+# Changes
+1. Make API Data Persists within the app. Use Watermelon DB

+ 6 - 1
android/app/build.gradle

@@ -146,6 +146,9 @@ android {
 
         }
     }
+    packagingOptions {
+        pickFirst '**/libc++_shared.so' // ⬅️ This (if missing)
+    }
 }
 
 dependencies {
@@ -153,7 +156,8 @@ dependencies {
     implementation("com.facebook.react:react-android")
 
     implementation("androidx.swiperefreshlayout:swiperefreshlayout:1.0.0")
-
+    implementation project(':watermelondb')
+    implementation project(':watermelondb-jsi')
     debugImplementation("com.facebook.flipper:flipper:${FLIPPER_VERSION}")
     debugImplementation("com.facebook.flipper:flipper-network-plugin:${FLIPPER_VERSION}") {
         exclude group:'com.squareup.okhttp3', module:'okhttp'
@@ -165,6 +169,7 @@ dependencies {
     } else {
         implementation jscFlavor
     }
+    
 }
 
 apply from: file("../../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); 

+ 1 - 0
android/app/proguard-rules.pro

@@ -8,3 +8,4 @@
 #   http://developer.android.com/guide/developing/tools/proguard.html
 
 # Add any project specific keep options here:
+-keep class com.nozbe.watermelondb.** { *; }

+ 5 - 0
android/app/src/main/java/com/navmelon/MainApplication.java

@@ -9,6 +9,9 @@ import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint;
 import com.facebook.react.defaults.DefaultReactNativeHost;
 import com.facebook.soloader.SoLoader;
 import java.util.List;
+import com.nozbe.watermelondb.jsi.WatermelonDBJSIPackage;
+import com.nozbe.watermelondb.WatermelonDBPackage; // ⬅️ This!
+import com.facebook.react.bridge.JSIModulePackage; // ⬅️ This!
 
 public class MainApplication extends Application implements ReactApplication {
 
@@ -25,6 +28,8 @@ public class MainApplication extends Application implements ReactApplication {
           List<ReactPackage> packages = new PackageList(this).getPackages();
           // Packages that cannot be autolinked yet can be added manually here, for example:
           // packages.add(new MyReactNativePackage());
+          packages.add(new WatermelonDBJSIPackage())
+          packages.add(new WatermelonDBPackage())
           return packages;
         }
 

+ 2 - 0
android/build.gradle

@@ -6,6 +6,7 @@ buildscript {
         minSdkVersion = 21
         compileSdkVersion = 33
         targetSdkVersion = 33
+        kotlinVersion = '1.5.20'
 
         // We use NDK 23 which has both M1 support and is the side-by-side NDK version from AGP.
         ndkVersion = "23.1.7779620"
@@ -17,5 +18,6 @@ buildscript {
     dependencies {
         classpath("com.android.tools.build:gradle:7.3.1")
         classpath("com.facebook.react:react-native-gradle-plugin")
+        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 
     }
 }

+ 4 - 0
android/settings.gradle

@@ -2,3 +2,7 @@ rootProject.name = 'NavMelon'
 apply from: file("../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesSettingsGradle(settings)
 include ':app'
 includeBuild('../node_modules/react-native-gradle-plugin')
+include ':watermelondb-jsi'
+project(':watermelondb-jsi').projectDir = new File(rootProject.projectDir, '../node_modules/@nozbe/watermelondb/native/android-jsi')
+include ':watermelondb'
+project(':watermelondb').projectDir = new File(rootProject.projectDir, '../node_modules/@nozbe/watermelondb/native/android')

+ 5 - 1
babel.config.js

@@ -1,4 +1,8 @@
 module.exports = {
   presets: ['module:metro-react-native-babel-preset'],
-  plugins: ['react-native-reanimated/plugin']
+  plugins: [
+    ["@babel/plugin-proposal-decorators", { "legacy": true }],
+    'react-native-reanimated/plugin',
+    
+  ]
 };

+ 36 - 14
components/organisms/Sections/CategorySection.js

@@ -5,7 +5,7 @@ import colors from '../../../theme/colors'
 import { ToggleButton } from 'react-native-paper'
 import SectionHeader from '../Headers/SectionHeader'
 import HorizontalNewsCardVariant from '../Cards/HorizontalNewsCardVariant'
-import {CATEGORY_URL,ARTICLE_URL} from '../../../utils/Constants/urls'
+import {CATEGORY_URL,ARTICLE_URL, PAGINATE_BY} from '../../../utils/Constants/constants'
 import { useConstructor } from '../../../utils/Constants/functions'
 
 
@@ -13,7 +13,7 @@ import { useConstructor } from '../../../utils/Constants/functions'
 
 const CategorySection = () => {
 
-    const [news,setNews] = React.useState({})
+    const [news,setNews] = React.useState({'all':[]})
     const updateNewsByCategories = (key, value) => {
         setNews((prevObject) => ({
           ...prevObject,
@@ -33,9 +33,16 @@ const CategorySection = () => {
                         .then((json) => {
                             let categoriesHeading = json.body.results.map((item) => item.heading.name)
                             setCategories(categoriesHeading)
+                            setNews({})
                             setNews(categoriesHeading.reduce((result, key) => ({ ...result, [key]: []}), {})),
                             setCategoryValue(categoriesHeading[0])
                             return categoriesHeading
+                        }).
+                        then((cats) => {
+                            cats.forEach(cat=> {
+                                fetchNews(cat)
+                            });
+                            return cats
                         })
                         .catch((err) => console.log(err))
                         .finally(() => console.log("Fetch Categories Executed"))
@@ -46,20 +53,20 @@ const CategorySection = () => {
     const fetchNews = (category) => {
         fetch(`http://www.newscout.in/api/v1/article/search/?domain=newscout&category=${category}`)
         .then(res => res.json())
-        .then((json) => {
-            const newsDataFetch = json.body.results
-            const finalNewsData = newsDataFetch.map((article) => ({
+        .then((data) => {
+            const newsDataFetch = data.body.results
+            const finalNewsData = newsDataFetch.slice(0,PAGINATE_BY).map((article) => ({
                 headline: article.title,
-                image: article.cover_image,
+                image: {uri:article.cover_image},
                 category: article.category,
                 root_category: article.root_category,
                 timestamp: article.published_on,
                 tagline: "Bruh Momento Oi Lorem Ipsum di rubi rabbi",
                 id:article.id
-            }),
-            updateNewsByCategories(category,finalNewsData))
+            }))
+            updateNewsByCategories(category,finalNewsData)
             // categories.forEach((category) => {setNews((prev) => ({...prev,[category]:json.body.results}))})
-            return newsDataFetch
+            return finalNewsData
         })
         .catch((err) => console.log(err))
         .finally(() => console.log("Fetch Category News Executed"))
@@ -68,13 +75,19 @@ const CategorySection = () => {
 
     useConstructor( () => {
         const cat_data = fetchCategories()
-        // console.log(`construct ${categories}`)
-        for (let category in cat_data) {
-            fetchNews(category)
+        //console.log(`construct ${categories}`)
+        // for (let category in cat_data) {
+        //     updateNewsByCategories(category,fetchNews(category))
 
-        }
+        // }
     })
 
+    // useEffect(() => {
+    //     for (let category in cat_data) {
+    //         fetchNews(category)
+
+    //     }
+    // })
 
     return (
         <View style={styles.categoriesContainer}>
@@ -98,7 +111,16 @@ const CategorySection = () => {
             <ScrollView showsVerticalScrollIndicator={false}>
                 <View style={styles.categoriesNewsContainer}>
                     <Text>{console.log(news)}</Text>
-                    {/* {news['Regional Updates'].map((item) => <HorizontalNewsCardVariant />)} */}
+                    {news[categoryValue] !== undefined 
+                        ? news[categoryValue].map((item) =>
+                             <HorizontalNewsCardVariant 
+                                headline={item.headline}
+                                image={item.image}
+                                timestamp={item.timestamp}
+                                tagline={item.tagline}
+                             />)
+                        : <Text> News Not Present</Text>
+                    }
                 </View>
             </ScrollView>
         </View>

+ 13 - 2
components/organisms/Sections/RecentNewsSection.js

@@ -10,11 +10,21 @@ import Carousel from 'react-native-reanimated-carousel';
 import MaterialComIcon from 'react-native-vector-icons/MaterialCommunityIcons'
 import { useConstructor } from '../../../utils/Constants/functions'
 
+// import {Q} from '@nozbe/watermelondb';
+// import withObservables from '@nozbe/with-observables';
 
 
 const ITEM_WIDTH = Math.round(metrics.screenWidth * 0.9);
 const ITEM_HEIGHT = Math.round(ITEM_WIDTH * 3 / 4);
 
+/*
+   Enhanced News Card
+*/
+
+// const EnhancedImageBGCard = withObservables(['recent_news'], ({news}) => ({
+//   news: news.observe(),
+// }))(ImageBGCard);
+
 
 const RecentNewsSection = () => {
 
@@ -31,7 +41,7 @@ const RecentNewsSection = () => {
     .then((res) => res.json())
     .then((json) => {
       const postData = json.body.results
-      const finalPostData = postData.map((item)=> ({
+      const finalPostData = postData.slice(0,5).map((item)=> ({
         image:item.cover_image,
         author: item.author,
         headline: item.title,
@@ -111,7 +121,8 @@ const styles = StyleSheet.create({
   },
   recentCardContainer: {
     alignItems: 'center',
-    paddingHorizontal: 8
+    paddingHorizontal: 8,
+    width: metrics.screenWidth
   },
   paginationContainer:{
     justifyContent:'flex-end',

+ 25 - 4
components/organisms/Sections/RecentPostsSection.js

@@ -12,14 +12,29 @@ const RecentPostsSection = () => {
   const fetchPosts = () => {
     fetch("http://www.newscout.in/api/v1/article/search/?domain=newscout&category=Sector%20Updates")
     .then((res) => res.json())
-    .then((json) => setPosts(json.body.results))
-    .then(() => console.log(posts))
+    .then((json) => {
+      const postsFetched = json.body.results
+      const finalPosts = postsFetched.map((item,index) => ({
+        key: index,
+        id: item.id,
+        image: {uri:item.cover_image},
+        author: item.author,
+        headline: item.title
+      }))
+      setPosts(finalPosts)
+      return postsFetched
+    })
+    .then((data) => {
+      console.log(data[0].keys())
+      return data
+    })
     .catch((err) => console.log(err))
     .finally(() => console.log("Fetch Posts Executed"))
   }
 
   useConstructor(function(){
-    fetchPosts()
+    const fetchPost = fetchPosts();
+    console.log(fetchPost)
   })
 
   return (
@@ -27,7 +42,13 @@ const RecentPostsSection = () => {
       <SectionHeader label={"Recents Posts"}/>
       <View style={styles.recentPostsContainer}>
         <ScrollView horizontal showsHorizontalScrollIndicator={false}>
-            {posts.map((item) => <VerticalNewsCard key={posts.indexOf(item)} id={posts.indexOf(item)}/>)}
+            {posts.map((item) => <VerticalNewsCard 
+              key={item.key}
+              id={item.id}
+              image={item.image}
+              author={item.author}
+              headline={item.headline}
+            />)}
         </ScrollView>
       </View>  
     </View>

+ 15 - 0
database/models/RecentNews.js

@@ -0,0 +1,15 @@
+import {Model, Q} from '@nozbe/watermelondb';
+import {field, children, lazy, action} from '@nozbe/watermelondb/decorators';
+
+export default class RecentNews extends Model {
+  static table = 'recent_news';
+
+  // static associations = {};
+
+  @field('headline')
+  headline;
+
+  @field('author')
+  author;
+
+}

+ 15 - 0
database/schema.js

@@ -0,0 +1,15 @@
+import { appSchema, tableSchema } from "@nozbe/watermelondb";
+
+export const mySchema = appSchema({
+    version: 1,
+    tables:[
+        tableSchema({
+            name: 'recent_news',
+            columns:[
+                {name:'headline',type:'string'},
+                {name:'author', type:'string'},
+                {name:'image', type:'string'},
+            ]
+        })
+    ]
+})

+ 20 - 1
index.js

@@ -5,5 +5,24 @@
 import {AppRegistry} from 'react-native';
 import App from './App';
 import {name as appName} from './app.json';
-
+// import { mySchema } from './database/schema';
+// import {Database} from '@nozbe/watermelondb';
+// import SQLiteAdapter from '@nozbe/watermelondb/adapters/sqlite'
+// import { setGenerator } from '@nozbe/watermelondb/utils/common/randomId';
+// import { v4 as uuidv4 } from 'uuid';
+// setGenerator(uuidv4);
 AppRegistry.registerComponent(appName, () => App);
+
+
+// const adapter = new SQLiteAdapter({
+//     dbName: 'WatermelonDemo',
+//     schema: mySchema
+// })
+
+// const database = new Database({
+//     adapter,
+//     modelClasses:[],
+//     actionsEnabled: true
+// })  
+
+

+ 2 - 1
metro.config.js

@@ -3,7 +3,8 @@
  * https://github.com/facebook/react-native
  *
  * @format
- */
+*/
+
 
 module.exports = {
   transformer: {

+ 7 - 7
navigation/HomePageNavigator.js

@@ -1,15 +1,13 @@
 import React from 'react'
 import SearchPage from '../screens/SearchPage';
-import BookmarkPage from '../screens/BookmarkPage';
-import SettingsPage from '../screens/SettingsPage';
 import { createBottomTabNavigator } from "@react-navigation/bottom-tabs"
 import IonIcon from 'react-native-vector-icons/dist/Ionicons';
 import colors from '../theme/colors';
 import fonts from '../theme/fonts';
-import NewscoutHomeHeader from '../components/organisms/Headers/NewscoutHomeHeader';
 import NewscoutTitleHeader from '../components/organisms/Headers/NewscoutTitleHeader';
 import BookmarkNavigator from './BookmarkNavigator';
 import LandingPageNavigator from './LandingPageNavigator';
+import ProfilePage from '../screens/ProfilePage';
 
 
 
@@ -37,7 +35,7 @@ const HomePageNavigator = ({ route, navigation }) => {
                         case "Bookmark":
                             iconName = "bookmark-outline";
                             break
-                        case "Settings":
+                        case "Profile":
                             iconName = 'person-outline';
                             break
                         default:
@@ -72,10 +70,12 @@ const HomePageNavigator = ({ route, navigation }) => {
                 })}
             />
             <Tab.Screen
-                name="Settings"
-                component={SettingsPage}
+                name="Profile"
+                component={ProfilePage}
                 options={() => ({
-                    header: () => <NewscoutTitleHeader title={"Settings"} backButtonShown={true}></NewscoutTitleHeader>
+                    header: () => <NewscoutTitleHeader title={"My Profile"} backButtonShown={false}>
+                        
+                    </NewscoutTitleHeader>
                 })}
             />
         </Tab.Navigator>

+ 30 - 0
navigation/ProfileNavigator.js

@@ -0,0 +1,30 @@
+import { View, Text , TouchableWithoutFeedback} from 'react-native'
+import React from 'react'
+import { createNativeStackNavigator } from '@react-navigation/native-stack'
+import ProfilePage from '../screens/ProfilePage';
+import SettingsPage from '../screens/SettingsPage';
+
+
+const Stack = createNativeStackNavigator();
+const ProfileNavigator = ({ route, navigation}) => {
+    return (
+        <Stack.Navigator
+            initialRouteName='Profile'
+        >
+            <Stack.Screen
+                name="Profile"
+                options={(navigation) => ({
+                    
+                })}
+                component={ProfilePage}
+            />
+            <Stack.Screen
+                name="Settings"
+                options={(navigation) => {
+
+                }}
+                component={SettingsPage}
+            />
+        </Stack.Navigator>
+    )
+}

文件差异内容过多而无法显示
+ 677 - 260
package-lock.json


+ 3 - 1
package.json

@@ -25,10 +25,12 @@
     "react-native-reanimated-carousel": "^3.5.1",
     "react-native-safe-area-context": "^4.6.4",
     "react-native-screens": "^3.20.0",
-    "react-native-vector-icons": "^9.2.0"
+    "react-native-vector-icons": "^9.2.0",
+    "uuid": "^9.0.0"
   },
   "devDependencies": {
     "@babel/core": "^7.20.0",
+    "@babel/plugin-proposal-decorators": "^7.22.7",
     "@babel/preset-env": "^7.20.0",
     "@babel/runtime": "^7.20.0",
     "@react-native-community/eslint-config": "^3.2.0",

+ 48 - 0
screens/ProfilePage.js

@@ -0,0 +1,48 @@
+import { Image, StyleSheet, Text, View } from 'react-native'
+import React from 'react'
+import images from '../assets/images/images'
+
+const PROFILE_SIZE = 128
+
+const ProfilePage = (props) => {
+
+    const {
+        navigation,
+        route,
+        name,
+        profileQuote,
+        metrics
+    } = props
+
+    return (
+        <View style={styles.profileContainer}>
+            <View style={styles.profileImageContainer}>
+                <Image source={images.imageCard} style={styles.profileImage}>
+
+                </Image>
+            </View>
+            <Text>Semina Gurung</Text>
+            <Text>
+                The reason behind their disappointment is that iPhone users have been..
+            </Text>
+            
+        </View>
+    )
+}
+
+export default ProfilePage
+
+const styles = StyleSheet.create({
+    profileContainer: {
+
+    },
+    profileImageContainer: {
+        paddingVertical: 16,
+        alignItems: 'center'
+    },
+    profileImage: {
+        borderRadius: PROFILE_SIZE,
+        height: PROFILE_SIZE,
+        width: PROFILE_SIZE
+    }
+})

+ 1 - 1
utils/Constants/urls.js → utils/Constants/constants.js

@@ -1,6 +1,6 @@
 export const BASE_URL = "http://www.newscout.in";
 export const DEFAULT_DOMAIN = "newscout";
-export const PAGINATE_BY = 30;
+export const PAGINATE_BY = 5;
 export const API_URL_v1 = BASE_URL + "/api/v1/"
 export const API_URL_v2 = BASE_URL + "/api/v2/"
 

+ 1 - 1
utils/Constants/functions.js

@@ -8,5 +8,5 @@ export const useConstructor = (callBack = () => {}) => {
     if (hasBeenCalled) return;
     callBack();
     setHasBeenCalled(true);
-  }
+}
 

文件差异内容过多而无法显示
+ 352 - 211
yarn.lock


部分文件因为文件数量过多而无法显示