Skip to content

Commit ea4887a

Browse files
authored
Merge pull request #1 from kelvinthh/dev
Merge dev to master
2 parents 0ef4214 + db09131 commit ea4887a

File tree

103 files changed

+3812
-16
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

103 files changed

+3812
-16
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,3 +162,4 @@ package-lock.json
162162

163163
# Temporary files created by Metro to check the health of the file watcher
164164
.metro-health-check*
165+
.env

App.tsx

Lines changed: 39 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,42 @@
1-
import { StatusBar } from 'expo-status-bar';
2-
import { Text, View } from 'react-native';
1+
import React, { useEffect } from "react";
2+
import { SafeAreaView } from "react-native";
3+
import { RecoilRoot, useSetRecoilState } from "recoil";
4+
import Header from "./src/components/Header";
5+
import imageState from "./src/state/imageState";
6+
import Body from "./src/components/Body";
7+
import suggestionState from "./src/state/suggestionState";
8+
import { fetchImages, fetchSuggestion } from "./src/fetchData";
9+
import { Toast } from 'react-native-toast-message/lib/src/Toast';
310

4-
export default function App() {
11+
const AppContent = () => {
12+
const setImages = useSetRecoilState(imageState);
13+
const setSuggestion = useSetRecoilState(suggestionState);
14+
15+
useEffect(() => {
16+
(async () => {
17+
const images = await fetchImages();
18+
const suggestion = await fetchSuggestion();
19+
20+
setImages(images ?? []); // Provide an empty array as the default value
21+
setSuggestion(suggestion ?? ""); // Provide an empty string as the default value
22+
})();
23+
}, []);
24+
25+
return (
26+
<SafeAreaView className="flex-1">
27+
<Header />
28+
<Body />
29+
</SafeAreaView>
30+
);
31+
};
32+
33+
const App = () => {
534
return (
6-
<View className="flex-1 items-center justify-center bg-black text-white">
7-
<Text className='text-white'>Open up App.tsx to start working on your app!</Text>
8-
<StatusBar style="auto" />
9-
</View>
35+
<RecoilRoot>
36+
<AppContent />
37+
<Toast/>
38+
</RecoilRoot>
1039
);
11-
}
40+
};
41+
42+
export default App;

README.md

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
# React Native AI Image Generator with DALL-E and ChatGPT 🖼️📱
2+
3+
This is a mobile version of the [Image Generation Next.js](https://github.com/kelvinthh/Image-Generation-Next.js) app built with React Native, TypeScript, and NativeWind (Tailwind CSS) for styling. The app allows users to generate images based on text prompts, with suggestions provided by OpenAI's ChatGPT 3.5 API and images generated using OpenAI's DALL-E API. The back end is hosted on Azure Functions, and images are stored in Azure Storage.
4+
![](https://i.imgur.com/NZdLcXf.png)
5+
6+
## Features 🌟
7+
8+
- Generate images using text prompts powered by DALL-E 🎨
9+
- Get text prompt suggestion immediately generated by ChatGPT 3.5 💡
10+
- Swipe up to refresh images ⏳
11+
- Image overlay with name on long-press 🏷️
12+
13+
## Technologies 💻
14+
15+
- React Native with Expo
16+
- TypeScript
17+
- NativeWind (Tailwind CSS) for styling
18+
- OpenAI's ChatGPT 3.5 API for prompt suggestions
19+
- OpenAI's DALL-E API for image generation
20+
- Recoil for global state management
21+
- Azure Functions for back-end hosting
22+
- Azure Storage for storing images
23+
24+
## Getting Started 🚀
25+
26+
1. Clone this repository.
27+
28+
2. Install the required dependencies by running `npm install`.
29+
30+
3. Create a `.env` file in the project root and configure the required environment variables:
31+
```
32+
REMOTE_HOST=
33+
API_GET_IMAGES=
34+
API_GET_SUGGESTIONS=
35+
API_GENERATE_IMAGE=
36+
```
37+
38+
4. Run the app on your preferred platform (iOS or Android) using `npx react-native run-ios` or `npx react-native run-android`.
39+
40+
5. Enjoy generating and exploring images based on your text prompts! 🌈
41+
42+
## Additional Information ℹ️
43+
44+
- The back-end part of this project can be found in the [Image Generation Next.js](https://github.com/kelvinthh/Image-Generation-Next.js) repository.
45+
- The app is designed to work with the back end hosted on Azure Functions and images stored in Azure Storage.
46+
- The project is a creative and user-friendly application that offers suggestions and generates images based on user input.

android/.gitignore

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# OSX
2+
#
3+
.DS_Store
4+
5+
# Android/IntelliJ
6+
#
7+
build/
8+
.idea
9+
.gradle
10+
local.properties
11+
*.iml
12+
*.hprof
13+
14+
# Bundle artifacts
15+
*.jsbundle

android/app/build.gradle

Lines changed: 237 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,237 @@
1+
apply plugin: "com.android.application"
2+
apply plugin: "com.facebook.react"
3+
4+
import com.android.build.OutputFile
5+
6+
def projectRoot = rootDir.getAbsoluteFile().getParentFile().getAbsolutePath()
7+
def expoDebuggableVariants = ['debug']
8+
// Override `debuggableVariants` for expo-updates debugging
9+
if (System.getenv('EX_UPDATES_NATIVE_DEBUG') == "1") {
10+
react {
11+
expoDebuggableVariants = []
12+
}
13+
}
14+
15+
16+
/**
17+
* This is the configuration block to customize your React Native Android app.
18+
* By default you don't need to apply any configuration, just uncomment the lines you need.
19+
*/
20+
react {
21+
entryFile = file(["node", "-e", "require('expo/scripts/resolveAppEntry')", projectRoot, "android", "absolute"].execute(null, rootDir).text.trim())
22+
reactNativeDir = new File(["node", "--print", "require.resolve('react-native/package.json')"].execute(null, rootDir).text.trim()).getParentFile().getAbsoluteFile()
23+
hermesCommand = new File(["node", "--print", "require.resolve('react-native/package.json')"].execute(null, rootDir).text.trim()).getParentFile().getAbsolutePath() + "/sdks/hermesc/%OS-BIN%/hermesc"
24+
debuggableVariants = expoDebuggableVariants
25+
26+
/* Folders */
27+
// The root of your project, i.e. where "package.json" lives. Default is '..'
28+
// root = file("../")
29+
// The folder where the react-native NPM package is. Default is ../node_modules/react-native
30+
// reactNativeDir = file("../node_modules/react-native")
31+
// The folder where the react-native Codegen package is. Default is ../node_modules/react-native-codegen
32+
// codegenDir = file("../node_modules/react-native-codegen")
33+
// The cli.js file which is the React Native CLI entrypoint. Default is ../node_modules/react-native/cli.js
34+
// cliFile = file("../node_modules/react-native/cli.js")
35+
36+
/* Variants */
37+
// The list of variants to that are debuggable. For those we're going to
38+
// skip the bundling of the JS bundle and the assets. By default is just 'debug'.
39+
// If you add flavors like lite, prod, etc. you'll have to list your debuggableVariants.
40+
// debuggableVariants = ["liteDebug", "prodDebug"]
41+
42+
/* Bundling */
43+
// A list containing the node command and its flags. Default is just 'node'.
44+
// nodeExecutableAndArgs = ["node"]
45+
//
46+
// The command to run when bundling. By default is 'bundle'
47+
// bundleCommand = "ram-bundle"
48+
//
49+
// The path to the CLI configuration file. Default is empty.
50+
// bundleConfig = file(../rn-cli.config.js)
51+
//
52+
// The name of the generated asset file containing your JS bundle
53+
// bundleAssetName = "MyApplication.android.bundle"
54+
//
55+
// The entry file for bundle generation. Default is 'index.android.js' or 'index.js'
56+
// entryFile = file("../js/MyApplication.android.js")
57+
//
58+
// A list of extra flags to pass to the 'bundle' commands.
59+
// See https://github.com/react-native-community/cli/blob/main/docs/commands.md#bundle
60+
// extraPackagerArgs = []
61+
62+
/* Hermes Commands */
63+
// The hermes compiler command to run. By default it is 'hermesc'
64+
// hermesCommand = "$rootDir/my-custom-hermesc/bin/hermesc"
65+
//
66+
// The list of flags to pass to the Hermes compiler. By default is "-O", "-output-source-map"
67+
// hermesFlags = ["-O", "-output-source-map"]
68+
}
69+
70+
// Override `hermesEnabled` by `expo.jsEngine`
71+
ext {
72+
hermesEnabled = (findProperty('expo.jsEngine') ?: "hermes") == "hermes"
73+
}
74+
75+
/**
76+
* Set this to true to create four separate APKs instead of one,
77+
* one for each native architecture. This is useful if you don't
78+
* use App Bundles (https://developer.android.com/guide/app-bundle/)
79+
* and want to have separate APKs to upload to the Play Store.
80+
*/
81+
def enableSeparateBuildPerCPUArchitecture = false
82+
83+
/**
84+
* Set this to true to Run Proguard on Release builds to minify the Java bytecode.
85+
*/
86+
def enableProguardInReleaseBuilds = (findProperty('android.enableProguardInReleaseBuilds') ?: false).toBoolean()
87+
88+
/**
89+
* The preferred build flavor of JavaScriptCore (JSC)
90+
*
91+
* For example, to use the international variant, you can use:
92+
* `def jscFlavor = 'org.webkit:android-jsc-intl:+'`
93+
*
94+
* The international variant includes ICU i18n library and necessary data
95+
* allowing to use e.g. `Date.toLocaleString` and `String.localeCompare` that
96+
* give correct results when using with locales other than en-US. Note that
97+
* this variant is about 6MiB larger per architecture than default.
98+
*/
99+
def jscFlavor = 'org.webkit:android-jsc:+'
100+
101+
/**
102+
* Private function to get the list of Native Architectures you want to build.
103+
* This reads the value from reactNativeArchitectures in your gradle.properties
104+
* file and works together with the --active-arch-only flag of react-native run-android.
105+
*/
106+
def reactNativeArchitectures() {
107+
def value = project.getProperties().get("reactNativeArchitectures")
108+
return value ? value.split(",") : ["armeabi-v7a", "x86", "x86_64", "arm64-v8a"]
109+
}
110+
111+
android {
112+
ndkVersion rootProject.ext.ndkVersion
113+
114+
compileSdkVersion rootProject.ext.compileSdkVersion
115+
116+
namespace 'com.hhtam.imggenrn'
117+
defaultConfig {
118+
applicationId 'com.hhtam.imggenrn'
119+
minSdkVersion rootProject.ext.minSdkVersion
120+
targetSdkVersion rootProject.ext.targetSdkVersion
121+
versionCode 1
122+
versionName "1.0.0"
123+
}
124+
125+
splits {
126+
abi {
127+
reset()
128+
enable enableSeparateBuildPerCPUArchitecture
129+
universalApk false // If true, also generate a universal APK
130+
include (*reactNativeArchitectures())
131+
}
132+
}
133+
signingConfigs {
134+
debug {
135+
storeFile file('debug.keystore')
136+
storePassword 'android'
137+
keyAlias 'androiddebugkey'
138+
keyPassword 'android'
139+
}
140+
}
141+
buildTypes {
142+
debug {
143+
signingConfig signingConfigs.debug
144+
}
145+
release {
146+
// Caution! In production, you need to generate your own keystore file.
147+
// see https://reactnative.dev/docs/signed-apk-android.
148+
signingConfig signingConfigs.debug
149+
shrinkResources (findProperty('android.enableShrinkResourcesInReleaseBuilds')?.toBoolean() ?: false)
150+
minifyEnabled enableProguardInReleaseBuilds
151+
proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
152+
}
153+
}
154+
155+
// applicationVariants are e.g. debug, release
156+
applicationVariants.all { variant ->
157+
variant.outputs.each { output ->
158+
// For each separate APK per architecture, set a unique version code as described here:
159+
// https://developer.android.com/studio/build/configure-apk-splits.html
160+
// Example: versionCode 1 will generate 1001 for armeabi-v7a, 1002 for x86, etc.
161+
def versionCodes = ["armeabi-v7a": 1, "x86": 2, "arm64-v8a": 3, "x86_64": 4]
162+
def abi = output.getFilter(OutputFile.ABI)
163+
if (abi != null) { // null for the universal-debug, universal-release variants
164+
output.versionCodeOverride =
165+
defaultConfig.versionCode * 1000 + versionCodes.get(abi)
166+
}
167+
168+
}
169+
}
170+
}
171+
172+
// Apply static values from `gradle.properties` to the `android.packagingOptions`
173+
// Accepts values in comma delimited lists, example:
174+
// android.packagingOptions.pickFirsts=/LICENSE,**/picasa.ini
175+
["pickFirsts", "excludes", "merges", "doNotStrip"].each { prop ->
176+
// Split option: 'foo,bar' -> ['foo', 'bar']
177+
def options = (findProperty("android.packagingOptions.$prop") ?: "").split(",");
178+
// Trim all elements in place.
179+
for (i in 0..<options.size()) options[i] = options[i].trim();
180+
// `[] - ""` is essentially `[""].filter(Boolean)` removing all empty strings.
181+
options -= ""
182+
183+
if (options.length > 0) {
184+
println "android.packagingOptions.$prop += $options ($options.length)"
185+
// Ex: android.packagingOptions.pickFirsts += '**/SCCS/**'
186+
options.each {
187+
android.packagingOptions[prop] += it
188+
}
189+
}
190+
}
191+
192+
dependencies {
193+
// The version of react-native is set by the React Native Gradle Plugin
194+
implementation("com.facebook.react:react-android")
195+
196+
def isGifEnabled = (findProperty('expo.gif.enabled') ?: "") == "true";
197+
def isWebpEnabled = (findProperty('expo.webp.enabled') ?: "") == "true";
198+
def isWebpAnimatedEnabled = (findProperty('expo.webp.animated') ?: "") == "true";
199+
def frescoVersion = rootProject.ext.frescoVersion
200+
201+
// If your app supports Android versions before Ice Cream Sandwich (API level 14)
202+
if (isGifEnabled || isWebpEnabled) {
203+
implementation("com.facebook.fresco:fresco:${frescoVersion}")
204+
implementation("com.facebook.fresco:imagepipeline-okhttp3:${frescoVersion}")
205+
}
206+
207+
if (isGifEnabled) {
208+
// For animated gif support
209+
implementation("com.facebook.fresco:animated-gif:${frescoVersion}")
210+
}
211+
212+
if (isWebpEnabled) {
213+
// For webp support
214+
implementation("com.facebook.fresco:webpsupport:${frescoVersion}")
215+
if (isWebpAnimatedEnabled) {
216+
// Animated webp support
217+
implementation("com.facebook.fresco:animated-webp:${frescoVersion}")
218+
}
219+
}
220+
221+
implementation("androidx.swiperefreshlayout:swiperefreshlayout:1.0.0")
222+
223+
debugImplementation("com.facebook.flipper:flipper:${FLIPPER_VERSION}")
224+
debugImplementation("com.facebook.flipper:flipper-network-plugin:${FLIPPER_VERSION}") {
225+
exclude group:'com.squareup.okhttp3', module:'okhttp'
226+
}
227+
debugImplementation("com.facebook.flipper:flipper-fresco-plugin:${FLIPPER_VERSION}")
228+
229+
if (hermesEnabled.toBoolean()) {
230+
implementation("com.facebook.react:hermes-android")
231+
} else {
232+
implementation jscFlavor
233+
}
234+
}
235+
236+
apply from: new File(["node", "--print", "require.resolve('@react-native-community/cli-platform-android/package.json')"].execute(null, rootDir).text.trim(), "../native_modules.gradle");
237+
applyNativeModulesAppBuildGradle(project)

android/app/debug.keystore

2.2 KB
Binary file not shown.

android/app/proguard-rules.pro

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# Add project specific ProGuard rules here.
2+
# By default, the flags in this file are appended to flags specified
3+
# in /usr/local/Cellar/android-sdk/24.3.3/tools/proguard/proguard-android.txt
4+
# You can edit the include path and order by changing the proguardFiles
5+
# directive in build.gradle.
6+
#
7+
# For more details, see
8+
# http://developer.android.com/guide/developing/tools/proguard.html
9+
10+
# react-native-reanimated
11+
-keep class com.swmansion.reanimated.** { *; }
12+
-keep class com.facebook.react.turbomodule.** { *; }
13+
14+
# Add any project specific keep options here:
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
2+
xmlns:tools="http://schemas.android.com/tools">
3+
4+
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
5+
6+
<application android:usesCleartextTraffic="true" tools:targetApi="28" tools:ignore="GoogleAppIndexingWarning" />
7+
</manifest>

0 commit comments

Comments
 (0)