diff --git a/android/app/src/main/res/drawable-hdpi/loader.gif b/android/app/src/main/res/drawable-hdpi/loader.gif
deleted file mode 100644
index 9abab46..0000000
Binary files a/android/app/src/main/res/drawable-hdpi/loader.gif and /dev/null differ
diff --git a/android/app/src/main/res/drawable-mdpi/loader.gif b/android/app/src/main/res/drawable-mdpi/loader.gif
deleted file mode 100644
index 9abab46..0000000
Binary files a/android/app/src/main/res/drawable-mdpi/loader.gif and /dev/null differ
diff --git a/android/app/src/main/res/drawable-xhdpi/loader.gif b/android/app/src/main/res/drawable-xhdpi/loader.gif
deleted file mode 100644
index 9abab46..0000000
Binary files a/android/app/src/main/res/drawable-xhdpi/loader.gif and /dev/null differ
diff --git a/android/app/src/main/res/drawable-xxhdpi/loader.gif b/android/app/src/main/res/drawable-xxhdpi/loader.gif
deleted file mode 100644
index 9abab46..0000000
Binary files a/android/app/src/main/res/drawable-xxhdpi/loader.gif and /dev/null differ
diff --git a/android/app/src/main/res/drawable-xxxhdpi/loader.gif b/android/app/src/main/res/drawable-xxxhdpi/loader.gif
deleted file mode 100644
index 9abab46..0000000
Binary files a/android/app/src/main/res/drawable-xxxhdpi/loader.gif and /dev/null differ
diff --git a/android/app/src/main/res/drawable/background_splash.xml b/android/app/src/main/res/drawable/background_splash.xml
index 78316f2..f0ce332 100644
--- a/android/app/src/main/res/drawable/background_splash.xml
+++ b/android/app/src/main/res/drawable/background_splash.xml
@@ -10,25 +10,16 @@
/>
-
-
-
diff --git a/android/app/src/main/res/drawable/loader.gif b/android/app/src/main/res/drawable/loader.gif
new file mode 100644
index 0000000..87f9ac0
Binary files /dev/null and b/android/app/src/main/res/drawable/loader.gif differ
diff --git a/android/app/src/main/res/layout/launch_screen.xml b/android/app/src/main/res/layout/launch_screen.xml
index 75f3ffc..44af626 100644
--- a/android/app/src/main/res/layout/launch_screen.xml
+++ b/android/app/src/main/res/layout/launch_screen.xml
@@ -7,14 +7,14 @@
android:layout_height="match_parent"
android:layout_gravity="start|end|top|bottom|center|center_horizontal|center_vertical"
android:background="@color/dark"
- android:fitsSystemWindows="true"
+ android:statusBarColor="@color/transparent"
tools:context=".MainActivity">
{
+ const forecast = useSelector((state) => state.daily[index]);
+ console.log('render daily timeline DayCard : ', index);
+ return (
+
+
+
+ {index === 0
+ ? 'Today'
+ : index === 1
+ ? 'Tomorrow'
+ : moment(forecast.dt * 1000).format('dddd')}
+
+
+ {moment(forecast.dt * 1000).format('D/M')}
+
+
+
+
+
+ {round(forecast.temp.morn)}°
+ ~ {round(forecast.feels_like.morn)}°
+
+
+ {round(forecast.temp.day)}°
+ ~ {round(forecast.feels_like.day)}°
+
+
+ {round(forecast.temp.eve)}°
+ ~ {round(forecast.feels_like.eve)}°
+
+
+ {round(forecast.temp.night)}°
+ ~ {round(forecast.feels_like.night)}°
+
+
+
+ );
+});
+
+export default ({ dayClicked, onPress }) => {
+ console.log('render daily timeline : ', dayClicked);
+ return (
+
+
+
+
+
+
+
+
+
+
+
+ {[...Array(8)].map((value, index) => (
+ onPress(index)}>
+
+
+ ))}
+
+
+ );
+};
+
+const Container = styled.View`
+ flex-grow: 1;
+ flex-direction: row;
+ justify-content: center;
+ overflow: hidden;
+ border-radius: ${RFValue(10)}px;
+`;
+
+const ScrollView = styled.ScrollView.attrs(() => ({
+ contentContainerStyle: {
+ justifyContent: 'space-between',
+ },
+}))``;
+
+const column = css`
+ margin-vertical: ${RFValue(20)}px;
+ padding-vertical: ${RFValue(20)}px;
+`;
+
+const Column = styled.View`
+ ${column}
+ flex: 1;
+ width: ${RFValue(70)}px;
+ margin-right: ${RFValue(5)}px;
+ border-width: ${({ clicked }) => (clicked ? '2px' : '1px')};
+ border-color: ${({ clicked, theme }) =>
+ clicked ? theme.colors.primary : theme.colors.border};
+ border-radius: ${RFValue(25)}px;
+ background-color: ${({ theme }) => theme.colors.backgroundAlt};
+ /* shadow-opacity: 0.75;
+ shadow-radius: 5px;
+ shadow-color: red;
+ shadow-offset: 0px 0px;
+ overflow: hidden; */
+ elevation: ${({ clicked }) => (clicked ? 4 : 0)};
+`;
+
+const ColumnFirst = styled.View`
+ ${column}
+ width: ${RFValue(40)}px;
+`;
+
+const Text = styled.Text`
+ text-align: center;
+ color: ${({ theme }) => theme.colors.text};
+ font-size: ${RFValue(17)}px;
+`;
+
+const Header = styled.View`
+ height: ${RFValue(90)}px;
+ align-items: center;
+`;
+
+const Content = styled.View`
+ flex-grow: 1;
+ justify-content: space-around;
+ align-items: center;
+`;
+
+const FeatherIcon = styled(Feather).attrs(({ color, theme }) => ({
+ size: RFValue(20),
+ color: color || theme.colors.icon,
+}))`
+ text-align: center;
+`;
+
+const CardHeading = styled(Text)`
+ font-size: ${RFValue(14)}px;
+`;
+
+const CardSubHeading = styled(Text)`
+ color: ${({ theme }) => theme.colors.textAlt};
+ font-size: ${RFValue(12)}px;
+`;
+
+const WeatherIcon = styled(LottieView)`
+ width: ${RFValue(40)}px;
+ height: ${RFValue(40)}px;
+ padding-top: ${RFValue(5)}px;
+`;
+
+const TimeTempBox = styled.View`
+ align-items: center;
+ justify-content: center;
+`;
+
+const Temp = styled(Text)`
+ font-size: ${RFValue(15)}px;
+`;
+
+const Feels = styled(Text)`
+ font-size: ${RFValue(11)}px;
+ color: ${({ theme }) => theme.colors.textAlt};
+ padding-right: ${RFValue(9)}px;
+`;
diff --git a/src/components/Day.jsx b/src/components/Day.jsx
index a469fa0..50c0a09 100644
--- a/src/components/Day.jsx
+++ b/src/components/Day.jsx
@@ -1,32 +1,38 @@
-import React from 'react';
+import React, { useMemo } from 'react';
import styled, { css } from 'styled-components/native';
import { RFValue } from 'react-native-responsive-fontsize';
import LottieView from 'lottie-react-native';
+import moment from 'moment';
+import { useSelector } from 'react-redux';
import { round, weatherIcons } from '../utils';
-export default ({ day, forecast }) => {
- return (
-
-
-
- {day}
-
-
- {forecast.weather[0].main}
-
- {round(forecast.temp.max)}° / {round(forecast.temp.min)}°
-
-
-
- );
+export default ({ index }) => {
+ const forecast = useSelector((state) => state.daily[index]);
+ return useMemo(() => {
+ console.log('render day : ', index);
+ return (
+
+
+
+ {moment(forecast.dt * 1000).format('dddd')}
+
+
+ {forecast.weather[0].main}
+
+ {round(forecast.temp.max)}° / {round(forecast.temp.min)}°
+
+
+
+ );
+ }, [forecast]);
};
const Container = styled.View`
@@ -50,6 +56,7 @@ const DayIcon = styled.View`
const WeatherIcon = styled(LottieView)`
width: ${RFValue(30)}px;
height: ${RFValue(30)}px;
+ elevation: 4;
`;
const text = css`
diff --git a/src/components/DayDetailsBox.jsx b/src/components/DayForecastDetails.jsx
similarity index 61%
rename from src/components/DayDetailsBox.jsx
rename to src/components/DayForecastDetails.jsx
index 59aef45..4e33577 100644
--- a/src/components/DayDetailsBox.jsx
+++ b/src/components/DayForecastDetails.jsx
@@ -1,35 +1,73 @@
-import React, { useContext } from 'react';
+import React, { useContext, useMemo } from 'react';
import styled from 'styled-components/native';
import { RFValue } from 'react-native-responsive-fontsize';
import Ionicons from 'react-native-vector-icons/Ionicons';
import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons';
import Fontisto from 'react-native-vector-icons/Fontisto';
+import Feather from 'react-native-vector-icons/Feather';
import { ThemeContext } from 'styled-components';
import { useSelector } from 'react-redux';
+import moment from 'moment';
-const Card = ({ heading, sunHeading, icon }) => {
- return (
-
-
- {heading}
- {sunHeading}
-
- {icon}
-
- );
+const Card = ({ heading, subHeading, icon }) => {
+ return useMemo(() => {
+ console.log('render day forecast Deails : ', heading);
+ return (
+
+
+ {heading}
+ {subHeading}
+
+ {icon}
+
+ );
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [subHeading]);
};
-export default ({ forecast }) => {
+export default ({ index }) => {
+ const forecast = useSelector((state) => state.daily[index]);
+ const timeFormat = useSelector((state) => state.timeFormat);
const units = useSelector((state) => state.units);
const themeContext = useContext(ThemeContext);
const iconSize = RFValue(30);
+
+ const timeString = (sec) => {
+ if (timeFormat === '24') return moment(sec * 1000).format('HH:mm');
+ return moment(sec * 1000).format('h:m A');
+ };
+
return (
- <>
+
+
+
+ }
+ />
+
+ }
+ />
+
{
/>
{
{
/>
{
{
/>
{
}
/>
- >
+
);
};
+const Container = styled.View`
+ margin: ${RFValue(20)}px;
+ margin-top: 0px;
+`;
+
const BoxRow = styled.View`
flex-direction: row;
height: ${RFValue(60)}px;
diff --git a/src/components/DropDownSettings.jsx b/src/components/DropDownSettings.jsx
index 81b93e9..82a967d 100644
--- a/src/components/DropDownSettings.jsx
+++ b/src/components/DropDownSettings.jsx
@@ -119,7 +119,7 @@ const DropSetting = styled.View`
flex-direction: row;
justify-content: space-between;
align-items: center;
- height: ${RFValue(45)}px;
+ height: ${RFValue(40)}px;
margin-bottom: ${RFValue(5)}px;
border-radius: 30px;
`;
diff --git a/src/components/Error.jsx b/src/components/Error.jsx
index 11e5313..3f68220 100644
--- a/src/components/Error.jsx
+++ b/src/components/Error.jsx
@@ -1,14 +1,19 @@
-import React, { useContext } from 'react';
+import React, { useEffect, useContext } from 'react';
import styled from 'styled-components/native';
import { RFValue } from 'react-native-responsive-fontsize';
import { useSelector } from 'react-redux';
import { ThemeContext } from 'styled-components';
+import SplashScreen from 'react-native-splash-screen';
export default ({ getWeather }) => {
const error = useSelector((state) => state.error);
const themeContext = useContext(ThemeContext);
+ useEffect(() => {
+ SplashScreen.hide();
+ }, []);
+
return (
{error}
diff --git a/src/components/HourlyTimeline.jsx b/src/components/HourlyTimeline.jsx
index 22b9c38..d13f79c 100644
--- a/src/components/HourlyTimeline.jsx
+++ b/src/components/HourlyTimeline.jsx
@@ -1,88 +1,128 @@
-import React from 'react';
-import { Dimensions } from 'react-native';
+import React, { useEffect, useMemo } from 'react';
import styled from 'styled-components/native';
import { LineChart } from 'react-native-chart-kit';
import { RFValue } from 'react-native-responsive-fontsize';
import { useSelector } from 'react-redux';
import moment from 'moment';
-import { Svg, Text as TextSVG } from 'react-native-svg';
+import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons';
+import SplashScreen from 'react-native-splash-screen';
-import { round, weatherIcons, rootNavigation } from '../utils';
+import { round, weatherIcons } from '../utils';
export default () => {
const timeFormat = useSelector((state) => state.timeFormat);
const hourly = useSelector((state) => state.forecast.hourly);
+ const COLOR = 'blue';
+
+ useEffect(() => {
+ SplashScreen.hide();
+ }, []);
const timeString = (sec) => {
if (timeFormat === '24') return moment(sec * 1000).format('HH:mm');
- return moment(sec * 1000).format('hh:mm a');
+ return moment(sec * 1000).format('h A');
};
+
const chartData = {
- labels: hourly.map((item) => timeString(item.dt)),
+ labels: hourly.map((item, index) =>
+ index === 24 ? 'Tomorrow' : timeString(item.dt)
+ ),
datasets: [
{
data: hourly.map((item) => round(item.temp)),
- color: (opacity = 0.5) => `rgba(255, 255, 255, ${opacity})`,
},
],
legend: [],
};
- const chartConfig = {
- backgroundColor: '#005aae',
- backgroundGradientFrom: '#006ace',
- backgroundGradientTo: '#40a1fc',
- decimalPlaces: 2,
- color: (opacity = 0) => `rgba(255, 255, 255, ${opacity})`,
+
+ const colors = {
+ blue: {
+ backgroundColor: '#005aae',
+ backgroundGradientFrom: '#006ace',
+ backgroundGradientTo: '#40a1fc',
+ },
+ orange: {
+ backgroundColor: '#e26a00',
+ backgroundGradientFrom: '#fb8c00',
+ backgroundGradientTo: '#ffa726',
+ fillShadowGradient: '#000',
+ },
+ };
+
+ const config = {
+ decimalPlaces: 0,
+ fillShadowGradientOpacity: 0.12,
+ color: (opacity = 1) => `rgba(255, 255, 255, ${opacity})`,
labelColor: (opacity = 1) => `rgba(255, 255, 255, ${opacity})`,
style: {},
propsForDots: {
r: '4',
strokeWidth: '2',
- stroke: '#40a1fc',
},
propsForLabels: { fontSize: RFValue(9) },
propsForVerticalLabels: { fontWeight: 'bold', fontSize: RFValue(8) },
};
- return (
-
- {/* Hourly forecast */}
-
- {
- return (
-
- {indexData}°
-
- );
- }}
- formatYLabel={(label) => round(label)}
- style={{}}
- />
-
-
+
+ const chartConfig = (color) => ({
+ ...config,
+ ...colors[color || COLOR],
+ propsForDots: {
+ ...config.propsForDots,
+ stroke: colors[color || COLOR].backgroundGradientTo,
+ },
+ });
+
+ const renderDotContent = ({ x, y, index, indexData }) => (
+
+ {indexData}°
+
+
);
+
+ return useMemo(() => {
+ console.log('render hourly timeline');
+ return (
+
+ {/* Hourly forecast */}
+
+ ({
+ r: index === 24 ? '6' : '4',
+ strokeWidth: '2',
+ stroke: colors['orange'].backgroundGradientTo,
+ })}
+ />
+
+
+ );
+ }, [hourly]);
};
const Container = styled.View`
@@ -107,3 +147,18 @@ const HeadingText = styled.Text`
padding-top: ${RFValue(5)}px;
font-weight: bold;
`;
+
+const DotView = styled.View`
+ height: ${RFValue(45)}px;
+ justify-content: space-between;
+ position: absolute;
+ top: ${({ y }) => y + RFValue(4)}px;
+ left: ${({ x }) => x - RFValue(6)}px;
+`;
+
+const DotText = styled.Text`
+ padding-left: 2px;
+ color: white;
+ font-size: ${RFValue(10)}px;
+ font-weight: bold;
+`;
diff --git a/src/components/LiveTime.jsx b/src/components/LiveTime.jsx
index d935bf2..533b8c4 100644
--- a/src/components/LiveTime.jsx
+++ b/src/components/LiveTime.jsx
@@ -6,6 +6,7 @@ import { RFValue } from 'react-native-responsive-fontsize';
import { useSelector } from 'react-redux';
export default () => {
+ const lastFetched = useSelector((state) => state.lastFetched);
const timeFormat = useSelector((state) => state.timeFormat);
const [currTime, setCurrTime] = useState(moment());
@@ -17,14 +18,25 @@ export default () => {
}, []);
return (
-
+ <>
+ {'Updated ' + moment(lastFetched).fromNow()}
+ {/* */}
+ >
);
};
+const LastFetched = styled.Text`
+ justify-content: center;
+ padding: ${RFValue(5)}px;
+ color: ${({ theme }) => theme.colors.textAlt};
+ font-size: ${RFValue(10)}px;
+ padding-bottom: ${RFValue(20)}px;
+`;
+
const Time = styled.Text`
justify-content: center;
padding: ${RFValue(5)}px;
diff --git a/src/components/Today.jsx b/src/components/Today.jsx
index a3bd33e..175926a 100644
--- a/src/components/Today.jsx
+++ b/src/components/Today.jsx
@@ -1,70 +1,71 @@
-import React, { useEffect, useContext } from 'react';
+import React, { useContext, useMemo } from 'react';
import styled from 'styled-components/native';
import { RFValue } from 'react-native-responsive-fontsize';
import LottieView from 'lottie-react-native';
import { useSelector } from 'react-redux';
-import SplashScreen from 'react-native-splash-screen';
+
import IconI from 'react-native-vector-icons/Ionicons';
import { ThemeContext } from 'styled-components';
-
import LiveTime from './LiveTime';
import { StyledTouchableScale } from './StyledComponents';
import { round, weatherIcons, rootNavigation } from '../utils';
-export default () => {
- const weather = useSelector((state) => state.weather);
- const forecast = useSelector((state) => state.forecast);
+const SettingsIcon = () => {
const themeContext = useContext(ThemeContext);
-
- useEffect(() => {
- SplashScreen.hide();
- }, []);
-
return (
-
-
- rootNavigation.navigate('DayDetails', { forecast: forecast.daily[0] })
- }
- >
-
-
-
-
- {round(weather.main.temp)}°
-
- {weather.name}
-
- Feels Like {round(weather.main.feels_like)}°
-
- {weather.weather[0].main}
-
-
- rootNavigation.navigate('Settings')}
- >
-
-
-
+ rootNavigation.navigate('Settings')}
+ >
+
+
);
};
+export default () => {
+ const weather = useSelector((state) => state.weather);
+
+ return useMemo(() => {
+ console.log('render today');
+ return (
+
+ rootNavigation.navigate('DayDetails', { index: 0 })}
+ >
+
+
+
+
+ {round(weather.main.temp)}°
+
+ {weather.name}
+
+ Feels Like {round(weather.main.feels_like)}°
+
+ {weather.weather[0].main}
+
+
+
+
+ );
+ }, [weather]);
+};
+
const Container = styled.View`
flex: 1;
`;
diff --git a/src/components/WeekDays.jsx b/src/components/WeekDays.jsx
index 5d086cf..db69e1e 100644
--- a/src/components/WeekDays.jsx
+++ b/src/components/WeekDays.jsx
@@ -1,56 +1,27 @@
-import React, { useEffect, useState } from 'react';
+import React, { useRef } from 'react';
import styled from 'styled-components/native';
-import moment from 'moment';
import { RFValue } from 'react-native-responsive-fontsize';
-import { useSelector } from 'react-redux';
import { StyledTouchableScale } from './StyledComponents';
import { rootNavigation } from '../utils';
import Day from './Day';
export default () => {
- const [today] = useState(moment().format('dddd'));
- const [dayNames, setDayNames] = useState();
-
- const forecast = useSelector((state) => state.forecast);
-
- useEffect(() => {
- let weekDays = [
- 'Sunday',
- 'Monday',
- 'Tuesday',
- 'Wednesday',
- 'Thursday',
- 'Friday',
- 'Saturday',
- ];
- let dayNo = weekDays.indexOf(today);
- let day = '';
- while (dayNo >= 0) {
- day = weekDays.shift();
- weekDays.push(day);
- dayNo--;
- }
- weekDays = weekDays.slice(0, 5);
- setDayNames(weekDays);
- }, [today]);
+ console.log('render weekdays');
return (
- {dayNames &&
- dayNames.map((day, index) => (
-
- rootNavigation.navigate('DayDetails', {
- forecast: forecast.daily[index + 1],
- })
- }
- >
-
-
- ))}
+ {[...Array(6)].map((value, index) => (
+
+ rootNavigation.navigate('DayDetails', { index: index + 1 })
+ }
+ >
+
+
+ ))}
);
};
diff --git a/src/containers/StackNavigation.jsx b/src/containers/StackNavigation.jsx
index 0a7b765..6af0661 100644
--- a/src/containers/StackNavigation.jsx
+++ b/src/containers/StackNavigation.jsx
@@ -50,6 +50,7 @@ export default () => {
headerPressColorAndroid: themeContext.colors.buttonPress,
headerTitleAlign: 'center',
headerBackTitleVisible: false,
+ headerShown: true,
headerTitleStyle: {
fontSize: RFValue(18),
},
diff --git a/src/pages/DayDetails.jsx b/src/pages/DayDetails.jsx
index 1877997..2c11dae 100644
--- a/src/pages/DayDetails.jsx
+++ b/src/pages/DayDetails.jsx
@@ -1,30 +1,23 @@
-import React, { useContext } from 'react';
+import React, { useState } from 'react';
import styled from 'styled-components/native';
-import { RFValue } from 'react-native-responsive-fontsize';
-import { ThemeContext } from 'styled-components';
-import { useSelector } from 'react-redux';
-import DayDetailsBox from '../components/DayDetailsBox';
+import DailyTimeline from '../components/DailyTimeline';
+import DayForecastDetails from '../components/DayForecastDetails';
export default ({ route }) => {
- const units = useSelector((state) => state.units);
- const themeContext = useContext(ThemeContext);
- const { forecast } = route.params;
+ const { index } = route.params;
+ const [dayClicked, setDayClicked] = useState(index);
+ console.log('render day details ');
return (
-
-
+
+
);
};
const Container = styled.View`
flex: 1;
- padding: ${RFValue(10)}px;
background-color: ${({ theme }) => theme.colors.background};
`;
-
-const DailyTimeline = styled.View`
- flex-grow: 1;
-`;
diff --git a/src/pages/Home.jsx b/src/pages/Home.jsx
index f25fece..0d7dfa6 100644
--- a/src/pages/Home.jsx
+++ b/src/pages/Home.jsx
@@ -1,5 +1,5 @@
-import React, { useEffect, useContext } from 'react';
-import { RefreshControl, View, Text, Dimensions } from 'react-native';
+import React, { useEffect, useContext, useLayoutEffect, useMemo } from 'react';
+import { RefreshControl, View, Dimensions } from 'react-native';
import styled from 'styled-components/native';
import { useSelector } from 'react-redux';
@@ -16,53 +16,63 @@ import { useWeather, useStorage } from '../utils';
export default ({ navigation }) => {
const screenHeight = Dimensions.get('screen').height;
const themeContext = useContext(ThemeContext);
- const { error, isLoading, weather, forecast } = useSelector((state) => state);
+ const isLoading = useSelector((state) => state.isLoading);
+ const hasData = useSelector((state) => state.hasData);
+ const error = useSelector((state) => state.error);
+
const { getWeather } = useWeather();
const fetchStorage = useStorage();
- useEffect(() => {
+ useLayoutEffect(() => {
navigation.setOptions({ headerShown: false });
- getWeather();
+ }, []);
+
+ useEffect(() => {
fetchStorage();
+ getWeather();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
useEffect(() => {
if (error) {
- Toast.show(error, Toast.SHORT);
+ Toast.show(error, Toast.LONG, Toast.BOTTOM);
}
}, [error]);
- return (
-
- {weather && forecast ? (
-
- }
- >
- {
+ console.log('render home');
+ return (
+
+ {hasData ? (
+
+ }
>
-
-
-
-
-
- ) : (
- error &&
- )}
-
- );
+
+
+
+
+
+
+ ) : (
+ error &&
+ )}
+
+ );
+ }, [error, hasData, isLoading, themeContext]);
};
const Container = styled.View`
diff --git a/src/utils/storage.js b/src/utils/storage.js
index 9d8f705..814dcb2 100644
--- a/src/utils/storage.js
+++ b/src/utils/storage.js
@@ -5,7 +5,7 @@ const getItem = (key) => {
try {
return AsyncStorage.getItem(key);
} catch (e) {
- console.log('error getting', key, ': ', e);
+ console.error('error getting', key, ': ', e);
}
};
@@ -14,7 +14,7 @@ const getData = async (key) => {
const jsonValue = await AsyncStorage.getItem(key);
return jsonValue != null ? JSON.parse(jsonValue) : null;
} catch (e) {
- console.log('error getting', key, ': ', e);
+ console.error('error getting', key, ': ', e);
}
};
@@ -22,7 +22,7 @@ const setItem = async (key, value) => {
try {
await AsyncStorage.setItem(key, value);
} catch (e) {
- console.log('error setting', key, ': ', e);
+ console.error('error setting', key, ': ', e);
}
};
@@ -31,7 +31,7 @@ const setData = async (key, value) => {
const jsonValue = JSON.stringify(value);
await AsyncStorage.setItem(key, jsonValue);
} catch (e) {
- console.log('error setting', key, ': ', e);
+ console.error('error setting', key, ': ', e);
}
};
@@ -39,7 +39,7 @@ const removeItem = async (key) => {
try {
await AsyncStorage.removeItem(key);
} catch (e) {
- console.log('error removing', key, ': ', e);
+ console.error('error removing', key, ': ', e);
}
};
@@ -47,7 +47,7 @@ const clearStorage = async () => {
try {
await AsyncStorage.clear();
} catch (e) {
- console.log('error clearAll : ', e);
+ console.error('error clearAll : ', e);
}
};
diff --git a/src/utils/store.js b/src/utils/store.js
index a05e3f1..529a7c9 100644
--- a/src/utils/store.js
+++ b/src/utils/store.js
@@ -1,26 +1,39 @@
import { createStore } from 'redux';
+import moment from 'moment';
import { weather, forecast, units, timeFormat, theme } from './storage';
const initialState = {
weather: null,
forecast: null,
error: null,
- isLoading: true,
+ isLoading: false,
units: 'metric',
timeFormat: '24',
theme: 'black',
+ clickedIndex: 0,
+ daily: [],
+ hasData: false,
+ lastFetched: 0,
};
const rootReducer = (state = initialState, action) => {
switch (action.type) {
case 'storage': {
+ console.log('storage fetch');
+
return {
...state,
- weather: action.payload.weather || initialState.weather,
- forecast: action.payload.forecast || initialState.forecast,
- timeFormat: action.payload.timeFormat || initialState.timeFormat,
- units: action.payload.units || initialState.units,
- theme: action.payload.theme || initialState.theme,
+ weather: action.payload.weather || state.weather,
+ forecast: action.payload.forecast || state.forecast,
+ timeFormat: action.payload.timeFormat || state.timeFormat,
+ units: action.payload.units || state.units,
+ theme: action.payload.theme || state.theme,
+ daily: action.payload.forecast.daily || state.daily,
+ hasData:
+ action.payload.weather && action.payload.forecast
+ ? true
+ : state.hasData,
+ lastFetched: action.payload.weather.dt * 1000 || state.lastFetched,
};
}
case 'weather': {
@@ -28,6 +41,8 @@ const rootReducer = (state = initialState, action) => {
return {
...state,
weather: action.payload,
+ hasData: state.forecast ? true : state.hasData,
+ lastFetched: moment(),
};
}
case 'onecall': {
@@ -35,6 +50,9 @@ const rootReducer = (state = initialState, action) => {
return {
...state,
forecast: action.payload,
+ daily: action.payload.daily,
+ hasData: state.weather ? true : state.hasData,
+ lastFetched: moment(),
};
}
case 'error': {
diff --git a/src/utils/useLocation.js b/src/utils/useLocation.js
index 06a3bd1..670ad77 100644
--- a/src/utils/useLocation.js
+++ b/src/utils/useLocation.js
@@ -42,7 +42,7 @@ export default () => {
Geolocation.getCurrentPosition(
// get current location from native GPS service
(position) => {
- console.log('get location');
+ console.log('location fetched');
setIsLoading(false);
setData({
latitude: position.coords.latitude,
@@ -50,7 +50,7 @@ export default () => {
});
},
(err) => {
- console.log(err.code, err.message);
+ console.error(err.code, err.message);
setError(err.message);
setIsLoading(false);
},
diff --git a/src/utils/useWeather.js b/src/utils/useWeather.js
index 06038b1..c098fb7 100644
--- a/src/utils/useWeather.js
+++ b/src/utils/useWeather.js
@@ -105,7 +105,7 @@ export default () => {
setForecastLoading(false);
}
} catch (err) {
- console.log('Connection failed');
+ console.error('Connection failed');
setError('Connection Failed');
setIsLoading(false);
}
diff --git a/src/utils/utils.js b/src/utils/utils.js
index be1d4dd..7d82276 100644
--- a/src/utils/utils.js
+++ b/src/utils/utils.js
@@ -11,22 +11,76 @@ export const ceil = (no) => {
};
export const weatherIcons = {
- '01d': require('../assets/lotties/01d.json'),
- '01n': require('../assets/lotties/01n.json'),
- '02d': require('../assets/lotties/02d.json'),
- '02n': require('../assets/lotties/02n.json'),
- '03d': require('../assets/lotties/03d.json'),
- '03n': require('../assets/lotties/03d.json'),
- '04d': require('../assets/lotties/03d.json'),
- '04n': require('../assets/lotties/03d.json'),
- '09d': require('../assets/lotties/09d.json'),
- '09n': require('../assets/lotties/09n.json'),
- '10d': require('../assets/lotties/09d.json'),
- '10n': require('../assets/lotties/09n.json'),
- '11d': require('../assets/lotties/11d.json'),
- '11n': require('../assets/lotties/11n.json'),
- '13d': require('../assets/lotties/13d.json'),
- '13n': require('../assets/lotties/13n.json'),
- '50d': require('../assets/lotties/50d.json'),
- '50n': require('../assets/lotties/50n.json'),
+ '01d': {
+ icon: 'weather-sunny',
+ animation: require('../assets/lotties/01d.json'),
+ },
+ '01n': {
+ icon: 'weather-night',
+ animation: require('../assets/lotties/01n.json'),
+ },
+ '02d': {
+ icon: 'weather-partly-cloudy',
+ animation: require('../assets/lotties/02d.json'),
+ },
+ '02n': {
+ icon: 'weather-night-partly-cloudy',
+ animation: require('../assets/lotties/02n.json'),
+ },
+ '03d': {
+ icon: 'weather-cloudy',
+ animation: require('../assets/lotties/03d.json'),
+ },
+ '03n': {
+ icon: 'weather-cloudy',
+ animation: require('../assets/lotties/03d.json'),
+ },
+ '04d': {
+ icon: 'weather-cloudy',
+ animation: require('../assets/lotties/03d.json'),
+ },
+ '04n': {
+ icon: 'weather-cloudy',
+ animation: require('../assets/lotties/03d.json'),
+ },
+ '09d': {
+ icon: 'weather-rainy',
+ animation: require('../assets/lotties/09d.json'),
+ },
+ '09n': {
+ icon: 'weather-rainy',
+ animation: require('../assets/lotties/09n.json'),
+ },
+ '10d': {
+ icon: 'weather-pouring',
+ animation: require('../assets/lotties/09d.json'),
+ },
+ '10n': {
+ icon: 'weather-pouring',
+ animation: require('../assets/lotties/09n.json'),
+ },
+ '11d': {
+ icon: 'weather-lightning-rainy',
+ animation: require('../assets/lotties/11d.json'),
+ },
+ '11n': {
+ icon: 'weather-lightning-rainy',
+ animation: require('../assets/lotties/11n.json'),
+ },
+ '13d': {
+ icon: 'weather-snowy-heavy',
+ animation: require('../assets/lotties/13d.json'),
+ },
+ '13n': {
+ icon: 'weather-snowy-heavy',
+ animation: require('../assets/lotties/13n.json'),
+ },
+ '50d': {
+ icon: 'weather-fog',
+ animation: require('../assets/lotties/50d.json'),
+ },
+ '50n': {
+ icon: 'weather-fog',
+ animation: require('../assets/lotties/50n.json'),
+ },
};
diff --git a/yarn.lock b/yarn.lock
index 358e76d..e66097b 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1951,6 +1951,11 @@ babel-plugin-syntax-trailing-function-commas@^7.0.0-beta.0:
resolved "https://registry.yarnpkg.com/babel-plugin-syntax-trailing-function-commas/-/babel-plugin-syntax-trailing-function-commas-7.0.0-beta.0.tgz#aa213c1435e2bffeb6fca842287ef534ad05d5cf"
integrity sha512-Xj9XuRuz3nTSbaTXWv3itLOcxyF4oPD8douBBmj7U9BBC6nEBYfyOJYQMf/8PJAFotC62UY5dFfIGEPr7WswzQ==
+babel-plugin-transform-remove-console@^6.9.4:
+ version "6.9.4"
+ resolved "https://registry.yarnpkg.com/babel-plugin-transform-remove-console/-/babel-plugin-transform-remove-console-6.9.4.tgz#b980360c067384e24b357a588d807d3c83527780"
+ integrity sha1-uYA2DAZzhOJLNXpYjYB9PINSd4A=
+
babel-preset-current-node-syntax@^0.1.2:
version "0.1.4"
resolved "https://registry.yarnpkg.com/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-0.1.4.tgz#826f1f8e7245ad534714ba001f84f7e906c3b615"