├── .buckconfig ├── .eslintrc.js ├── .flowconfig ├── .gitattributes ├── .gitignore ├── .prettierrc.js ├── .vscode └── settings.json ├── .watchmanconfig ├── README.md ├── __tests__ ├── App-test.js └── App.js ├── android ├── app │ ├── _BUCK │ ├── build.gradle │ ├── build_defs.bzl │ ├── debug.keystore │ ├── proguard-rules.pro │ └── src │ │ ├── debug │ │ ├── AndroidManifest.xml │ │ └── java │ │ │ └── com │ │ │ └── wahlswiper │ │ │ └── ReactNativeFlipper.java │ │ └── main │ │ ├── AndroidManifest.xml │ │ ├── assets │ │ └── fonts │ │ │ ├── Rubik-Bold.ttf │ │ │ ├── Rubik-Medium.ttf │ │ │ ├── Rubik-Regular.ttf │ │ │ └── Wahlswiper.ttf │ │ ├── ic_launcher-web.png │ │ ├── java │ │ └── com │ │ │ └── wahlswiper │ │ │ ├── MainActivity.java │ │ │ └── MainApplication.java │ │ └── res │ │ ├── mipmap-anydpi-v26 │ │ ├── ic_launcher.xml │ │ └── ic_launcher_round.xml │ │ ├── mipmap-hdpi │ │ ├── ic_launcher.png │ │ ├── ic_launcher_background.png │ │ ├── ic_launcher_foreground.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-mdpi │ │ ├── ic_launcher.png │ │ ├── ic_launcher_background.png │ │ ├── ic_launcher_foreground.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xhdpi │ │ ├── ic_launcher.png │ │ ├── ic_launcher_background.png │ │ ├── ic_launcher_foreground.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxhdpi │ │ ├── ic_launcher.png │ │ ├── ic_launcher_background.png │ │ ├── ic_launcher_foreground.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxxhdpi │ │ ├── ic_launcher.png │ │ ├── ic_launcher_background.png │ │ ├── ic_launcher_foreground.png │ │ └── ic_launcher_round.png │ │ ├── values-de │ │ └── strings.xml │ │ ├── values │ │ ├── strings.xml │ │ └── styles.xml │ │ └── xml │ │ └── filepaths.xml ├── build.gradle ├── gradle.properties ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle ├── app.json ├── assets └── icons │ ├── arrow-left.svg │ ├── arrow-right.svg │ ├── at.svg │ ├── check.svg │ ├── chevron-right.svg │ ├── circle-arrow-right.svg │ ├── circle-help.svg │ ├── circle-info.svg │ ├── close.svg │ ├── cog.svg │ ├── de.svg │ ├── download.svg │ ├── flags │ ├── cz.svg │ ├── dk.svg │ ├── ee.svg │ ├── fi.svg │ ├── gr.svg │ ├── hu.svg │ ├── it.svg │ ├── lt.svg │ ├── nl.svg │ ├── ro.svg │ └── se.svg │ ├── fr.svg │ ├── pl.svg │ ├── play.svg │ ├── share.svg │ ├── skip.svg │ └── swiper.svg ├── babel.config.js ├── index.js ├── ios ├── Launch Screen.storyboard ├── OneSignalNotificationServiceExtension │ ├── Info.plist │ ├── NotificationService.h │ ├── NotificationService.m │ └── OneSignalNotificationServiceExtension.entitlements ├── Podfile ├── Podfile.lock ├── ar.lproj │ └── InfoPlist.strings ├── de.lproj │ └── InfoPlist.strings ├── en.lproj │ └── InfoPlist.strings ├── fa.lproj │ └── InfoPlist.strings ├── fi.lproj │ └── InfoPlist.strings ├── fr.lproj │ └── InfoPlist.strings ├── ku.lproj │ └── InfoPlist.strings ├── launch_icon.png ├── launch_icon_de.png ├── launchscreen_gradient.jpg ├── launchscreen_icon_de.png ├── ru.lproj │ └── InfoPlist.strings ├── sv.lproj │ └── InfoPlist.strings ├── test.swift ├── tr.lproj │ └── InfoPlist.strings ├── voteswiper-Bridging-Header.h ├── voteswiper-tvOS │ └── Info.plist ├── voteswiper-tvOSTests │ └── Info.plist ├── voteswiper.xcodeproj │ ├── project.pbxproj │ ├── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ └── IDEWorkspaceChecks.plist │ └── xcshareddata │ │ └── xcschemes │ │ ├── OneSignalNotificationServiceExtension.xcscheme │ │ ├── voteswiper-tvOS.xcscheme │ │ └── voteswiper.xcscheme ├── voteswiper.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist ├── voteswiper │ ├── AppDelegate.h │ ├── AppDelegate.m │ ├── Images.xcassets │ │ ├── AppIcon.appiconset │ │ │ ├── 1024.png │ │ │ ├── 20x1.png │ │ │ ├── 20x2-1.png │ │ │ ├── 20x2.png │ │ │ ├── 20x3.png │ │ │ ├── 29x1.png │ │ │ ├── 29x2-1.png │ │ │ ├── 29x2.png │ │ │ ├── 29x3.png │ │ │ ├── 40x1.png │ │ │ ├── 40x2-1.png │ │ │ ├── 40x2.png │ │ │ ├── 40x3.png │ │ │ ├── 60x2.png │ │ │ ├── 60x3.png │ │ │ ├── 76x1.png │ │ │ ├── 76x2.png │ │ │ ├── 83-5x2.png │ │ │ └── Contents.json │ │ └── Contents.json │ ├── Info.plist │ ├── main.m │ └── voteswiper.entitlements └── voteswiperTests │ ├── Info.plist │ └── voteswiperTests.m ├── metro.config.js ├── package.json ├── src ├── App.tsx ├── Init.tsx ├── Navigator.tsx ├── common │ ├── breakpoints.ts │ ├── config.ts │ ├── headerHeight.ts │ └── package.json ├── components │ ├── Box │ │ ├── index.tsx │ │ └── styles.ts │ ├── BoxGradient │ │ ├── index.tsx │ │ └── styles.ts │ ├── ButtonDark │ │ ├── index.tsx │ │ └── styles.ts │ ├── ButtonGradient │ │ ├── index.tsx │ │ └── styles.ts │ ├── Container │ │ ├── index.tsx │ │ └── styles.ts │ ├── Countdown │ │ ├── index.tsx │ │ └── styles.ts │ ├── CountryPill │ │ ├── index.tsx │ │ └── styles.ts │ ├── ElectionPill │ │ ├── index.tsx │ │ └── styles.ts │ ├── FadeIn │ │ └── index.tsx │ ├── FullScreenVideo │ │ ├── index.tsx │ │ └── styles.ts │ ├── Loader │ │ └── index.tsx │ ├── ResultBar │ │ ├── index.tsx │ │ └── styles.ts │ ├── ScrollContainer │ │ ├── index.tsx │ │ └── styles.ts │ ├── ShareButton │ │ ├── index.tsx │ │ └── styles.ts │ ├── Title │ │ ├── index.tsx │ │ └── styles.ts │ ├── Txt │ │ ├── index.tsx │ │ └── styles.ts │ └── package.json ├── connectors │ ├── api.ts │ ├── package.json │ └── storyblok.ts ├── contexts │ ├── app.tsx │ ├── package.json │ └── swiper.tsx ├── global.d.ts ├── icons │ ├── AT.tsx │ ├── AdjustmentHorizontal.tsx │ ├── ArrowLeft.tsx │ ├── ArrowRight.tsx │ ├── ArrowRightCircle.tsx │ ├── BoxMultiple.tsx │ ├── CZ.tsx │ ├── Check.tsx │ ├── ChevronRight.tsx │ ├── Close.tsx │ ├── Cog.tsx │ ├── DE.tsx │ ├── DK.tsx │ ├── Download.tsx │ ├── EE.tsx │ ├── FI.tsx │ ├── FR.tsx │ ├── GR.tsx │ ├── HU.tsx │ ├── HelpCircle.tsx │ ├── IT.tsx │ ├── InfoCircle.tsx │ ├── LT.tsx │ ├── NL.tsx │ ├── PL.tsx │ ├── Play.tsx │ ├── Polaroid.tsx │ ├── RO.tsx │ ├── SE.tsx │ ├── Share.tsx │ ├── Skip.tsx │ ├── Swiper.tsx │ └── package.json ├── resources │ └── fonts │ │ ├── Rubik-Bold.ttf │ │ ├── Rubik-Medium.ttf │ │ ├── Rubik-Regular.ttf │ │ └── Wahlswiper.ttf ├── rtl.ts ├── screens │ ├── ElectionDetails │ │ ├── index.tsx │ │ └── styles.ts │ ├── ElectionsIndex │ │ ├── index.tsx │ │ └── styles.ts │ ├── HelpIndex │ │ ├── index.tsx │ │ └── styles.ts │ ├── InfosIndex │ │ ├── index.tsx │ │ └── styles.ts │ ├── SelectCountry │ │ ├── index.tsx │ │ └── styles.ts │ ├── Settings │ │ ├── index.tsx │ │ └── styles.ts │ ├── SettingsCountry │ │ ├── index.tsx │ │ └── styles.ts │ ├── Swiper │ │ ├── components │ │ │ ├── Card │ │ │ │ ├── index.tsx │ │ │ │ └── styles.ts │ │ │ ├── ExitConfirmDialog │ │ │ │ ├── index.tsx │ │ │ │ └── styles.ts │ │ │ ├── MainButton │ │ │ │ ├── index.tsx │ │ │ │ └── styles.ts │ │ │ └── NavigationButton │ │ │ │ ├── index.tsx │ │ │ │ └── styles.ts │ │ ├── index.tsx │ │ └── styles.ts │ ├── SwiperChooseParties │ │ ├── index.tsx │ │ └── styles.ts │ ├── SwiperCompareParty │ │ ├── index.tsx │ │ └── styles.ts │ ├── SwiperEditAnswers │ │ ├── index.tsx │ │ └── styles.ts │ ├── SwiperExplainer │ │ ├── index.tsx │ │ └── styles.ts │ ├── SwiperResult │ │ ├── index.tsx │ │ └── styles.ts │ ├── SwiperVideo │ │ └── index.tsx │ └── package.json ├── translations │ ├── ar.ts │ ├── de.ts │ ├── en.ts │ ├── fa.ts │ ├── fi.ts │ ├── fr.ts │ ├── index.ts │ ├── ku.ts │ ├── package.json │ ├── ru.ts │ ├── sv.ts │ └── tr.ts ├── types │ ├── api.d.ts │ ├── package.json │ └── routes.d.ts └── util │ ├── cdn.ts │ ├── getCountryFlag.tsx │ ├── iPhoneXHelper.ts │ ├── locale.ts │ ├── momentLocale.ts │ ├── package.json │ └── storyblok-rich-text.tsx ├── tsconfig.json └── yarn.lock /.buckconfig: -------------------------------------------------------------------------------- 1 | 2 | [android] 3 | target = Google Inc.:Google APIs:23 4 | 5 | [maven_repositories] 6 | central = https://repo1.maven.org/maven2 7 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | extends: '@react-native-community', 4 | }; -------------------------------------------------------------------------------- /.flowconfig: -------------------------------------------------------------------------------- 1 | [ignore] 2 | ; We fork some components by platform 3 | .*/*[.]android.js 4 | 5 | ; Ignore "BUCK" generated dirs 6 | /\.buckd/ 7 | 8 | ; Ignore polyfills 9 | node_modules/react-native/Libraries/polyfills/.* 10 | 11 | ; These should not be required directly 12 | ; require from fbjs/lib instead: require('fbjs/lib/warning') 13 | node_modules/warning/.* 14 | 15 | ; Flow doesn't support platforms 16 | .*/Libraries/Utilities/LoadingView.js 17 | 18 | [untyped] 19 | .*/node_modules/@react-native-community/cli/.*/.* 20 | 21 | [include] 22 | 23 | [libs] 24 | node_modules/react-native/interface.js 25 | node_modules/react-native/flow/ 26 | 27 | [options] 28 | emoji=true 29 | 30 | esproposal.optional_chaining=enable 31 | esproposal.nullish_coalescing=enable 32 | 33 | module.file_ext=.js 34 | module.file_ext=.json 35 | module.file_ext=.ios.js 36 | 37 | munge_underscores=true 38 | 39 | module.name_mapper='^react-native/\(.*\)$' -> '/node_modules/react-native/\1' 40 | module.name_mapper='^@?[./a-zA-Z0-9$_-]+\.\(bmp\|gif\|jpg\|jpeg\|png\|psd\|svg\|webp\|m4v\|mov\|mp4\|mpeg\|mpg\|webm\|aac\|aiff\|caf\|m4a\|mp3\|wav\|html\|pdf\)$' -> '/node_modules/react-native/Libraries/Image/RelativeImageStub' 41 | 42 | suppress_type=$FlowIssue 43 | suppress_type=$FlowFixMe 44 | suppress_type=$FlowFixMeProps 45 | suppress_type=$FlowFixMeState 46 | 47 | suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(\\)? *\\(site=[a-z,_]*react_native\\(_ios\\)?_\\(oss\\|fb\\)[a-z,_]*\\)?)\\) 48 | suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(\\)? *\\(site=[a-z,_]*react_native\\(_ios\\)?_\\(oss\\|fb\\)[a-z,_]*\\)?)\\)?:? #[0-9]+ 49 | suppress_comment=\\(.\\|\n\\)*\\$FlowExpectedError 50 | 51 | [lints] 52 | sketchy-null-number=warn 53 | sketchy-null-mixed=warn 54 | sketchy-number=warn 55 | untyped-type-import=warn 56 | nonstrict-import=warn 57 | deprecated-type=warn 58 | unsafe-getters-setters=warn 59 | unnecessary-invariant=warn 60 | signature-verification-failure=warn 61 | deprecated-utility=error 62 | 63 | [strict] 64 | deprecated-type 65 | nonstrict-import 66 | sketchy-null 67 | unclear-type 68 | unsafe-getters-setters 69 | untyped-import 70 | untyped-type-import 71 | 72 | [version] 73 | ^0.122.0 -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | *.pbxproj -text 2 | # specific for windows script files 3 | *.bat text eol=crlf -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # OSX 2 | # 3 | .DS_Store 4 | 5 | # Xcode 6 | # 7 | build/ 8 | *.pbxuser 9 | !default.pbxuser 10 | *.mode1v3 11 | !default.mode1v3 12 | *.mode2v3 13 | !default.mode2v3 14 | *.perspectivev3 15 | !default.perspectivev3 16 | xcuserdata 17 | *.xccheckout 18 | *.moved-aside 19 | DerivedData 20 | *.hmap 21 | *.ipa 22 | *.xcuserstate 23 | 24 | # Android/IntelliJ 25 | # 26 | build/ 27 | .idea 28 | .gradle 29 | local.properties 30 | *.iml 31 | 32 | # node.js 33 | # 34 | node_modules/ 35 | npm-debug.log 36 | yarn-error.log 37 | 38 | # BUCK 39 | buck-out/ 40 | \.buckd/ 41 | *.keystore 42 | !debug.keystore 43 | 44 | # fastlane 45 | # 46 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 47 | # screenshots whenever they are needed. 48 | # For more information about the recommended setup visit: 49 | # https://docs.fastlane.tools/best-practices/source-control/ 50 | 51 | */fastlane/report.xml 52 | */fastlane/Preview.html 53 | */fastlane/screenshots 54 | 55 | # Bundle artifact 56 | *.jsbundle 57 | 58 | # CocoaPods 59 | /ios/Pods/ -------------------------------------------------------------------------------- /.prettierrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | bracketSpacing: false, 3 | jsxBracketSameLine: true, 4 | singleQuote: true, 5 | trailingComma: 'all', 6 | }; -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | // "search.useIgnoreFiles": false, 3 | // "search.exclude": { 4 | // "**/node_modules": false, 5 | // }, 6 | } -------------------------------------------------------------------------------- /.watchmanconfig: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # VoteSwiper / WahlSwiper - App 2 | 3 | [![Last Commit](https://img.shields.io/github/last-commit/movact/voteswiper-app)](https://github.com/MOVACT/voteswiper-app/commits) [![Open issues](https://img.shields.io/github/issues/movact/voteswiper-app)](https://github.com/MOVACT/voteswiper-app/issues) [![Follow WahlSwiper](https://img.shields.io/twitter/follow/wahlswiper)](https://www.twitter.com/wahlswiper) 4 | 5 | VoteSwiper (in Germany better known as WahlSwiper) is a cross-platform voting advice app for Android, iOS and web browsers. The app is operated by [MOVACT](https://www.movact.de) primarily for German federale and state elections. The content for the surveys is researched and developed by various institutions, most recently mainly by political scientists at the University of Freiburg. 6 | 7 | We started this project in 2017 for the federal election and since then grow a user base of over one million. While we operated closed source for a long time, we believe the right thing to do is to disclose the source code of the whole project for transparency. 8 | 9 | ## Development 10 | 11 | The app is built with React Native. You can start the project, like any other React Native project, by starting the Metro bundler and running the following commands in the terminal. Head over to the React Native documentation [here](https://reactnative.dev/docs/environment-setup) to learn more. 12 | 13 | #### 1. Start the bundler 14 | 15 | ```console 16 | react-native start 17 | ``` 18 | 19 | #### 1. Start the emulator 20 | 21 | ```console 22 | react-native run-ios 23 | ``` 24 | 25 | or 26 | 27 | ```console 28 | react-native run-android 29 | ``` 30 | 31 | ## How to contribute 32 | 33 | We appreciate any feedback. Feel free to open an issue if you find errors or use the discussion board if you'd like to suggest new features. 34 | 35 | ## Security Bugs 36 | 37 | If you find any security related issues we would appreciate if you safely disclose the issue to us via email to [max@voteswiper.org](mailto:max@voteswiper.org) directly. 38 | 39 | ## Contributors 40 | 41 | [![](https://github.com/mxmtsk.png?size=50)](https://github.com/mxmtsk) 42 | 43 | ## License 44 | 45 | Copyright MOVACT GmbH 46 | -------------------------------------------------------------------------------- /__tests__/App-test.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @format 3 | */ 4 | 5 | import 'react-native'; 6 | import React from 'react'; 7 | import App from '../src/App'; 8 | 9 | // Note: test renderer must be required after react-native. 10 | import renderer from 'react-test-renderer'; 11 | 12 | it('renders correctly', () => { 13 | renderer.create(); 14 | }); 15 | -------------------------------------------------------------------------------- /__tests__/App.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @format 3 | * @lint-ignore-every XPLATJSCOPYRIGHT1 4 | */ 5 | 6 | import 'react-native'; 7 | import React from 'react'; 8 | import App from '../src/App'; 9 | 10 | // Note: test renderer must be required after react-native. 11 | import renderer from 'react-test-renderer'; 12 | 13 | it('renders correctly', () => { 14 | renderer.create(); 15 | }); 16 | -------------------------------------------------------------------------------- /android/app/_BUCK: -------------------------------------------------------------------------------- 1 | # To learn about Buck see [Docs](https://buckbuild.com/). 2 | # To run your application with Buck: 3 | # - install Buck 4 | # - `npm start` - to start the packager 5 | # - `cd android` 6 | # - `keytool -genkey -v -keystore keystores/debug.keystore -storepass android -alias androiddebugkey -keypass android -dname "CN=Android Debug,O=Android,C=US"` 7 | # - `./gradlew :app:copyDownloadableDepsToLibs` - make all Gradle compile dependencies available to Buck 8 | # - `buck install -r android/app` - compile, install and run application 9 | # 10 | 11 | load(":build_defs.bzl", "create_aar_targets", "create_jar_targets") 12 | 13 | lib_deps = [] 14 | 15 | create_aar_targets(glob(["libs/*.aar"])) 16 | 17 | create_jar_targets(glob(["libs/*.jar"])) 18 | 19 | android_library( 20 | name = "all-libs", 21 | exported_deps = lib_deps, 22 | ) 23 | 24 | android_library( 25 | name = "app-code", 26 | srcs = glob([ 27 | "src/main/java/**/*.java", 28 | ]), 29 | deps = [ 30 | ":all-libs", 31 | ":build_config", 32 | ":res", 33 | ], 34 | ) 35 | 36 | android_build_config( 37 | name = "build_config", 38 | package = "com.wahlswiper", 39 | ) 40 | 41 | android_resource( 42 | name = "res", 43 | package = "com.wahlswiper", 44 | res = "src/main/res", 45 | ) 46 | 47 | android_binary( 48 | name = "app", 49 | keystore = "//android/keystores:debug", 50 | manifest = "src/main/AndroidManifest.xml", 51 | package_type = "debug", 52 | deps = [ 53 | ":app-code", 54 | ], 55 | ) 56 | -------------------------------------------------------------------------------- /android/app/build_defs.bzl: -------------------------------------------------------------------------------- 1 | """Helper definitions to glob .aar and .jar targets""" 2 | 3 | def create_aar_targets(aarfiles): 4 | for aarfile in aarfiles: 5 | name = "aars__" + aarfile[aarfile.rindex("/") + 1:aarfile.rindex(".aar")] 6 | lib_deps.append(":" + name) 7 | android_prebuilt_aar( 8 | name = name, 9 | aar = aarfile, 10 | ) 11 | 12 | def create_jar_targets(jarfiles): 13 | for jarfile in jarfiles: 14 | name = "jars__" + jarfile[jarfile.rindex("/") + 1:jarfile.rindex(".jar")] 15 | lib_deps.append(":" + name) 16 | prebuilt_jar( 17 | name = name, 18 | binary_jar = jarfile, 19 | ) 20 | -------------------------------------------------------------------------------- /android/app/debug.keystore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MOVACT/voteswiper-app/27acbaddb5ba3655f2110ee27c07be8014d05520/android/app/debug.keystore -------------------------------------------------------------------------------- /android/app/proguard-rules.pro: -------------------------------------------------------------------------------- 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 | # Add any project specific keep options here: -------------------------------------------------------------------------------- /android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 15 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /android/app/src/main/assets/fonts/Rubik-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MOVACT/voteswiper-app/27acbaddb5ba3655f2110ee27c07be8014d05520/android/app/src/main/assets/fonts/Rubik-Bold.ttf -------------------------------------------------------------------------------- /android/app/src/main/assets/fonts/Rubik-Medium.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MOVACT/voteswiper-app/27acbaddb5ba3655f2110ee27c07be8014d05520/android/app/src/main/assets/fonts/Rubik-Medium.ttf -------------------------------------------------------------------------------- /android/app/src/main/assets/fonts/Rubik-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MOVACT/voteswiper-app/27acbaddb5ba3655f2110ee27c07be8014d05520/android/app/src/main/assets/fonts/Rubik-Regular.ttf -------------------------------------------------------------------------------- /android/app/src/main/assets/fonts/Wahlswiper.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MOVACT/voteswiper-app/27acbaddb5ba3655f2110ee27c07be8014d05520/android/app/src/main/assets/fonts/Wahlswiper.ttf -------------------------------------------------------------------------------- /android/app/src/main/ic_launcher-web.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MOVACT/voteswiper-app/27acbaddb5ba3655f2110ee27c07be8014d05520/android/app/src/main/ic_launcher-web.png -------------------------------------------------------------------------------- /android/app/src/main/java/com/wahlswiper/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.wahlswiper; 2 | 3 | import com.facebook.react.ReactActivity; 4 | import com.facebook.react.ReactActivityDelegate; 5 | import com.facebook.react.ReactRootView; 6 | import com.swmansion.gesturehandler.react.RNGestureHandlerEnabledRootView; 7 | import android.os.Bundle; 8 | 9 | public class MainActivity extends ReactActivity { 10 | @Override 11 | protected void onCreate(Bundle savedInstanceState) { 12 | super.onCreate(null); 13 | } 14 | 15 | /** 16 | * Returns the name of the main component registered from JavaScript. This is used to schedule 17 | * rendering of the component. 18 | */ 19 | @Override 20 | protected String getMainComponentName() { 21 | return "wahlswiper"; 22 | } 23 | 24 | @Override 25 | protected ReactActivityDelegate createReactActivityDelegate() { 26 | return new ReactActivityDelegate(this, getMainComponentName()) { 27 | @Override 28 | protected ReactRootView createRootView() { 29 | return new RNGestureHandlerEnabledRootView(MainActivity.this); 30 | } 31 | }; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /android/app/src/main/java/com/wahlswiper/MainApplication.java: -------------------------------------------------------------------------------- 1 | package com.wahlswiper; 2 | 3 | import android.app.Application; 4 | import android.content.Context; 5 | import com.facebook.react.PackageList; 6 | import com.facebook.react.ReactApplication; 7 | import com.facebook.react.ReactInstanceManager; 8 | import com.facebook.react.ReactNativeHost; 9 | import com.facebook.react.ReactPackage; 10 | import com.facebook.soloader.SoLoader; 11 | import java.lang.reflect.InvocationTargetException; 12 | import java.util.List; 13 | 14 | public class MainApplication extends Application implements ReactApplication { 15 | 16 | private final ReactNativeHost mReactNativeHost = 17 | new ReactNativeHost(this) { 18 | @Override 19 | public boolean getUseDeveloperSupport() { 20 | return BuildConfig.DEBUG; 21 | } 22 | 23 | @Override 24 | protected List getPackages() { 25 | @SuppressWarnings("UnnecessaryLocalVariable") 26 | List packages = new PackageList(this).getPackages(); 27 | // Packages that cannot be autolinked yet can be added manually here, for example: 28 | // packages.add(new MyReactNativePackage()); 29 | return packages; 30 | } 31 | 32 | @Override 33 | protected String getJSMainModuleName() { 34 | return "index"; 35 | } 36 | }; 37 | 38 | @Override 39 | public ReactNativeHost getReactNativeHost() { 40 | return mReactNativeHost; 41 | } 42 | 43 | @Override 44 | public void onCreate() { 45 | super.onCreate(); 46 | SoLoader.init(this, /* native exopackage */ false); 47 | initializeFlipper(this, getReactNativeHost().getReactInstanceManager()); 48 | } 49 | 50 | /** 51 | * Loads Flipper in React Native templates. Call this in the onCreate method with something like 52 | * initializeFlipper(this, getReactNativeHost().getReactInstanceManager()); 53 | * 54 | * @param context 55 | * @param reactInstanceManager 56 | */ 57 | private static void initializeFlipper( 58 | Context context, ReactInstanceManager reactInstanceManager) { 59 | if (BuildConfig.DEBUG) { 60 | try { 61 | /* 62 | We use reflection here to pick up the class that initializes Flipper, 63 | since Flipper library is not available in release mode 64 | */ 65 | Class aClass = Class.forName("com.wahlswiper.ReactNativeFlipper"); 66 | aClass 67 | .getMethod("initializeFlipper", Context.class, ReactInstanceManager.class) 68 | .invoke(null, context, reactInstanceManager); 69 | } catch (ClassNotFoundException e) { 70 | e.printStackTrace(); 71 | } catch (NoSuchMethodException e) { 72 | e.printStackTrace(); 73 | } catch (IllegalAccessException e) { 74 | e.printStackTrace(); 75 | } catch (InvocationTargetException e) { 76 | e.printStackTrace(); 77 | } 78 | } 79 | } 80 | } -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MOVACT/voteswiper-app/27acbaddb5ba3655f2110ee27c07be8014d05520/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-hdpi/ic_launcher_background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MOVACT/voteswiper-app/27acbaddb5ba3655f2110ee27c07be8014d05520/android/app/src/main/res/mipmap-hdpi/ic_launcher_background.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MOVACT/voteswiper-app/27acbaddb5ba3655f2110ee27c07be8014d05520/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MOVACT/voteswiper-app/27acbaddb5ba3655f2110ee27c07be8014d05520/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MOVACT/voteswiper-app/27acbaddb5ba3655f2110ee27c07be8014d05520/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/ic_launcher_background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MOVACT/voteswiper-app/27acbaddb5ba3655f2110ee27c07be8014d05520/android/app/src/main/res/mipmap-mdpi/ic_launcher_background.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MOVACT/voteswiper-app/27acbaddb5ba3655f2110ee27c07be8014d05520/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MOVACT/voteswiper-app/27acbaddb5ba3655f2110ee27c07be8014d05520/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MOVACT/voteswiper-app/27acbaddb5ba3655f2110ee27c07be8014d05520/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/ic_launcher_background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MOVACT/voteswiper-app/27acbaddb5ba3655f2110ee27c07be8014d05520/android/app/src/main/res/mipmap-xhdpi/ic_launcher_background.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MOVACT/voteswiper-app/27acbaddb5ba3655f2110ee27c07be8014d05520/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MOVACT/voteswiper-app/27acbaddb5ba3655f2110ee27c07be8014d05520/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MOVACT/voteswiper-app/27acbaddb5ba3655f2110ee27c07be8014d05520/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/ic_launcher_background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MOVACT/voteswiper-app/27acbaddb5ba3655f2110ee27c07be8014d05520/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_background.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MOVACT/voteswiper-app/27acbaddb5ba3655f2110ee27c07be8014d05520/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MOVACT/voteswiper-app/27acbaddb5ba3655f2110ee27c07be8014d05520/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MOVACT/voteswiper-app/27acbaddb5ba3655f2110ee27c07be8014d05520/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MOVACT/voteswiper-app/27acbaddb5ba3655f2110ee27c07be8014d05520/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_background.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MOVACT/voteswiper-app/27acbaddb5ba3655f2110ee27c07be8014d05520/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MOVACT/voteswiper-app/27acbaddb5ba3655f2110ee27c07be8014d05520/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /android/app/src/main/res/values-de/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | WahlSwiper 3 | 4 | -------------------------------------------------------------------------------- /android/app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | VoteSwiper 3 | 4 | -------------------------------------------------------------------------------- /android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /android/app/src/main/res/xml/filepaths.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /android/build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | ext { 5 | buildToolsVersion = "29.0.2" 6 | minSdkVersion = 16 7 | compileSdkVersion = 29 8 | targetSdkVersion = 29 9 | } 10 | repositories { 11 | google() 12 | jcenter() 13 | } 14 | dependencies { 15 | classpath("com.android.tools.build:gradle:3.5.3") 16 | 17 | // NOTE: Do not place your application dependencies here; they belong 18 | // in the individual module build.gradle files 19 | } 20 | } 21 | 22 | subprojects { 23 | afterEvaluate {project -> 24 | if (project.hasProperty("android")) { 25 | android { 26 | compileSdkVersion rootProject.ext.compileSdkVersion 27 | buildToolsVersion rootProject.ext.buildToolsVersion 28 | } 29 | } 30 | } 31 | } 32 | 33 | allprojects { 34 | repositories { 35 | mavenLocal() 36 | maven { 37 | // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm 38 | url("$rootDir/../node_modules/react-native/android") 39 | } 40 | maven { 41 | // Android JSC is installed from npm 42 | url("$rootDir/../node_modules/jsc-android/dist") 43 | } 44 | 45 | google() 46 | jcenter() 47 | maven { url 'https://www.jitpack.io' } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /android/gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Gradle settings configured through the IDE *will override* 5 | # any settings specified in this file. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m 13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 14 | 15 | # When configured, Gradle will run in incubating parallel mode. 16 | # This option should only be used with decoupled projects. More details, visit 17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 18 | # org.gradle.parallel=true 19 | 20 | # AndroidX package structure to make it clearer which packages are bundled with the 21 | # Android operating system, and which are packaged with your app's APK 22 | # https://developer.android.com/topic/libraries/support-library/androidx-rn 23 | android.useAndroidX=true 24 | # Automatically convert third-party libraries to use AndroidX 25 | android.enableJetifier=true 26 | # Version of flipper SDK to use with React Native 27 | FLIPPER_VERSION=0.54.0 -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MOVACT/voteswiper-app/27acbaddb5ba3655f2110ee27c07be8014d05520/android/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.2-all.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists -------------------------------------------------------------------------------- /android/settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'wahlswiper' 2 | apply from: file("../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesSettingsGradle(settings) 3 | include ':react-native-video' 4 | project(':react-native-video').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-video/android-exoplayer') 5 | 6 | include ':app' 7 | -------------------------------------------------------------------------------- /app.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "wahlswiper", 3 | "displayName": "VoteSwiper" 4 | } -------------------------------------------------------------------------------- /assets/icons/arrow-left.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/icons/arrow-right.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/icons/at.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/icons/check.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/icons/chevron-right.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/icons/circle-arrow-right.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/icons/circle-help.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/icons/circle-info.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/icons/close.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/icons/cog.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/icons/de.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/icons/download.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/icons/flags/cz.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/icons/flags/dk.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/icons/flags/ee.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/icons/flags/fi.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /assets/icons/flags/gr.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/icons/flags/hu.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/icons/flags/it.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/icons/flags/lt.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/icons/flags/nl.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/icons/flags/ro.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/icons/flags/se.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/icons/fr.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/icons/pl.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/icons/play.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/icons/share.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/icons/skip.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/icons/swiper.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: ["module:metro-react-native-babel-preset"], 3 | "plugins": [ 4 | ["@babel/plugin-proposal-decorators", { "legacy": true}] 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @format 3 | * @lint-ignore-every XPLATJSCOPYRIGHT1 4 | */ 5 | 6 | global.XMLHttpRequest = global.originalXMLHttpRequest || global.XMLHttpRequest; 7 | global.FormData = global.originalFormData || global.FormData; 8 | 9 | if (window.FETCH_SUPPORT) { 10 | window.FETCH_SUPPORT.blob = false; 11 | } else { 12 | global.Blob = global.originalBlob || global.Blob; 13 | global.FileReader = global.originalFileReader || global.FileReader; 14 | } 15 | 16 | import {AppRegistry, Platform} from 'react-native'; 17 | import App from './src/App'; 18 | import {name as appName} from './app.json'; 19 | 20 | AppRegistry.registerComponent( 21 | Platform.OS === 'ios' ? 'voteswiper' : appName, 22 | () => App, 23 | ); 24 | -------------------------------------------------------------------------------- /ios/Launch Screen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /ios/OneSignalNotificationServiceExtension/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleDisplayName 8 | OneSignalNotificationServiceExtension 9 | CFBundleExecutable 10 | $(EXECUTABLE_NAME) 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | XPC! 19 | CFBundleShortVersionString 20 | $(MARKETING_VERSION) 21 | CFBundleVersion 22 | $(CURRENT_PROJECT_VERSION) 23 | NSExtension 24 | 25 | NSExtensionPointIdentifier 26 | com.apple.usernotifications.service 27 | NSExtensionPrincipalClass 28 | NotificationService 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /ios/OneSignalNotificationServiceExtension/NotificationService.h: -------------------------------------------------------------------------------- 1 | // 2 | // NotificationService.h 3 | // OneSignalNotificationServiceExtension 4 | // 5 | // Created by Max Mitschke on 24.02.19. 6 | // Copyright © 2019 Facebook. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface NotificationService : UNNotificationServiceExtension 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /ios/OneSignalNotificationServiceExtension/NotificationService.m: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | #import "NotificationService.h" 4 | 5 | @interface NotificationService () 6 | 7 | @property (nonatomic, strong) void (^contentHandler)(UNNotificationContent *contentToDeliver); 8 | @property (nonatomic, strong) UNNotificationRequest *receivedRequest; 9 | @property (nonatomic, strong) UNMutableNotificationContent *bestAttemptContent; 10 | 11 | @end 12 | 13 | @implementation NotificationService 14 | 15 | - (void)didReceiveNotificationRequest:(UNNotificationRequest *)request withContentHandler:(void (^)(UNNotificationContent * _Nonnull))contentHandler { 16 | self.receivedRequest = request; 17 | self.contentHandler = contentHandler; 18 | self.bestAttemptContent = [request.content mutableCopy]; 19 | 20 | [OneSignal didReceiveNotificationExtensionRequest:self.receivedRequest withMutableNotificationContent:self.bestAttemptContent]; 21 | 22 | // DEBUGGING: Uncomment the 2 lines below and comment out the one above to ensure this extension is excuting 23 | // Note, this extension only runs when mutable-content is set 24 | // Setting an attachment or action buttons automatically adds this 25 | // NSLog(@"Running NotificationServiceExtension"); 26 | // self.bestAttemptContent.body = [@"[Modified] " stringByAppendingString:self.bestAttemptContent.body]; 27 | 28 | self.contentHandler(self.bestAttemptContent); 29 | } 30 | 31 | - (void)serviceExtensionTimeWillExpire { 32 | // Called just before the extension will be terminated by the system. 33 | // Use this as an opportunity to deliver your "best attempt" at modified content, otherwise the original push payload will be used. 34 | 35 | [OneSignal serviceExtensionTimeWillExpireRequest:self.receivedRequest withMutableNotificationContent:self.bestAttemptContent]; 36 | 37 | self.contentHandler(self.bestAttemptContent); 38 | } 39 | 40 | @end 41 | -------------------------------------------------------------------------------- /ios/OneSignalNotificationServiceExtension/OneSignalNotificationServiceExtension.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.application-groups 6 | 7 | group.de.movact.wahlswiper.onesignal 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /ios/Podfile: -------------------------------------------------------------------------------- 1 | require_relative '../node_modules/react-native/scripts/react_native_pods' 2 | require_relative '../node_modules/@react-native-community/cli-platform-ios/native_modules' 3 | pod 'OpenSSL-Universal', '~>1.0.2.20' 4 | platform :ios, '10.0' 5 | 6 | target 'voteswiper' do 7 | config = use_native_modules! 8 | 9 | use_react_native!(:path => config["reactNativePath"]) 10 | 11 | target 'voteswiperTests' do 12 | inherit! :complete 13 | # Pods for testing 14 | end 15 | 16 | # Enables Flipper. 17 | # 18 | # Note that if you have use_frameworks! enabled, Flipper will not work and 19 | # you should disable these next few lines. 20 | # use_flipper!({ 'Flipper-Folly' => '2.5.3', 'Flipper' => '0.87.0', 'Flipper-RSocket' => '1.3.1' }) 21 | # post_install do |installer| 22 | # flipper_post_install(installer) 23 | # end 24 | end 25 | 26 | target 'voteswiper-tvOS' do 27 | # Pods for voteswiper-tvOS 28 | 29 | target 'voteswiper-tvOSTests' do 30 | inherit! :search_paths 31 | # Pods for testing 32 | end 33 | end 34 | 35 | target 'OneSignalNotificationServiceExtension' do 36 | pod 'OneSignal', '>= 2.9.3', '< 3.0' 37 | end -------------------------------------------------------------------------------- /ios/ar.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* 2 | Tutorial: https://hackernoon.com/localize-an-application-name-in-react-native-c36c4b2be7c3 3 | */ 4 | "CFBundleDisplayName" = "VoteSwiper"; 5 | "CFBundleName" = "VoteSwiper"; 6 | "NSPhotoLibraryAddUsageDescription" = "To save your VoteSwiper result as image."; 7 | -------------------------------------------------------------------------------- /ios/de.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | "CFBundleDisplayName" = "WahlSwiper"; 2 | "CFBundleName" = "WahlSwiper"; 3 | "NSPhotoLibraryAddUsageDescription" = "Damit du dein Ergebnis als Bild speichern kannst."; 4 | -------------------------------------------------------------------------------- /ios/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* 2 | Tutorial: https://hackernoon.com/localize-an-application-name-in-react-native-c36c4b2be7c3 3 | */ 4 | "CFBundleDisplayName" = "VoteSwiper"; 5 | "CFBundleName" = "VoteSwiper"; 6 | "NSPhotoLibraryAddUsageDescription" = "To save your VoteSwiper result as image."; 7 | -------------------------------------------------------------------------------- /ios/fa.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* 2 | Tutorial: https://hackernoon.com/localize-an-application-name-in-react-native-c36c4b2be7c3 3 | */ 4 | "CFBundleDisplayName" = "VoteSwiper"; 5 | "CFBundleName" = "VoteSwiper"; 6 | "NSPhotoLibraryAddUsageDescription" = "To save your VoteSwiper result as image."; 7 | -------------------------------------------------------------------------------- /ios/fi.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* 2 | Tutorial: https://hackernoon.com/localize-an-application-name-in-react-native-c36c4b2be7c3 3 | */ 4 | "CFBundleDisplayName" = "VoteSwiper"; 5 | "CFBundleName" = "VoteSwiper"; 6 | "NSPhotoLibraryAddUsageDescription" = "To save your VoteSwiper result as image."; 7 | -------------------------------------------------------------------------------- /ios/fr.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* 2 | Tutorial: https://hackernoon.com/localize-an-application-name-in-react-native-c36c4b2be7c3 3 | */ 4 | "CFBundleDisplayName" = "VoteSwiper"; 5 | "CFBundleName" = "VoteSwiper"; 6 | "NSPhotoLibraryAddUsageDescription" = "To save your VoteSwiper result as image."; 7 | -------------------------------------------------------------------------------- /ios/ku.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* 2 | Tutorial: https://hackernoon.com/localize-an-application-name-in-react-native-c36c4b2be7c3 3 | */ 4 | "CFBundleDisplayName" = "VoteSwiper"; 5 | "CFBundleName" = "VoteSwiper"; 6 | "NSPhotoLibraryAddUsageDescription" = "To save your VoteSwiper result as image."; 7 | -------------------------------------------------------------------------------- /ios/launch_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MOVACT/voteswiper-app/27acbaddb5ba3655f2110ee27c07be8014d05520/ios/launch_icon.png -------------------------------------------------------------------------------- /ios/launch_icon_de.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MOVACT/voteswiper-app/27acbaddb5ba3655f2110ee27c07be8014d05520/ios/launch_icon_de.png -------------------------------------------------------------------------------- /ios/launchscreen_gradient.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MOVACT/voteswiper-app/27acbaddb5ba3655f2110ee27c07be8014d05520/ios/launchscreen_gradient.jpg -------------------------------------------------------------------------------- /ios/launchscreen_icon_de.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MOVACT/voteswiper-app/27acbaddb5ba3655f2110ee27c07be8014d05520/ios/launchscreen_icon_de.png -------------------------------------------------------------------------------- /ios/ru.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* 2 | Tutorial: https://hackernoon.com/localize-an-application-name-in-react-native-c36c4b2be7c3 3 | */ 4 | "CFBundleDisplayName" = "VoteSwiper"; 5 | "CFBundleName" = "VoteSwiper"; 6 | "NSPhotoLibraryAddUsageDescription" = "To save your VoteSwiper result as image."; 7 | -------------------------------------------------------------------------------- /ios/sv.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* 2 | Tutorial: https://hackernoon.com/localize-an-application-name-in-react-native-c36c4b2be7c3 3 | */ 4 | "CFBundleDisplayName" = "VoteSwiper"; 5 | "CFBundleName" = "VoteSwiper"; 6 | "NSPhotoLibraryAddUsageDescription" = "To save your VoteSwiper result as image."; 7 | -------------------------------------------------------------------------------- /ios/test.swift: -------------------------------------------------------------------------------- 1 | // 2 | // test.swift 3 | // voteswiper 4 | // 5 | // Created by Max Mitschke on 26.02.19. 6 | // Copyright © 2019 Facebook. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | -------------------------------------------------------------------------------- /ios/tr.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* 2 | Tutorial: https://hackernoon.com/localize-an-application-name-in-react-native-c36c4b2be7c3 3 | */ 4 | "CFBundleDisplayName" = "VoteSwiper"; 5 | "CFBundleName" = "VoteSwiper"; 6 | "NSPhotoLibraryAddUsageDescription" = "To save your VoteSwiper result as image."; 7 | -------------------------------------------------------------------------------- /ios/voteswiper-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | // 2 | // Use this file to import your target's public headers that you would like to expose to Swift. 3 | // 4 | 5 | -------------------------------------------------------------------------------- /ios/voteswiper-tvOS/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | NSAppTransportSecurity 26 | 27 | NSExceptionDomains 28 | 29 | localhost 30 | 31 | NSExceptionAllowsInsecureHTTPLoads 32 | 33 | 34 | 35 | 36 | NSLocationWhenInUseUsageDescription 37 | 38 | UILaunchStoryboardName 39 | LaunchScreen 40 | UIRequiredDeviceCapabilities 41 | 42 | armv7 43 | 44 | UISupportedInterfaceOrientations 45 | 46 | UIInterfaceOrientationPortrait 47 | UIInterfaceOrientationLandscapeLeft 48 | UIInterfaceOrientationLandscapeRight 49 | 50 | UIViewControllerBasedStatusBarAppearance 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /ios/voteswiper-tvOSTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /ios/voteswiper.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ios/voteswiper.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/voteswiper.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /ios/voteswiper.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/voteswiper/AppDelegate.h: -------------------------------------------------------------------------------- 1 | 2 | #import 3 | #import 4 | 5 | @interface AppDelegate : UIResponder 6 | 7 | @property(nonatomic, strong) UIWindow *window; 8 | 9 | @end 10 | -------------------------------------------------------------------------------- /ios/voteswiper/AppDelegate.m: -------------------------------------------------------------------------------- 1 | #import "AppDelegate.h" 2 | 3 | #import 4 | #import 5 | #import 6 | 7 | #ifdef FB_SONARKIT_ENABLED 8 | #import 9 | #import 10 | #import 11 | #import 12 | #import 13 | #import 14 | static void InitializeFlipper(UIApplication *application) { 15 | FlipperClient *client = [FlipperClient sharedClient]; 16 | SKDescriptorMapper *layoutDescriptorMapper = [[SKDescriptorMapper alloc] initWithDefaults]; 17 | [client addPlugin:[[FlipperKitLayoutPlugin alloc] initWithRootNode:application withDescriptorMapper:layoutDescriptorMapper]]; 18 | [client addPlugin:[[FKUserDefaultsPlugin alloc] initWithSuiteName:nil]]; 19 | [client addPlugin:[FlipperKitReactPlugin new]]; 20 | [client addPlugin:[[FlipperKitNetworkPlugin alloc] initWithNetworkAdapter:[SKIOSNetworkAdapter new]]]; 21 | [client start]; 22 | } 23 | #endif 24 | 25 | @implementation AppDelegate 26 | 27 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 28 | { 29 | #ifdef FB_SONARKIT_ENABLED 30 | InitializeFlipper(application); 31 | #endif 32 | 33 | RCTBridge *bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:launchOptions]; 34 | RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:bridge 35 | moduleName:@"voteswiper" 36 | initialProperties:nil]; 37 | 38 | rootView.backgroundColor = [[UIColor alloc] initWithRed:117.0f/255.0f green:119.0f/255.0f blue:189.0f/255.0f alpha:1]; 39 | 40 | self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; 41 | UIViewController *rootViewController = [UIViewController new]; 42 | rootViewController.view = rootView; 43 | self.window.rootViewController = rootViewController; 44 | [self.window makeKeyAndVisible]; 45 | return YES; 46 | } 47 | 48 | - (NSURL *)sourceURLForBridge:(RCTBridge *)bridge 49 | { 50 | #if DEBUG 51 | return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index" fallbackResource:nil]; 52 | #else 53 | return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"]; 54 | #endif 55 | } 56 | 57 | @end 58 | -------------------------------------------------------------------------------- /ios/voteswiper/Images.xcassets/AppIcon.appiconset/1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MOVACT/voteswiper-app/27acbaddb5ba3655f2110ee27c07be8014d05520/ios/voteswiper/Images.xcassets/AppIcon.appiconset/1024.png -------------------------------------------------------------------------------- /ios/voteswiper/Images.xcassets/AppIcon.appiconset/20x1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MOVACT/voteswiper-app/27acbaddb5ba3655f2110ee27c07be8014d05520/ios/voteswiper/Images.xcassets/AppIcon.appiconset/20x1.png -------------------------------------------------------------------------------- /ios/voteswiper/Images.xcassets/AppIcon.appiconset/20x2-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MOVACT/voteswiper-app/27acbaddb5ba3655f2110ee27c07be8014d05520/ios/voteswiper/Images.xcassets/AppIcon.appiconset/20x2-1.png -------------------------------------------------------------------------------- /ios/voteswiper/Images.xcassets/AppIcon.appiconset/20x2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MOVACT/voteswiper-app/27acbaddb5ba3655f2110ee27c07be8014d05520/ios/voteswiper/Images.xcassets/AppIcon.appiconset/20x2.png -------------------------------------------------------------------------------- /ios/voteswiper/Images.xcassets/AppIcon.appiconset/20x3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MOVACT/voteswiper-app/27acbaddb5ba3655f2110ee27c07be8014d05520/ios/voteswiper/Images.xcassets/AppIcon.appiconset/20x3.png -------------------------------------------------------------------------------- /ios/voteswiper/Images.xcassets/AppIcon.appiconset/29x1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MOVACT/voteswiper-app/27acbaddb5ba3655f2110ee27c07be8014d05520/ios/voteswiper/Images.xcassets/AppIcon.appiconset/29x1.png -------------------------------------------------------------------------------- /ios/voteswiper/Images.xcassets/AppIcon.appiconset/29x2-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MOVACT/voteswiper-app/27acbaddb5ba3655f2110ee27c07be8014d05520/ios/voteswiper/Images.xcassets/AppIcon.appiconset/29x2-1.png -------------------------------------------------------------------------------- /ios/voteswiper/Images.xcassets/AppIcon.appiconset/29x2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MOVACT/voteswiper-app/27acbaddb5ba3655f2110ee27c07be8014d05520/ios/voteswiper/Images.xcassets/AppIcon.appiconset/29x2.png -------------------------------------------------------------------------------- /ios/voteswiper/Images.xcassets/AppIcon.appiconset/29x3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MOVACT/voteswiper-app/27acbaddb5ba3655f2110ee27c07be8014d05520/ios/voteswiper/Images.xcassets/AppIcon.appiconset/29x3.png -------------------------------------------------------------------------------- /ios/voteswiper/Images.xcassets/AppIcon.appiconset/40x1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MOVACT/voteswiper-app/27acbaddb5ba3655f2110ee27c07be8014d05520/ios/voteswiper/Images.xcassets/AppIcon.appiconset/40x1.png -------------------------------------------------------------------------------- /ios/voteswiper/Images.xcassets/AppIcon.appiconset/40x2-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MOVACT/voteswiper-app/27acbaddb5ba3655f2110ee27c07be8014d05520/ios/voteswiper/Images.xcassets/AppIcon.appiconset/40x2-1.png -------------------------------------------------------------------------------- /ios/voteswiper/Images.xcassets/AppIcon.appiconset/40x2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MOVACT/voteswiper-app/27acbaddb5ba3655f2110ee27c07be8014d05520/ios/voteswiper/Images.xcassets/AppIcon.appiconset/40x2.png -------------------------------------------------------------------------------- /ios/voteswiper/Images.xcassets/AppIcon.appiconset/40x3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MOVACT/voteswiper-app/27acbaddb5ba3655f2110ee27c07be8014d05520/ios/voteswiper/Images.xcassets/AppIcon.appiconset/40x3.png -------------------------------------------------------------------------------- /ios/voteswiper/Images.xcassets/AppIcon.appiconset/60x2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MOVACT/voteswiper-app/27acbaddb5ba3655f2110ee27c07be8014d05520/ios/voteswiper/Images.xcassets/AppIcon.appiconset/60x2.png -------------------------------------------------------------------------------- /ios/voteswiper/Images.xcassets/AppIcon.appiconset/60x3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MOVACT/voteswiper-app/27acbaddb5ba3655f2110ee27c07be8014d05520/ios/voteswiper/Images.xcassets/AppIcon.appiconset/60x3.png -------------------------------------------------------------------------------- /ios/voteswiper/Images.xcassets/AppIcon.appiconset/76x1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MOVACT/voteswiper-app/27acbaddb5ba3655f2110ee27c07be8014d05520/ios/voteswiper/Images.xcassets/AppIcon.appiconset/76x1.png -------------------------------------------------------------------------------- /ios/voteswiper/Images.xcassets/AppIcon.appiconset/76x2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MOVACT/voteswiper-app/27acbaddb5ba3655f2110ee27c07be8014d05520/ios/voteswiper/Images.xcassets/AppIcon.appiconset/76x2.png -------------------------------------------------------------------------------- /ios/voteswiper/Images.xcassets/AppIcon.appiconset/83-5x2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MOVACT/voteswiper-app/27acbaddb5ba3655f2110ee27c07be8014d05520/ios/voteswiper/Images.xcassets/AppIcon.appiconset/83-5x2.png -------------------------------------------------------------------------------- /ios/voteswiper/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "20x20", 5 | "idiom" : "iphone", 6 | "filename" : "20x2.png", 7 | "scale" : "2x" 8 | }, 9 | { 10 | "size" : "20x20", 11 | "idiom" : "iphone", 12 | "filename" : "20x3.png", 13 | "scale" : "3x" 14 | }, 15 | { 16 | "size" : "29x29", 17 | "idiom" : "iphone", 18 | "filename" : "29x2.png", 19 | "scale" : "2x" 20 | }, 21 | { 22 | "size" : "29x29", 23 | "idiom" : "iphone", 24 | "filename" : "29x3.png", 25 | "scale" : "3x" 26 | }, 27 | { 28 | "size" : "40x40", 29 | "idiom" : "iphone", 30 | "filename" : "40x2.png", 31 | "scale" : "2x" 32 | }, 33 | { 34 | "size" : "40x40", 35 | "idiom" : "iphone", 36 | "filename" : "40x3.png", 37 | "scale" : "3x" 38 | }, 39 | { 40 | "size" : "60x60", 41 | "idiom" : "iphone", 42 | "filename" : "60x2.png", 43 | "scale" : "2x" 44 | }, 45 | { 46 | "size" : "60x60", 47 | "idiom" : "iphone", 48 | "filename" : "60x3.png", 49 | "scale" : "3x" 50 | }, 51 | { 52 | "size" : "20x20", 53 | "idiom" : "ipad", 54 | "filename" : "20x1.png", 55 | "scale" : "1x" 56 | }, 57 | { 58 | "size" : "20x20", 59 | "idiom" : "ipad", 60 | "filename" : "20x2-1.png", 61 | "scale" : "2x" 62 | }, 63 | { 64 | "size" : "29x29", 65 | "idiom" : "ipad", 66 | "filename" : "29x1.png", 67 | "scale" : "1x" 68 | }, 69 | { 70 | "size" : "29x29", 71 | "idiom" : "ipad", 72 | "filename" : "29x2-1.png", 73 | "scale" : "2x" 74 | }, 75 | { 76 | "size" : "40x40", 77 | "idiom" : "ipad", 78 | "filename" : "40x1.png", 79 | "scale" : "1x" 80 | }, 81 | { 82 | "size" : "40x40", 83 | "idiom" : "ipad", 84 | "filename" : "40x2-1.png", 85 | "scale" : "2x" 86 | }, 87 | { 88 | "size" : "76x76", 89 | "idiom" : "ipad", 90 | "filename" : "76x1.png", 91 | "scale" : "1x" 92 | }, 93 | { 94 | "size" : "76x76", 95 | "idiom" : "ipad", 96 | "filename" : "76x2.png", 97 | "scale" : "2x" 98 | }, 99 | { 100 | "size" : "83.5x83.5", 101 | "idiom" : "ipad", 102 | "filename" : "83-5x2.png", 103 | "scale" : "2x" 104 | }, 105 | { 106 | "size" : "1024x1024", 107 | "idiom" : "ios-marketing", 108 | "filename" : "1024.png", 109 | "scale" : "1x" 110 | } 111 | ], 112 | "info" : { 113 | "version" : 1, 114 | "author" : "xcode" 115 | } 116 | } -------------------------------------------------------------------------------- /ios/voteswiper/Images.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /ios/voteswiper/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | VoteSwiper 9 | CFBundleExecutable 10 | $(EXECUTABLE_NAME) 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | $(MARKETING_VERSION) 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | $(CURRENT_PROJECT_VERSION) 25 | LSApplicationQueriesSchemes 26 | 27 | whatsapp 28 | mailto 29 | 30 | LSRequiresIPhoneOS 31 | 32 | NSAppTransportSecurity 33 | 34 | NSAllowsArbitraryLoads 35 | 36 | NSExceptionDomains 37 | 38 | localhost 39 | 40 | NSExceptionAllowsInsecureHTTPLoads 41 | 42 | 43 | 44 | 45 | NSLocationAlwaysAndWhenInUseUsageDescription 46 | To send you push notifications for your country based on your location 47 | NSLocationAlwaysUsageDescription 48 | To send you push notifications for your country based on your location 49 | NSLocationWhenInUseUsageDescription 50 | To send you push notifications for your country based on your location 51 | NSPhotoLibraryAddUsageDescription 52 | To save your VoteSwiper result as image. 53 | UIAppFonts 54 | 55 | Rubik-Bold.ttf 56 | Rubik-Medium.ttf 57 | Rubik-Regular.ttf 58 | Wahlswiper.ttf 59 | 60 | UIBackgroundModes 61 | 62 | remote-notification 63 | 64 | UILaunchStoryboardName 65 | Launch Screen 66 | UIRequiredDeviceCapabilities 67 | 68 | armv7 69 | 70 | UIRequiresFullScreen 71 | 72 | UISupportedInterfaceOrientations 73 | 74 | UIInterfaceOrientationPortrait 75 | 76 | UISupportedInterfaceOrientations~ipad 77 | 78 | UIInterfaceOrientationPortrait 79 | 80 | UIViewControllerBasedStatusBarAppearance 81 | 82 | 83 | 84 | -------------------------------------------------------------------------------- /ios/voteswiper/main.m: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | #import "AppDelegate.h" 4 | 5 | int main(int argc, char * argv[]) { 6 | @autoreleasepool { 7 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /ios/voteswiper/voteswiper.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | aps-environment 6 | development 7 | com.apple.security.application-groups 8 | 9 | group.de.movact.wahlswiper.onesignal 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /ios/voteswiperTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /ios/voteswiperTests/voteswiperTests.m: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) Facebook, Inc. and its affiliates. 3 | * 4 | * This source code is licensed under the MIT license found in the 5 | * LICENSE file in the root directory of this source tree. 6 | */ 7 | 8 | #import 9 | #import 10 | 11 | #import 12 | #import 13 | 14 | #define TIMEOUT_SECONDS 600 15 | #define TEXT_TO_LOOK_FOR @"Welcome to React Native!" 16 | 17 | @interface voteswiperTests : XCTestCase 18 | 19 | @end 20 | 21 | @implementation voteswiperTests 22 | 23 | - (BOOL)findSubviewInView:(UIView *)view matching:(BOOL(^)(UIView *view))test 24 | { 25 | if (test(view)) { 26 | return YES; 27 | } 28 | for (UIView *subview in [view subviews]) { 29 | if ([self findSubviewInView:subview matching:test]) { 30 | return YES; 31 | } 32 | } 33 | return NO; 34 | } 35 | 36 | - (void)testRendersWelcomeScreen 37 | { 38 | UIViewController *vc = [[[RCTSharedApplication() delegate] window] rootViewController]; 39 | NSDate *date = [NSDate dateWithTimeIntervalSinceNow:TIMEOUT_SECONDS]; 40 | BOOL foundElement = NO; 41 | 42 | __block NSString *redboxError = nil; 43 | #ifdef DEBUG 44 | RCTSetLogFunction(^(RCTLogLevel level, RCTLogSource source, NSString *fileName, NSNumber *lineNumber, NSString *message) { 45 | if (level >= RCTLogLevelError) { 46 | redboxError = message; 47 | } 48 | }); 49 | #endif 50 | 51 | while ([date timeIntervalSinceNow] > 0 && !foundElement && !redboxError) { 52 | [[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; 53 | [[NSRunLoop mainRunLoop] runMode:NSRunLoopCommonModes beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; 54 | 55 | foundElement = [self findSubviewInView:vc.view matching:^BOOL(UIView *view) { 56 | if ([view.accessibilityLabel isEqualToString:TEXT_TO_LOOK_FOR]) { 57 | return YES; 58 | } 59 | return NO; 60 | }]; 61 | } 62 | 63 | #ifdef DEBUG 64 | RCTSetLogFunction(RCTDefaultLogFunction); 65 | #endif 66 | 67 | XCTAssertNil(redboxError, @"RedBox error: %@", redboxError); 68 | XCTAssertTrue(foundElement, @"Couldn't find element with text '%@' in %d seconds", TEXT_TO_LOOK_FOR, TIMEOUT_SECONDS); 69 | } 70 | 71 | 72 | @end 73 | -------------------------------------------------------------------------------- /metro.config.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Metro configuration for React Native 3 | * https://github.com/facebook/react-native 4 | * 5 | * @format 6 | */ 7 | 8 | module.exports = { 9 | transformer: { 10 | getTransformOptions: async () => ({ 11 | transform: { 12 | experimentalImportSupport: false, 13 | inlineRequires: false, 14 | }, 15 | }), 16 | }, 17 | }; 18 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "voteswiper", 3 | "version": "0.0.1", 4 | "private": true, 5 | "scripts": { 6 | "android": "react-native run-android", 7 | "ios": "react-native run-ios", 8 | "start": "react-native start", 9 | "test": "jest", 10 | "lint": "eslint ." 11 | }, 12 | "dependencies": { 13 | "@react-native-async-storage/async-storage": "^1.13.2", 14 | "@react-native-community/blur": "^3.6.0", 15 | "@react-native-community/masked-view": "^0.1.10", 16 | "@react-navigation/bottom-tabs": "^5.11.11", 17 | "@react-navigation/native": "^5.9.4", 18 | "@react-navigation/stack": "^5.14.5", 19 | "axios": "^0.18.0", 20 | "clamp": "^1.0.1", 21 | "matomo-tracker-react-native": "^0.3.1", 22 | "moment": "^2.24.0", 23 | "react": "16.13.1", 24 | "react-native": "0.63.4", 25 | "react-native-collapsible": "^1.5.3", 26 | "react-native-deck-swiper": "https://github.com/movact/react-native-deck-swiper.git#master", 27 | "react-native-gesture-handler": "^1.9.0", 28 | "react-native-linear-gradient": "^2.5.6", 29 | "react-native-localize": "^2.1.1", 30 | "react-native-onesignal": "^3.9.3", 31 | "react-native-reanimated": "^1.13.2", 32 | "react-native-restart": "^0.0.20", 33 | "react-native-safe-area-context": "^3.1.9", 34 | "react-native-screens": "^2.16.1", 35 | "react-native-share": "^7.0.0", 36 | "react-native-svg": "^12.1.0", 37 | "react-native-video": "^5.1.0-alpha8", 38 | "storyblok-js-client": "^4.1.3", 39 | "storyblok-rich-text-react-renderer": "^2.3.1" 40 | }, 41 | "devDependencies": { 42 | "@babel/core": "^7.8.4", 43 | "@babel/plugin-proposal-class-properties": "^7.3.3", 44 | "@babel/plugin-proposal-decorators": "^7.3.0", 45 | "@babel/runtime": "^7.8.4", 46 | "@react-native-community/eslint-config": "^1.1.0", 47 | "@types/react": "^17.0.0", 48 | "@types/react-native": "^0.63.42", 49 | "@types/react-native-video": "^5.0.3", 50 | "@typescript-eslint/parser": "^4.11.0", 51 | "babel-jest": "^25.1.0", 52 | "eslint": "^6.5.1", 53 | "jest": "^25.1.0", 54 | "metro-react-native-babel-preset": "^0.59.0", 55 | "prettier-plugin-organize-imports": "^2.1.0", 56 | "react-test-renderer": "16.13.1", 57 | "typescript": "^4.1.3" 58 | }, 59 | "jest": { 60 | "preset": "react-native" 61 | }, 62 | "rnpm": { 63 | "assets": [ 64 | "./src/resources/fonts/" 65 | ] 66 | }, 67 | "resolutions": { 68 | "graceful-fs": "4.2.4" 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/App.tsx: -------------------------------------------------------------------------------- 1 | import {NavigationContainer} from '@react-navigation/native'; 2 | import Container from 'components/Container'; 3 | import AppProvider from 'contexts/app'; 4 | import SwiperProvider from 'contexts/swiper'; 5 | import React from 'react'; 6 | import {StatusBar, StyleSheet, View} from 'react-native'; 7 | import MatomoTracker, {MatomoProvider} from 'matomo-tracker-react-native'; 8 | import OneSignal from 'react-native-onesignal'; 9 | import {SafeAreaProvider} from 'react-native-safe-area-context'; 10 | import {enableScreens} from 'react-native-screens'; 11 | import Init from './Init'; 12 | 13 | enableScreens(); 14 | 15 | const styles = StyleSheet.create({ 16 | app: { 17 | flex: 1, 18 | }, 19 | }); 20 | 21 | const App: React.FC = () => { 22 | const instance = new MatomoTracker({ 23 | urlBase: 'https://t.voteswiper.org/', // required 24 | // trackerUrl: 'https://LINK.TO.DOMAIN/tracking.php', // optional, default value: `${urlBase}matomo.php` 25 | siteId: 1, // required, number matching your Matomo project 26 | // userId: 'UID76903202' // optional, default value: `undefined`. 27 | // disabled: false, // optional, default value: false. Disables all tracking operations if set to true. 28 | // log: false // optional, default value: false. Enables some logs if set to true. 29 | }); 30 | 31 | React.useEffect(() => { 32 | OneSignal.init('3cbf99cf-a3e1-4f71-917f-3ef70c0fe6df'); 33 | }, []); 34 | 35 | return ( 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | ); 53 | }; 54 | 55 | export default App; 56 | -------------------------------------------------------------------------------- /src/Init.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import Container from 'components/Container'; 3 | import SelectCountry from 'screens/SelectCountry'; 4 | import Loader from 'components/Loader'; 5 | import {useApp} from 'contexts/app'; 6 | import Navigator from './Navigator'; 7 | import {useMatomo} from 'matomo-tracker-react-native'; 8 | 9 | const Init: React.FC = () => { 10 | const {hydrated, country} = useApp(); 11 | 12 | const {trackAppStart} = useMatomo(); 13 | 14 | React.useEffect(() => { 15 | trackAppStart(); 16 | }, [trackAppStart]); 17 | 18 | if (!hydrated) { 19 | return ( 20 | 21 | 22 | 23 | ); 24 | } 25 | 26 | if (!country) { 27 | return ; 28 | } 29 | 30 | return ( 31 | 32 | 33 | 34 | ); 35 | }; 36 | 37 | export default Init; 38 | -------------------------------------------------------------------------------- /src/common/breakpoints.ts: -------------------------------------------------------------------------------- 1 | export const sm = 375; 2 | -------------------------------------------------------------------------------- /src/common/config.ts: -------------------------------------------------------------------------------- 1 | const config = { 2 | api: 'https://api.voteswiper.org/api', 3 | apiVersion: 1, 4 | fallbackLocale: 'en', 5 | locales: ['en', 'de', 'ru', 'tr', 'fr', 'fi', 'sv', 'ku', 'ar', 'fa'], 6 | rtlLocales: ['ar', 'fa'], 7 | storyblokAccessToken: 'b7BTTUOEkSa786viucYnjwtt', 8 | }; 9 | 10 | export default config; 11 | -------------------------------------------------------------------------------- /src/common/headerHeight.ts: -------------------------------------------------------------------------------- 1 | import {isIphoneX} from 'util/iPhoneXHelper'; 2 | 3 | const headerHeight = () => { 4 | // eslint-disable-next-line react-hooks/rules-of-hooks 5 | // const height = useHeaderHeight(); 6 | const height = 100; 7 | if (isIphoneX()) { 8 | return height + 30; 9 | } 10 | return height; 11 | }; 12 | 13 | export default headerHeight; 14 | -------------------------------------------------------------------------------- /src/common/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name" : "common" 3 | } -------------------------------------------------------------------------------- /src/components/Box/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import {GestureResponderEvent, View} from 'react-native'; 3 | import LinearGradient from 'react-native-linear-gradient'; 4 | import ButtonGradient from '../ButtonGradient'; 5 | import styles from './styles'; 6 | 7 | interface Props { 8 | actionText?: string; 9 | actionOnPress?: (event?: GestureResponderEvent) => void; 10 | withBorder?: boolean; 11 | topMargin?: number; 12 | } 13 | 14 | const Box: React.FC = ({ 15 | topMargin = 30, 16 | actionText, 17 | actionOnPress, 18 | withBorder = false, 19 | children, 20 | }) => { 21 | return ( 22 | 23 | 24 | 33 | {children} 34 | 35 | 36 | 37 | {actionText && actionOnPress ? ( 38 | 39 | 40 | 41 | ) : null} 42 | 43 | ); 44 | }; 45 | 46 | export default Box; 47 | -------------------------------------------------------------------------------- /src/components/Box/styles.ts: -------------------------------------------------------------------------------- 1 | import {StyleSheet, Dimensions, Platform} from 'react-native'; 2 | 3 | const borderRadius = 5; 4 | 5 | const iPhone6 = 375; 6 | const {width} = Dimensions.get('window'); 7 | 8 | let rootPadding = 20; 9 | let withActionPaddingHorizontal = 40; 10 | let withActionPaddingTop = withActionPaddingHorizontal; 11 | let withActionPaddingBottom = 60; 12 | 13 | if (width < iPhone6) { 14 | rootPadding = 15; 15 | withActionPaddingHorizontal = 20; 16 | withActionPaddingTop = withActionPaddingHorizontal; 17 | withActionPaddingBottom = 30; 18 | } 19 | 20 | export default StyleSheet.create({ 21 | shadow: { 22 | borderRadius, 23 | shadowColor: '#000', 24 | shadowOffset: {width: 0, height: 5}, 25 | shadowOpacity: 0.25, 26 | shadowRadius: 20, 27 | elevation: 0, 28 | marginTop: 30, 29 | backgroundColor: 'transparent', 30 | }, 31 | root: { 32 | padding: rootPadding, 33 | borderRadius, 34 | }, 35 | 36 | withAction: { 37 | marginBottom: 30, 38 | paddingHorizontal: withActionPaddingHorizontal, 39 | paddingTop: withActionPaddingTop, 40 | paddingBottom: withActionPaddingBottom, 41 | }, 42 | withBorder: { 43 | borderWidth: Platform.OS === 'android' ? 0 : 4, 44 | borderColor: '#E6E90F', 45 | overflow: 'hidden', 46 | }, 47 | action: { 48 | justifyContent: 'center', 49 | alignItems: 'center', 50 | position: 'absolute', 51 | bottom: 0, 52 | left: 0, 53 | right: 0, 54 | zIndex: 2, 55 | }, 56 | }); 57 | -------------------------------------------------------------------------------- /src/components/BoxGradient/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import {View} from 'react-native'; 3 | import LinearGradient from 'react-native-linear-gradient'; 4 | import styles from './styles'; 5 | 6 | const BoxGradient: React.FC = ({children}) => { 7 | return ( 8 | 9 | 14 | {children} 15 | 16 | 17 | ); 18 | }; 19 | 20 | export default BoxGradient; 21 | -------------------------------------------------------------------------------- /src/components/BoxGradient/styles.ts: -------------------------------------------------------------------------------- 1 | import {StyleSheet, Dimensions} from 'react-native'; 2 | 3 | const borderRadius = 5; 4 | 5 | const iPhone6 = 375; 6 | const {width} = Dimensions.get('window'); 7 | 8 | let rootPadding = 20; 9 | 10 | if (width < iPhone6) { 11 | rootPadding = 15; 12 | } 13 | 14 | export default StyleSheet.create({ 15 | shadow: { 16 | borderRadius, 17 | backgroundColor: '#222043', 18 | shadowColor: '#000', 19 | shadowOffset: {width: 0, height: 5}, 20 | shadowOpacity: 0.15, 21 | shadowRadius: 20, 22 | elevation: 1, 23 | }, 24 | root: { 25 | padding: rootPadding, 26 | borderRadius, 27 | }, 28 | }); 29 | -------------------------------------------------------------------------------- /src/components/ButtonDark/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import {GestureResponderEvent, TouchableHighlight, View} from 'react-native'; 3 | import LinearGradient from 'react-native-linear-gradient'; 4 | import Txt from '../Txt'; 5 | import styles from './styles'; 6 | 7 | interface Props { 8 | text: string | React.ReactElement; 9 | icon?: string; 10 | center?: boolean; 11 | onPress: (event: GestureResponderEvent) => void; 12 | } 13 | 14 | const ButtonDark: React.FC = ({text, center = false, onPress}) => { 15 | const [active, setActive] = React.useState(false); 16 | 17 | return ( 18 | { 20 | setActive(true); 21 | }} 22 | onPressOut={() => { 23 | setActive(false); 24 | }} 25 | onPress={onPress} 26 | underlayColor="rgba(0,0,0,0)" 27 | tvParallaxProperties={{ 28 | shiftDistanceX: 0, 29 | shiftDistanceY: 5, 30 | tiltAngle: 0.0, 31 | magnification: 1.05, 32 | pressMagnification: 0.95, 33 | }}> 34 | 35 | 41 | 42 | {center === true ? ( 43 | 44 | 45 | {text} 46 | 47 | 48 | ) : ( 49 | 50 | {text} 51 | 52 | )} 53 | 54 | 55 | 56 | ); 57 | }; 58 | 59 | export default ButtonDark; 60 | -------------------------------------------------------------------------------- /src/components/ButtonDark/styles.ts: -------------------------------------------------------------------------------- 1 | import {StyleSheet, Platform} from 'react-native'; 2 | 3 | const borderRadius = 10; 4 | 5 | export default StyleSheet.create({ 6 | button: { 7 | marginTop: 10, 8 | position: 'relative', 9 | }, 10 | inner: { 11 | borderRadius, 12 | backgroundColor: 'transparent', 13 | paddingHorizontal: 20, 14 | paddingTop: Platform.isTV ? 15 : 11, 15 | paddingBottom: Platform.isTV ? 19 : 13, 16 | justifyContent: 'space-between', 17 | alignItems: 'center', 18 | flexDirection: 'row', 19 | }, 20 | text: { 21 | fontSize: Platform.isTV ? 29 : 14, 22 | color: '#fff', 23 | }, 24 | bg: { 25 | borderRadius, 26 | position: 'absolute', 27 | top: 0, 28 | left: 0, 29 | right: 0, 30 | bottom: 0, 31 | opacity: 0.4, 32 | }, 33 | bgActive: { 34 | opacity: 0.8, 35 | }, 36 | icon: { 37 | marginRight: 10, 38 | }, 39 | textWithIcon: { 40 | flex: 1, 41 | alignSelf: 'center', 42 | alignItems: 'center', 43 | justifyContent: 'center', 44 | }, 45 | }); 46 | -------------------------------------------------------------------------------- /src/components/ButtonGradient/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { 3 | GestureResponderEvent, 4 | TouchableWithoutFeedback, 5 | View, 6 | } from 'react-native'; 7 | import LinearGradient from 'react-native-linear-gradient'; 8 | import Txt from '../Txt'; 9 | import styles from './styles'; 10 | 11 | interface Props { 12 | text: string; 13 | onPress: (event: GestureResponderEvent) => void; 14 | disabled?: boolean; 15 | } 16 | 17 | const ButtonGradient: React.FC = ({text, disabled = false, onPress}) => { 18 | const [active, setActive] = React.useState(false); 19 | 20 | const color1 = React.useMemo(() => { 21 | if (disabled) { 22 | return '#49223A'; 23 | } 24 | 25 | if (active === true) { 26 | return '#8186D7'; 27 | } 28 | 29 | return '#DB67AE'; 30 | }, [active, disabled]); 31 | 32 | const color2 = React.useMemo(() => { 33 | if (disabled) { 34 | return '#2B2C47'; 35 | } 36 | 37 | return '#8186D7'; 38 | }, [disabled]); 39 | 40 | return ( 41 | { 43 | setActive(true); 44 | }} 45 | onPressOut={() => { 46 | setActive(false); 47 | }} 48 | onPress={onPress} 49 | style={styles.buttonOuter} 50 | disabled={disabled}> 51 | 52 | 58 | 59 | 60 | {text} 61 | 62 | 63 | 64 | 65 | ); 66 | }; 67 | 68 | export default ButtonGradient; 69 | -------------------------------------------------------------------------------- /src/components/ButtonGradient/styles.ts: -------------------------------------------------------------------------------- 1 | import {StyleSheet, Dimensions} from 'react-native'; 2 | 3 | const iPhone6 = 375; 4 | const {width} = Dimensions.get('window'); 5 | 6 | let innerPaddingHorizontal = 40; 7 | let innerHeight = 60; 8 | let textFontSize = 18; 9 | 10 | if (width < iPhone6) { 11 | innerPaddingHorizontal = 30; 12 | innerHeight = 50; 13 | textFontSize = 16; 14 | } 15 | 16 | const borderRadius = 15; 17 | 18 | export default StyleSheet.create({ 19 | buttonOuter: { 20 | alignSelf: 'center', 21 | }, 22 | button: { 23 | marginTop: 10, 24 | }, 25 | inner: { 26 | borderRadius, 27 | backgroundColor: 'transparent', 28 | paddingHorizontal: innerPaddingHorizontal, 29 | height: innerHeight, 30 | justifyContent: 'center', 31 | alignItems: 'center', 32 | flexDirection: 'row', 33 | }, 34 | text: { 35 | fontSize: textFontSize, 36 | color: '#fff', 37 | alignSelf: 'center', 38 | textAlign: 'center', 39 | }, 40 | bg: { 41 | borderRadius, 42 | position: 'absolute', 43 | top: 0, 44 | left: 0, 45 | right: 0, 46 | bottom: 0, 47 | opacity: 1, 48 | }, 49 | bgActive: { 50 | opacity: 1, 51 | }, 52 | }); 53 | -------------------------------------------------------------------------------- /src/components/Container/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import LinearGradient from 'react-native-linear-gradient'; 3 | import styles from './styles'; 4 | 5 | interface Props { 6 | noPadding?: boolean; 7 | } 8 | 9 | const Container: React.FC = ({noPadding = false, children}) => { 10 | return ( 11 | 16 | {children} 17 | 18 | ); 19 | }; 20 | 21 | export default Container; 22 | -------------------------------------------------------------------------------- /src/components/Container/styles.ts: -------------------------------------------------------------------------------- 1 | import {StyleSheet} from 'react-native'; 2 | 3 | export default StyleSheet.create({ 4 | root: { 5 | flex: 1, 6 | // paddingBottom: 50, 7 | }, 8 | noPadding: { 9 | paddingTop: 0, 10 | paddingBottom: 0, 11 | }, 12 | }); 13 | -------------------------------------------------------------------------------- /src/components/Countdown/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import {View} from 'react-native'; 3 | import Txt from '../Txt'; 4 | import moment from 'util/momentLocale'; 5 | import styles from './styles'; 6 | import {useApp} from 'contexts/app'; 7 | 8 | interface Props { 9 | date: string; 10 | } 11 | 12 | const calculateRemainingTime = (date: string) => { 13 | const total = 14 | Date.parse(moment(date).toDate()) - Date.parse(new Date().toISOString()); 15 | const seconds = Math.floor((total / 1000) % 60); 16 | const minutes = Math.floor((total / 1000 / 60) % 60); 17 | const hours = Math.floor((total / (1000 * 60 * 60)) % 24); 18 | const days = Math.floor(total / (1000 * 60 * 60 * 24)); 19 | 20 | return { 21 | total, 22 | days, 23 | hours, 24 | minutes, 25 | seconds, 26 | }; 27 | }; 28 | 29 | const Countdown: React.FC = ({date}) => { 30 | const interval = React.useRef(null); 31 | const {t} = useApp(); 32 | const [remainingTime, setRemainingTime] = React.useState<{ 33 | total: number; 34 | days: number; 35 | hours: number; 36 | minutes: number; 37 | seconds: number; 38 | }>(calculateRemainingTime(date)); 39 | 40 | const updateCountdown = React.useCallback(() => { 41 | setRemainingTime(calculateRemainingTime(date)); 42 | }, [date]); 43 | 44 | React.useEffect(() => { 45 | interval.current = setInterval(updateCountdown, 1000); 46 | 47 | () => { 48 | clearInterval(interval.current); 49 | }; 50 | }, [updateCountdown]); 51 | 52 | return ( 53 | 54 | {remainingTime.days > 0 ? ( 55 | 56 | 57 | {remainingTime.days} 58 | 59 | 60 | {t('countdown.days')} 61 | 62 | 63 | ) : null} 64 | 65 | 66 | 67 | {('0' + remainingTime.hours).slice(-2)} 68 | 69 | 70 | {t('countdown.hours')} 71 | 72 | 73 | 74 | 75 | 76 | {('0' + remainingTime.minutes).slice(-2)} 77 | 78 | 79 | {t('countdown.minutes')} 80 | 81 | 82 | 83 | 84 | 85 | {('0' + remainingTime.seconds).slice(-2)} 86 | 87 | 88 | {t('countdown.seconds')} 89 | 90 | 91 | 92 | ); 93 | }; 94 | 95 | export default Countdown; 96 | -------------------------------------------------------------------------------- /src/components/Countdown/styles.ts: -------------------------------------------------------------------------------- 1 | import {StyleSheet} from 'react-native'; 2 | 3 | export default StyleSheet.create({ 4 | countdown: { 5 | justifyContent: 'center', 6 | alignItems: 'flex-end', 7 | flexDirection: 'row', 8 | paddingBottom: 10, 9 | paddingTop: 10, 10 | }, 11 | column: { 12 | paddingHorizontal: 5, 13 | flexDirection: 'column', 14 | alignItems: 'center', 15 | }, 16 | number: { 17 | color: '#fff', 18 | fontSize: 24, 19 | }, 20 | label: { 21 | color: 'rgba(255, 255, 255, 0.5)', 22 | fontSize: 10, 23 | letterSpacing: 2, 24 | }, 25 | }); 26 | -------------------------------------------------------------------------------- /src/components/CountryPill/index.tsx: -------------------------------------------------------------------------------- 1 | import ArrowRightCircle from 'icons/ArrowRightCircle'; 2 | import React from 'react'; 3 | import { 4 | GestureResponderEvent, 5 | TouchableWithoutFeedback, 6 | View, 7 | } from 'react-native'; 8 | import LinearGradient from 'react-native-linear-gradient'; 9 | import getCountryFlag from 'util/getCountryFlag'; 10 | import Txt from '../Txt'; 11 | import styles from './styles'; 12 | 13 | interface Props { 14 | name: string; 15 | locale: string; 16 | onPress: (event: GestureResponderEvent) => void; 17 | } 18 | 19 | const CountryPill: React.FC = ({locale, name, onPress}) => { 20 | const [active, setActive] = React.useState(false); 21 | 22 | return ( 23 | { 26 | setActive(true); 27 | }} 28 | onPressOut={() => { 29 | setActive(false); 30 | }}> 31 | 32 | 37 | {getCountryFlag(locale)} 38 | 39 | 40 | {name} 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | ); 50 | }; 51 | 52 | export default CountryPill; 53 | -------------------------------------------------------------------------------- /src/components/CountryPill/styles.ts: -------------------------------------------------------------------------------- 1 | import {StyleSheet} from 'react-native'; 2 | 3 | const borderRadius = 11; 4 | 5 | export default StyleSheet.create({ 6 | flag: { 7 | minWidth: 55, 8 | }, 9 | shadow: { 10 | backgroundColor: '#fff', 11 | borderRadius, 12 | shadowColor: '#000', 13 | shadowOffset: {width: 0, height: 1}, 14 | shadowOpacity: 0.3, 15 | shadowRadius: 7, 16 | elevation: 2, 17 | marginTop: 15, 18 | }, 19 | root: { 20 | borderRadius, 21 | paddingRight: 15, 22 | paddingLeft: 11, 23 | paddingVertical: 10, 24 | flexDirection: 'row', 25 | alignItems: 'center', 26 | justifyContent: 'space-between', 27 | }, 28 | disabled: { 29 | opacity: 0.6, 30 | }, 31 | content: { 32 | paddingRight: 10, 33 | flex: 1, 34 | }, 35 | title: { 36 | fontSize: 16, 37 | color: '#59568B', 38 | }, 39 | subTitle: { 40 | fontSize: 14, 41 | color: '#59568B', 42 | opacity: 0.75, 43 | paddingTop: 1, 44 | }, 45 | icon: { 46 | textShadowColor: 'rgba(129, 134, 215, 0.2)', 47 | textShadowOffset: {width: 0, height: 2}, 48 | textShadowRadius: 5, 49 | }, 50 | }); 51 | -------------------------------------------------------------------------------- /src/components/ElectionPill/index.tsx: -------------------------------------------------------------------------------- 1 | import {useApp} from 'contexts/app'; 2 | import React from 'react'; 3 | import { 4 | GestureResponderEvent, 5 | Image, 6 | TouchableWithoutFeedback, 7 | View, 8 | } from 'react-native'; 9 | import LinearGradient from 'react-native-linear-gradient'; 10 | import {Election} from 'types/api'; 11 | import moment from 'util/momentLocale'; 12 | import ArrowRightCircle from '../../icons/ArrowRightCircle'; 13 | import rtl from '../../rtl'; 14 | import Txt from '../Txt'; 15 | import styles from './styles'; 16 | 17 | interface Props extends Election { 18 | onPress: (event: GestureResponderEvent) => void; 19 | } 20 | 21 | const ElectionPill: React.FC = ({ 22 | onPress, 23 | card, 24 | name, 25 | voting_day, 26 | playable, 27 | playable_date, 28 | }) => { 29 | const {t, language} = useApp(); 30 | const [clickActive, setActiveClick] = React.useState(false); 31 | 32 | moment.locale(language || 'de'); 33 | 34 | return ( 35 | { 38 | setActiveClick(true); 39 | }} 40 | onPressOut={() => { 41 | setActiveClick(false); 42 | }} 43 | disabled={!playable}> 44 | 45 | 46 | 51 | 52 | 57 | 58 | 59 | {name} 60 | 61 | 62 | {playable 63 | ? moment(voting_day).format('LL') 64 | : t('electionPill.availableFrom', [ 65 | moment(playable_date).format('LL'), 66 | ])} 67 | 68 | 69 | 70 | 76 | 77 | 78 | 79 | 80 | ); 81 | }; 82 | 83 | export default ElectionPill; 84 | -------------------------------------------------------------------------------- /src/components/ElectionPill/styles.ts: -------------------------------------------------------------------------------- 1 | import {StyleSheet} from 'react-native'; 2 | 3 | const borderRadius = 11; 4 | 5 | export default StyleSheet.create({ 6 | shadow: { 7 | backgroundColor: '#fff', 8 | borderRadius, 9 | shadowColor: '#000', 10 | shadowOffset: {width: 0, height: 1}, 11 | shadowOpacity: 0.3, 12 | shadowRadius: 7, 13 | elevation: 2, 14 | marginTop: 20, 15 | }, 16 | card: { 17 | aspectRatio: 16 / 9, 18 | }, 19 | cardHolder: { 20 | borderTopLeftRadius: borderRadius - 1, 21 | borderTopRightRadius: borderRadius - 1, 22 | overflow: 'hidden', 23 | }, 24 | root: { 25 | borderRadius, 26 | paddingHorizontal: 15, 27 | paddingVertical: 10, 28 | flexDirection: 'row', 29 | alignItems: 'center', 30 | justifyContent: 'space-between', 31 | }, 32 | disabled: { 33 | opacity: 0.6, 34 | }, 35 | content: { 36 | paddingRight: 10, 37 | flex: 1, 38 | }, 39 | title: { 40 | fontSize: 16, 41 | flexWrap: 'wrap', 42 | color: '#59568B', 43 | }, 44 | subTitle: { 45 | fontSize: 14, 46 | color: '#59568B', 47 | opacity: 0.75, 48 | paddingTop: 1, 49 | }, 50 | icon: { 51 | textShadowColor: 'rgba(129, 134, 215, 0.2)', 52 | textShadowOffset: {width: 0, height: 2}, 53 | textShadowRadius: 5, 54 | }, 55 | }); 56 | -------------------------------------------------------------------------------- /src/components/FadeIn/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import Animated, {Easing} from 'react-native-reanimated'; 3 | 4 | interface Props { 5 | delay?: number; 6 | } 7 | 8 | const FadeIn: React.FC = ({delay = 0, children}) => { 9 | const animValue = React.useRef(new Animated.Value(0)); 10 | 11 | React.useEffect(() => { 12 | setTimeout(() => { 13 | Animated.timing(animValue.current, { 14 | toValue: 1, 15 | duration: 100, 16 | easing: Easing.ease, 17 | }).start(); 18 | }, delay); 19 | }, [delay]); 20 | 21 | const scale = animValue.current.interpolate({ 22 | inputRange: [0, 1], 23 | outputRange: [0.9, 1], 24 | }); 25 | 26 | return ( 27 | 32 | {children} 33 | 34 | ); 35 | }; 36 | 37 | export default FadeIn; 38 | -------------------------------------------------------------------------------- /src/components/FullScreenVideo/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import {View, StatusBar, TouchableOpacity} from 'react-native'; 3 | import Video from 'react-native-video'; 4 | import LinearGradient from 'react-native-linear-gradient'; 5 | import Txt from '../Txt'; 6 | import {isIphoneX} from 'util/iPhoneXHelper'; 7 | import styles from './styles'; 8 | import SvgClose from '../../icons/Close'; 9 | 10 | interface Props { 11 | onClose: () => void; 12 | source: {uri?: string; headers?: {[key: string]: string}} | number; 13 | } 14 | 15 | const FullScreenVideo: React.FC = ({onClose, source}) => { 16 | const interval = React.useRef(); 17 | const player = React.useRef