├── .gitignore
├── README.md
├── hn-android-client
├── .gitignore
├── app
│ ├── .gitignore
│ ├── build.gradle
│ ├── proguard-rules.pro
│ └── src
│ │ ├── androidTest
│ │ └── java
│ │ │ └── com
│ │ │ └── prof18
│ │ │ └── hn
│ │ │ └── android
│ │ │ └── client
│ │ │ └── ExampleInstrumentedTest.kt
│ │ ├── main
│ │ ├── AndroidManifest.xml
│ │ ├── java
│ │ │ └── com
│ │ │ │ └── prof18
│ │ │ │ └── hn
│ │ │ │ └── android
│ │ │ │ └── client
│ │ │ │ ├── adapter
│ │ │ │ └── NewsAdapter.kt
│ │ │ │ ├── data
│ │ │ │ ├── HNApiService.kt
│ │ │ │ └── model
│ │ │ │ │ ├── AppState.kt
│ │ │ │ │ ├── News.kt
│ │ │ │ │ └── NewsState.kt
│ │ │ │ └── ui
│ │ │ │ ├── MainActivity.kt
│ │ │ │ └── MainViewModel.kt
│ │ └── res
│ │ │ ├── drawable-v24
│ │ │ └── ic_launcher_foreground.xml
│ │ │ ├── drawable
│ │ │ └── ic_launcher_background.xml
│ │ │ ├── layout
│ │ │ ├── activity_main.xml
│ │ │ └── item_news_card.xml
│ │ │ ├── mipmap-anydpi-v26
│ │ │ ├── ic_launcher.xml
│ │ │ └── ic_launcher_round.xml
│ │ │ ├── mipmap-hdpi
│ │ │ ├── ic_launcher.png
│ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-mdpi
│ │ │ ├── ic_launcher.png
│ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-xhdpi
│ │ │ ├── ic_launcher.png
│ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-xxhdpi
│ │ │ ├── ic_launcher.png
│ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-xxxhdpi
│ │ │ ├── ic_launcher.png
│ │ │ └── ic_launcher_round.png
│ │ │ ├── values-night
│ │ │ └── themes.xml
│ │ │ └── values
│ │ │ ├── colors.xml
│ │ │ ├── strings.xml
│ │ │ └── themes.xml
│ │ └── test
│ │ └── java
│ │ └── com
│ │ └── prof18
│ │ └── hn
│ │ └── android
│ │ └── client
│ │ └── ExampleUnitTest.kt
├── build.gradle
├── gradle.properties
├── gradle
│ └── wrapper
│ │ ├── gradle-wrapper.jar
│ │ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
└── settings.gradle
├── hn-backend
├── .gitignore
├── build.gradle.kts
├── gradle.properties
├── gradle
│ └── wrapper
│ │ ├── gradle-wrapper.jar
│ │ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── resources
│ ├── application.conf
│ └── logback.xml
├── settings.gradle.kts
├── src
│ ├── Application.kt
│ ├── NewsRepository.kt
│ └── NewsRepositoryImpl.kt
└── test
│ └── ApplicationTest.kt
├── hn-foundation
├── .gitignore
├── build.gradle.kts
├── gradle.properties
├── gradle
│ └── wrapper
│ │ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── local.properties
├── settings.gradle.kts
└── src
│ ├── androidMain
│ ├── kotlin
│ │ └── .gitkeep
│ └── resources
│ │ └── .gitkeep
│ ├── androidTest
│ ├── kotlin
│ │ └── .gitkeep
│ └── resources
│ │ └── .gitkeep
│ ├── commonMain
│ ├── kotlin
│ │ └── com
│ │ │ └── prof18
│ │ │ └── hn
│ │ │ └── dto
│ │ │ ├── BaseDTO.kt
│ │ │ ├── NewsDTO.kt
│ │ │ └── NewsListDTO.kt
│ └── resources
│ │ └── .gitkeep
│ ├── commonTest
│ ├── kotlin
│ │ └── .gitkeep
│ └── resources
│ │ └── .gitkeep
│ ├── iosMain
│ ├── kotlin
│ │ └── .gitkeep
│ └── resources
│ │ └── .gitkeep
│ ├── iosTest
│ ├── kotlin
│ │ └── .gitkeep
│ └── resources
│ │ └── .gitkeep
│ ├── jvmMain
│ ├── kotlin
│ │ └── .gitkeep
│ └── resources
│ │ └── .gitkeep
│ ├── jvmTest
│ ├── kotlin
│ │ └── .gitkeep
│ └── resources
│ │ └── .gitkeep
│ └── main
│ └── AndroidManifest.xml
├── hn-ios-client
└── HN Client
│ ├── HN Client.xcodeproj
│ ├── project.pbxproj
│ ├── project.xcworkspace
│ │ ├── contents.xcworkspacedata
│ │ ├── xcshareddata
│ │ │ └── IDEWorkspaceChecks.plist
│ │ └── xcuserdata
│ │ │ └── marco.xcuserdatad
│ │ │ └── UserInterfaceState.xcuserstate
│ └── xcuserdata
│ │ ├── marco.xcuserdatad
│ │ └── xcschemes
│ │ │ └── xcschememanagement.plist
│ │ └── marcogomiero.xcuserdatad
│ │ └── xcschemes
│ │ └── xcschememanagement.plist
│ ├── HN Client.xcworkspace
│ ├── contents.xcworkspacedata
│ ├── xcshareddata
│ │ └── IDEWorkspaceChecks.plist
│ └── xcuserdata
│ │ ├── marco.xcuserdatad
│ │ ├── UserInterfaceState.xcuserstate
│ │ └── xcdebugger
│ │ │ └── Breakpoints_v2.xcbkptlist
│ │ └── marcogomiero.xcuserdatad
│ │ └── UserInterfaceState.xcuserstate
│ ├── HN Client
│ ├── AppDelegate.swift
│ ├── Assets.xcassets
│ │ ├── AppIcon.appiconset
│ │ │ └── Contents.json
│ │ └── Contents.json
│ ├── Base.lproj
│ │ └── LaunchScreen.storyboard
│ ├── Info.plist
│ ├── Preview Content
│ │ └── Preview Assets.xcassets
│ │ │ └── Contents.json
│ ├── SceneDelegate.swift
│ ├── data
│ │ ├── CustomSerializer.swift
│ │ └── model
│ │ │ ├── AppState.swift
│ │ │ ├── News.swift
│ │ │ └── NewsState.swift
│ └── ui
│ │ ├── MainView.swift
│ │ ├── MainViewModel.swift
│ │ └── components
│ │ ├── ErrorView.swift
│ │ ├── LoadingView.swift
│ │ ├── NewsCard.swift
│ │ └── NewsList.swift
│ ├── HN ClientTests
│ ├── HN_ClientTests.swift
│ └── Info.plist
│ ├── Podfile
│ ├── Podfile.lock
│ └── Pods
│ ├── Alamofire
│ ├── LICENSE
│ ├── README.md
│ └── Source
│ │ ├── AFError.swift
│ │ ├── Alamofire.swift
│ │ ├── AlamofireExtended.swift
│ │ ├── AuthenticationInterceptor.swift
│ │ ├── CachedResponseHandler.swift
│ │ ├── Combine.swift
│ │ ├── DispatchQueue+Alamofire.swift
│ │ ├── EventMonitor.swift
│ │ ├── HTTPHeaders.swift
│ │ ├── HTTPMethod.swift
│ │ ├── MultipartFormData.swift
│ │ ├── MultipartUpload.swift
│ │ ├── NetworkReachabilityManager.swift
│ │ ├── Notifications.swift
│ │ ├── OperationQueue+Alamofire.swift
│ │ ├── ParameterEncoder.swift
│ │ ├── ParameterEncoding.swift
│ │ ├── Protected.swift
│ │ ├── RedirectHandler.swift
│ │ ├── Request.swift
│ │ ├── RequestInterceptor.swift
│ │ ├── RequestTaskMap.swift
│ │ ├── Response.swift
│ │ ├── ResponseSerialization.swift
│ │ ├── Result+Alamofire.swift
│ │ ├── RetryPolicy.swift
│ │ ├── ServerTrustEvaluation.swift
│ │ ├── Session.swift
│ │ ├── SessionDelegate.swift
│ │ ├── StringEncoding+Alamofire.swift
│ │ ├── URLConvertible+URLRequestConvertible.swift
│ │ ├── URLEncodedFormEncoder.swift
│ │ ├── URLRequest+Alamofire.swift
│ │ ├── URLSessionConfiguration+Alamofire.swift
│ │ └── Validation.swift
│ ├── HNFoundation
│ ├── HNFoundation.xcframework
│ │ ├── Info.plist
│ │ ├── ios-arm64
│ │ │ └── HNFoundation.framework
│ │ │ │ ├── HNFoundation
│ │ │ │ ├── Headers
│ │ │ │ └── HNFoundation.h
│ │ │ │ ├── Info.plist
│ │ │ │ └── Modules
│ │ │ │ └── module.modulemap
│ │ └── ios-x86_64-simulator
│ │ │ └── HNFoundation.framework
│ │ │ ├── HNFoundation
│ │ │ ├── Headers
│ │ │ └── HNFoundation.h
│ │ │ ├── Info.plist
│ │ │ └── Modules
│ │ │ └── module.modulemap
│ └── README.md
│ ├── Local Podspecs
│ └── HNFoundation.podspec.json
│ ├── Manifest.lock
│ ├── Pods.xcodeproj
│ ├── project.pbxproj
│ └── xcuserdata
│ │ └── marcogomiero.xcuserdatad
│ │ └── xcschemes
│ │ ├── Alamofire.xcscheme
│ │ ├── HNFoundation.xcscheme
│ │ ├── Pods-HN Client.xcscheme
│ │ └── xcschememanagement.plist
│ └── Target Support Files
│ ├── Alamofire
│ ├── Alamofire-Info.plist
│ ├── Alamofire-dummy.m
│ ├── Alamofire-prefix.pch
│ ├── Alamofire-umbrella.h
│ ├── Alamofire.debug.xcconfig
│ ├── Alamofire.modulemap
│ └── Alamofire.release.xcconfig
│ ├── HNFoundation
│ ├── HNFoundation-copy-dsyms-input-files.xcfilelist
│ ├── HNFoundation-copy-dsyms-output-files.xcfilelist
│ ├── HNFoundation-copy-dsyms.sh
│ ├── HNFoundation-xcframeworks-input-files.xcfilelist
│ ├── HNFoundation-xcframeworks-output-files.xcfilelist
│ ├── HNFoundation-xcframeworks.sh
│ ├── HNFoundation.debug.xcconfig
│ └── HNFoundation.release.xcconfig
│ └── Pods-HN Client
│ ├── Pods-HN Client-Info.plist
│ ├── Pods-HN Client-acknowledgements.markdown
│ ├── Pods-HN Client-acknowledgements.plist
│ ├── Pods-HN Client-dummy.m
│ ├── Pods-HN Client-frameworks-Debug-input-files.xcfilelist
│ ├── Pods-HN Client-frameworks-Debug-output-files.xcfilelist
│ ├── Pods-HN Client-frameworks-Release-input-files.xcfilelist
│ ├── Pods-HN Client-frameworks-Release-output-files.xcfilelist
│ ├── Pods-HN Client-frameworks.sh
│ ├── Pods-HN Client-umbrella.h
│ ├── Pods-HN Client.debug.xcconfig
│ ├── Pods-HN Client.modulemap
│ └── Pods-HN Client.release.xcconfig
└── utils
├── hacker_news.json
└── news-generator.py
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Shared code between Android, iOS and Backend
2 | A sample of Android app, iOs app, and backend that share some common code via Kotlin Multiplatform.
3 |
4 | There are two branches:
5 |
6 | - [main](https://github.com/prof18/shared-hn-android-ios-backend/tree/main): the iOS code is shared using an [XCFramework](https://developer.apple.com/videos/play/wwdc2019/416/)
7 | - [with-ios-fatframework](https://github.com/prof18/shared-hn-android-ios-backend/tree/with-ios-fatframework): the iOS code is shared using a FatFramework.
8 |
9 | This sample project is used as reference during my talks, to show how to introduce Kotlin Multiplatform into an existing project:
10 |
11 | - ["And that, folks, is how we shared code between Android, iOS and the Backend - droidcon EMEA"](https://speakerdeck.com/prof18/and-that-folks-is-how-we-shared-code-between-android-ios-and-the-backend-droidcon-emea) -> [with-ios-fatframework](https://github.com/prof18/shared-hn-android-ios-backend/tree/with-ios-fatframework) branch
12 | - ["And that, folks, is how we shared code between Android, iOS and the Backend - FOSDEM"](https://www.marcogomiero.com/talks/2021/shared-code-kmp-fosdem/) -> [with-ios-fatframework](https://github.com/prof18/shared-hn-android-ios-backend/tree/with-ios-fatframework) branch
13 | - ["Introducing Kotlin Multiplatform in an existing project"](https://www.marcogomiero.com/talks/2021/kmp-existing-project-droidcon-berlin.md/) -> main branch
14 |
15 |
16 | ## Repo Structure
17 |
18 | ### hn-foundation
19 |
20 | This folder contains the Kotlin Multiplatform library that it's shared between Android, iOs, and the Backend. For Android and the backend, the library is distributed using a local Maven repository. For iOs instead, the library is distributed using two CocoaPod repositories hosted on GitHub:
21 |
22 | - [hn-foundation-cocoa](https://github.com/prof18/hn-foundation-cocoa): contains the library code in a FatFramework
23 | - [hn-foundation-cocoa-xcframework](https://github.com/prof18/hn-foundation-cocoa-xcframework): contains the library code in an XCFramework
24 |
25 | #### Publish artifacts for Android and Backend
26 |
27 | ```bas
28 | ./gradlew publishToMavenLocal
29 | ```
30 |
31 | #### Publish Debug iOS Framework
32 |
33 | ```bash
34 | ./gradlew publishDevFramework
35 | ```
36 |
37 | #### Publish Release iOS Framework
38 | ```bash
39 | ./gradlew publishFramework
40 | ```
41 |
42 | N.B. if you want to publish to a different CocoaPod repo, you must have a folder organized like that (where the hn-foundation-cocoa is the repo that contains the framework):
43 |
44 | ```bash
45 | .
46 | ├── hn-foundation-cocoa
47 | └── shared-hn-android-ios-backend
48 | ├── hn-android-client
49 | ├── hn-backend
50 | ├── hn-foundation
51 | └── hn-ios-client
52 | ```
53 |
54 | If you change the location, remember to customize the path declared in the task on the build.gradle.kts file
55 |
56 | ### hn-backend
57 |
58 | The folder contains a backend written with [Ktor](https://ktor.io/). After publishing the artifacts to the local Maven repository you can start the backend on your machine.
59 |
60 | ### hn-android-client
61 |
62 | Thet folder contains the Android client. After publishing the artifacts to the local Maven repository and after starting the backend, you can try the android app. Remember to change the base address of the backend [here](https://github.com/prof18/shared-hn-android-ios-backend/blob/master/hn-android-client/app/src/main/java/com/prof18/hn/android/client/ui/MainViewModel.kt#L23)
63 |
64 | ### hn-ios-client
65 |
66 | The project contains the iOS client. You should be able to try the iOs app as is since I've published the Pods. Of course, you can create your CocoaPod repository and try yourself the publishing process. Remember to change the base address of the backend [here](https://github.com/prof18/shared-hn-android-ios-backend/blob/master/hn-ios-client/HN%20Client/HN%20Client/ui/MainViewModel.swift#L20).
67 |
--------------------------------------------------------------------------------
/hn-android-client/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | /.idea/caches
5 | /.idea/libraries
6 | /.idea/modules.xml
7 | /.idea/workspace.xml
8 | /.idea/navEditor.xml
9 | /.idea/assetWizardSettings.xml
10 | .DS_Store
11 | /build
12 | /captures
13 | .externalNativeBuild
14 | .cxx
15 | local.properties
16 | /.idea
17 |
--------------------------------------------------------------------------------
/hn-android-client/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/hn-android-client/app/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'com.android.application'
3 | id 'kotlin-android'
4 | }
5 |
6 | android {
7 | compileSdkVersion 30
8 |
9 | defaultConfig {
10 | applicationId "com.prof18.hn.android.client"
11 | minSdkVersion 23
12 | targetSdkVersion 30
13 | versionCode 1
14 | versionName "1.0"
15 |
16 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
17 | }
18 |
19 | buildTypes {
20 | release {
21 | minifyEnabled false
22 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
23 | }
24 | }
25 | }
26 |
27 | dependencies {
28 |
29 | implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
30 | implementation 'androidx.core:core-ktx:1.6.0'
31 | implementation 'androidx.appcompat:appcompat:1.3.1'
32 | implementation 'com.google.android.material:material:1.4.0'
33 | implementation 'androidx.constraintlayout:constraintlayout:2.1.0'
34 | implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.3.1"
35 | implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.3.1"
36 | implementation "androidx.activity:activity-ktx:1.3.1"
37 |
38 | implementation 'com.squareup.retrofit2:retrofit:2.9.0'
39 | implementation("com.jakewharton.retrofit:retrofit2-kotlinx-serialization-converter:0.8.0")
40 | implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.2.2")
41 |
42 | implementation "com.prof18.hn.foundation:hn-foundation-android:2.0.0"
43 |
44 | testImplementation 'junit:junit:4.13.2'
45 | androidTestImplementation 'androidx.test.ext:junit:1.1.3'
46 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
47 | }
--------------------------------------------------------------------------------
/hn-android-client/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
--------------------------------------------------------------------------------
/hn-android-client/app/src/androidTest/java/com/prof18/hn/android/client/ExampleInstrumentedTest.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.hn.android.client
2 |
3 | import androidx.test.platform.app.InstrumentationRegistry
4 | import androidx.test.ext.junit.runners.AndroidJUnit4
5 |
6 | import org.junit.Test
7 | import org.junit.runner.RunWith
8 |
9 | import org.junit.Assert.*
10 |
11 | /**
12 | * Instrumented test, which will execute on an Android device.
13 | *
14 | * See [testing documentation](http://d.android.com/tools/testing).
15 | */
16 | @RunWith(AndroidJUnit4::class)
17 | class ExampleInstrumentedTest {
18 | @Test
19 | fun useAppContext() {
20 | // Context of the app under test.
21 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext
22 | assertEquals("com.prof18.hn.android.client", appContext.packageName)
23 | }
24 | }
--------------------------------------------------------------------------------
/hn-android-client/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/hn-android-client/app/src/main/java/com/prof18/hn/android/client/adapter/NewsAdapter.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.hn.android.client.adapter
2 |
3 | import android.content.Intent
4 | import android.net.Uri
5 | import android.view.LayoutInflater
6 | import android.view.View
7 | import android.view.ViewGroup
8 | import android.widget.TextView
9 | import androidx.recyclerview.widget.RecyclerView
10 | import com.google.android.material.card.MaterialCardView
11 | import com.prof18.hn.android.client.R
12 | import com.prof18.hn.android.client.data.model.News
13 |
14 | class NewsAdapter(var items: List = listOf()) :
15 | RecyclerView.Adapter() {
16 |
17 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = ViewHolder(
18 | LayoutInflater.from(parent.context).inflate(
19 | R.layout.item_news_card,
20 | parent,
21 | false
22 | )
23 | )
24 |
25 | override fun getItemCount() = items.size
26 |
27 | override fun onBindViewHolder(holder: ViewHolder, position: Int) =
28 | holder.bind(items[position])
29 |
30 | class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
31 |
32 | private val title = itemView.findViewById(R.id.news_title)
33 | private val date = itemView.findViewById(R.id.news_date)
34 | private val card = itemView.findViewById(R.id.news_card)
35 |
36 | fun bind(item: News) {
37 | title.text = item.title
38 | date.text = item.formattedDate
39 | card.setOnClickListener {
40 | itemView.context.startActivity(
41 | Intent(
42 | Intent.ACTION_VIEW,
43 | Uri.parse(item.url)
44 | )
45 | )
46 | }
47 | }
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/hn-android-client/app/src/main/java/com/prof18/hn/android/client/data/HNApiService.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.hn.android.client.data
2 |
3 | import com.prof18.hn.dto.NewsListDTO
4 | import retrofit2.http.GET
5 |
6 | interface HNApiService {
7 |
8 | @GET("hn/topStories")
9 | suspend fun getTopStories(): NewsListDTO
10 |
11 | }
--------------------------------------------------------------------------------
/hn-android-client/app/src/main/java/com/prof18/hn/android/client/data/model/AppState.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.hn.android.client.data.model
2 |
3 | data class AppState(
4 | var newsState: NewsState
5 | )
--------------------------------------------------------------------------------
/hn-android-client/app/src/main/java/com/prof18/hn/android/client/data/model/News.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.hn.android.client.data.model
2 |
3 | data class News(
4 | val title: String,
5 | val formattedDate: String,
6 | val url: String
7 | )
--------------------------------------------------------------------------------
/hn-android-client/app/src/main/java/com/prof18/hn/android/client/data/model/NewsState.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.hn.android.client.data.model
2 |
3 | sealed class NewsState {
4 | object Loading: NewsState()
5 | class Success(val news: List): NewsState()
6 | class Error(val reason: String): NewsState()
7 | }
--------------------------------------------------------------------------------
/hn-android-client/app/src/main/java/com/prof18/hn/android/client/ui/MainActivity.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.hn.android.client.ui
2 |
3 | import androidx.appcompat.app.AppCompatActivity
4 | import android.os.Bundle
5 | import android.view.View
6 | import android.widget.Button
7 | import android.widget.ProgressBar
8 | import android.widget.TextView
9 | import androidx.activity.viewModels
10 | import androidx.lifecycle.Observer
11 | import androidx.recyclerview.widget.RecyclerView
12 | import com.prof18.hn.android.client.R
13 | import com.prof18.hn.android.client.adapter.NewsAdapter
14 | import com.prof18.hn.android.client.data.model.NewsState
15 |
16 | class MainActivity : AppCompatActivity() {
17 |
18 | private lateinit var recyclerView: RecyclerView
19 | private lateinit var progressBar: ProgressBar
20 | private lateinit var errorMessage: TextView
21 | private lateinit var errorButton: Button
22 |
23 | val viewModel: MainViewModel by viewModels()
24 |
25 | override fun onCreate(savedInstanceState: Bundle?) {
26 | super.onCreate(savedInstanceState)
27 | setContentView(R.layout.activity_main)
28 | // setSupportActionBar(findViewById(R.id.toolbar))
29 |
30 | recyclerView = findViewById(R.id.recycler_view)
31 | progressBar = findViewById(R.id.progress_bar)
32 | errorMessage = findViewById(R.id.error_message)
33 | errorButton = findViewById(R.id.error_button)
34 |
35 | val adapter = NewsAdapter()
36 | recyclerView.adapter = adapter
37 |
38 | viewModel.appState.observe(this, {
39 | it?.let { appState ->
40 |
41 | when (appState.newsState) {
42 |
43 | is NewsState.Loading -> {
44 | progressBar.visibility = View.VISIBLE
45 | recyclerView.visibility = View.GONE
46 | errorMessage.visibility = View.GONE
47 | errorButton.visibility = View.GONE
48 | }
49 |
50 | is NewsState.Error -> {
51 | val errorState = appState.newsState as NewsState.Error
52 |
53 | progressBar.visibility = View.GONE
54 | recyclerView.visibility = View.GONE
55 |
56 | errorButton.visibility = View.VISIBLE
57 | errorMessage.visibility = View.VISIBLE
58 | errorMessage.text = errorState.reason
59 | errorButton.setOnClickListener {
60 | viewModel.loadData()
61 | }
62 | }
63 |
64 | is NewsState.Success -> {
65 | val successState = appState.newsState as NewsState.Success
66 | progressBar.visibility = View.GONE
67 | errorMessage.visibility = View.GONE
68 | errorButton.visibility = View.GONE
69 |
70 | recyclerView.visibility = View.VISIBLE
71 | adapter.items = successState.news
72 | adapter.notifyDataSetChanged()
73 | }
74 | }
75 | }
76 | })
77 | viewModel.loadData()
78 | }
79 | }
--------------------------------------------------------------------------------
/hn-android-client/app/src/main/java/com/prof18/hn/android/client/ui/MainViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.hn.android.client.ui
2 |
3 | import androidx.lifecycle.LiveData
4 | import androidx.lifecycle.MutableLiveData
5 | import androidx.lifecycle.ViewModel
6 | import androidx.lifecycle.viewModelScope
7 | import com.jakewharton.retrofit2.converter.kotlinx.serialization.asConverterFactory
8 | import com.prof18.hn.android.client.data.HNApiService
9 | import com.prof18.hn.android.client.data.model.AppState
10 | import com.prof18.hn.android.client.data.model.News
11 | import com.prof18.hn.android.client.data.model.NewsState
12 | import kotlinx.coroutines.launch
13 | import kotlinx.serialization.ExperimentalSerializationApi
14 | import kotlinx.serialization.json.Json
15 | import okhttp3.MediaType
16 | import retrofit2.Retrofit
17 | import java.text.SimpleDateFormat
18 | import java.util.*
19 |
20 | @ExperimentalSerializationApi
21 | class MainViewModel : ViewModel() {
22 |
23 | private val apiService: HNApiService by lazy {
24 | val contentType = MediaType.get("application/json")
25 | Retrofit.Builder()
26 | .baseUrl("http://192.168.0.147:8080/")
27 | .addConverterFactory(Json.asConverterFactory(contentType))
28 | .build()
29 | .create(HNApiService::class.java)
30 | }
31 |
32 | private val _appState = MutableLiveData()
33 | val appState: LiveData
34 | get() = _appState
35 |
36 | fun loadData() {
37 | viewModelScope.launch {
38 | _appState.value = AppState(newsState = NewsState.Loading)
39 | try {
40 | val newsResponse = apiService.getTopStories()
41 | val news = newsResponse.news.map {
42 | News(
43 | title = it.title,
44 | formattedDate = getStringTime(it.timestamp),
45 | url = it.url
46 | )
47 | }
48 | _appState.value = AppState(newsState = NewsState.Success(news))
49 | } catch (e: Exception) {
50 | e.printStackTrace()
51 | _appState.value = AppState(newsState = NewsState.Error("Something wrong here :("))
52 | }
53 | }
54 | }
55 |
56 | private fun getStringTime(time: Long): String {
57 | val formatter = SimpleDateFormat("d MMM yyyy", Locale.getDefault())
58 | return formatter.format(Date(time * 1000))
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/hn-android-client/app/src/main/res/drawable-v24/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
15 |
18 |
21 |
22 |
23 |
24 |
30 |
--------------------------------------------------------------------------------
/hn-android-client/app/src/main/res/drawable/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
10 |
15 |
20 |
25 |
30 |
35 |
40 |
45 |
50 |
55 |
60 |
65 |
70 |
75 |
80 |
85 |
90 |
95 |
100 |
105 |
110 |
115 |
120 |
125 |
130 |
135 |
140 |
145 |
150 |
155 |
160 |
165 |
170 |
171 |
--------------------------------------------------------------------------------
/hn-android-client/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
18 |
19 |
28 |
29 |
35 |
36 |
46 |
47 |
62 |
63 |
--------------------------------------------------------------------------------
/hn-android-client/app/src/main/res/layout/item_news_card.xml:
--------------------------------------------------------------------------------
1 |
2 |
12 |
13 |
16 |
17 |
30 |
31 |
46 |
47 |
48 |
49 |
--------------------------------------------------------------------------------
/hn-android-client/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/hn-android-client/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/hn-android-client/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/prof18/shared-hn-android-ios-backend/271a86050cbce6021fc8caeb7ebc6f80319105d9/hn-android-client/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/hn-android-client/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/prof18/shared-hn-android-ios-backend/271a86050cbce6021fc8caeb7ebc6f80319105d9/hn-android-client/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/hn-android-client/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/prof18/shared-hn-android-ios-backend/271a86050cbce6021fc8caeb7ebc6f80319105d9/hn-android-client/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/hn-android-client/app/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/prof18/shared-hn-android-ios-backend/271a86050cbce6021fc8caeb7ebc6f80319105d9/hn-android-client/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/hn-android-client/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/prof18/shared-hn-android-ios-backend/271a86050cbce6021fc8caeb7ebc6f80319105d9/hn-android-client/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/hn-android-client/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/prof18/shared-hn-android-ios-backend/271a86050cbce6021fc8caeb7ebc6f80319105d9/hn-android-client/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/hn-android-client/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/prof18/shared-hn-android-ios-backend/271a86050cbce6021fc8caeb7ebc6f80319105d9/hn-android-client/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/hn-android-client/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/prof18/shared-hn-android-ios-backend/271a86050cbce6021fc8caeb7ebc6f80319105d9/hn-android-client/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/hn-android-client/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/prof18/shared-hn-android-ios-backend/271a86050cbce6021fc8caeb7ebc6f80319105d9/hn-android-client/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/hn-android-client/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/prof18/shared-hn-android-ios-backend/271a86050cbce6021fc8caeb7ebc6f80319105d9/hn-android-client/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/hn-android-client/app/src/main/res/values-night/themes.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
16 |
--------------------------------------------------------------------------------
/hn-android-client/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #FFBB86FC
4 | #FF6200EE
5 | #FF3700B3
6 | #FF03DAC5
7 | #FF018786
8 | #FF000000
9 | #FFFFFFFF
10 |
--------------------------------------------------------------------------------
/hn-android-client/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | NH Client
3 |
--------------------------------------------------------------------------------
/hn-android-client/app/src/main/res/values/themes.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
16 |
--------------------------------------------------------------------------------
/hn-android-client/app/src/test/java/com/prof18/hn/android/client/ExampleUnitTest.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.hn.android.client
2 |
3 | import org.junit.Test
4 |
5 | import org.junit.Assert.*
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * See [testing documentation](http://d.android.com/tools/testing).
11 | */
12 | class ExampleUnitTest {
13 | @Test
14 | fun addition_isCorrect() {
15 | assertEquals(4, 2 + 2)
16 | }
17 | }
--------------------------------------------------------------------------------
/hn-android-client/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 | buildscript {
3 | ext.kotlin_version = "1.5.30"
4 | repositories {
5 | google()
6 | jcenter()
7 | }
8 | dependencies {
9 | classpath "com.android.tools.build:gradle:4.2.0"
10 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
11 |
12 | // NOTE: Do not place your application dependencies here; they belong
13 | // in the individual module build.gradle files
14 | }
15 | }
16 |
17 | allprojects {
18 | repositories {
19 | google()
20 | mavenLocal()
21 | jcenter()
22 | }
23 | }
24 |
25 | task clean(type: Delete) {
26 | delete rootProject.buildDir
27 | }
--------------------------------------------------------------------------------
/hn-android-client/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 | # IDE (e.g. Android Studio) users:
3 | # Gradle settings configured through the IDE *will override*
4 | # any settings specified in this file.
5 | # For more details on how to configure your build environment visit
6 | # http://www.gradle.org/docs/current/userguide/build_environment.html
7 | # Specifies the JVM arguments used for the daemon process.
8 | # The setting is particularly useful for tweaking memory settings.
9 | org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
10 | # When configured, Gradle will run in incubating parallel mode.
11 | # This option should only be used with decoupled projects. More details, visit
12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
13 | # org.gradle.parallel=true
14 | # AndroidX package structure to make it clearer which packages are bundled with the
15 | # Android operating system, and which are packaged with your app"s APK
16 | # https://developer.android.com/topic/libraries/support-library/androidx-rn
17 | android.useAndroidX=true
18 | # Automatically convert third-party libraries to use AndroidX
19 | android.enableJetifier=true
20 | # Kotlin code style for this project: "official" or "obsolete":
21 | kotlin.code.style=official
--------------------------------------------------------------------------------
/hn-android-client/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/prof18/shared-hn-android-ios-backend/271a86050cbce6021fc8caeb7ebc6f80319105d9/hn-android-client/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/hn-android-client/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Tue Sep 08 20:52:30 CEST 2020
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.1.1-bin.zip
7 |
--------------------------------------------------------------------------------
/hn-android-client/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Attempt to set APP_HOME
10 | # Resolve links: $0 may be a link
11 | PRG="$0"
12 | # Need this for relative symlinks.
13 | while [ -h "$PRG" ] ; do
14 | ls=`ls -ld "$PRG"`
15 | link=`expr "$ls" : '.*-> \(.*\)$'`
16 | if expr "$link" : '/.*' > /dev/null; then
17 | PRG="$link"
18 | else
19 | PRG=`dirname "$PRG"`"/$link"
20 | fi
21 | done
22 | SAVED="`pwd`"
23 | cd "`dirname \"$PRG\"`/" >/dev/null
24 | APP_HOME="`pwd -P`"
25 | cd "$SAVED" >/dev/null
26 |
27 | APP_NAME="Gradle"
28 | APP_BASE_NAME=`basename "$0"`
29 |
30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
31 | DEFAULT_JVM_OPTS=""
32 |
33 | # Use the maximum available, or set MAX_FD != -1 to use that value.
34 | MAX_FD="maximum"
35 |
36 | warn () {
37 | echo "$*"
38 | }
39 |
40 | die () {
41 | echo
42 | echo "$*"
43 | echo
44 | exit 1
45 | }
46 |
47 | # OS specific support (must be 'true' or 'false').
48 | cygwin=false
49 | msys=false
50 | darwin=false
51 | nonstop=false
52 | case "`uname`" in
53 | CYGWIN* )
54 | cygwin=true
55 | ;;
56 | Darwin* )
57 | darwin=true
58 | ;;
59 | MINGW* )
60 | msys=true
61 | ;;
62 | NONSTOP* )
63 | nonstop=true
64 | ;;
65 | esac
66 |
67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
68 |
69 | # Determine the Java command to use to start the JVM.
70 | if [ -n "$JAVA_HOME" ] ; then
71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
72 | # IBM's JDK on AIX uses strange locations for the executables
73 | JAVACMD="$JAVA_HOME/jre/sh/java"
74 | else
75 | JAVACMD="$JAVA_HOME/bin/java"
76 | fi
77 | if [ ! -x "$JAVACMD" ] ; then
78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
79 |
80 | Please set the JAVA_HOME variable in your environment to match the
81 | location of your Java installation."
82 | fi
83 | else
84 | JAVACMD="java"
85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
86 |
87 | Please set the JAVA_HOME variable in your environment to match the
88 | location of your Java installation."
89 | fi
90 |
91 | # Increase the maximum file descriptors if we can.
92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
93 | MAX_FD_LIMIT=`ulimit -H -n`
94 | if [ $? -eq 0 ] ; then
95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
96 | MAX_FD="$MAX_FD_LIMIT"
97 | fi
98 | ulimit -n $MAX_FD
99 | if [ $? -ne 0 ] ; then
100 | warn "Could not set maximum file descriptor limit: $MAX_FD"
101 | fi
102 | else
103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
104 | fi
105 | fi
106 |
107 | # For Darwin, add options to specify how the application appears in the dock
108 | if $darwin; then
109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
110 | fi
111 |
112 | # For Cygwin, switch paths to Windows format before running java
113 | if $cygwin ; then
114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
116 | JAVACMD=`cygpath --unix "$JAVACMD"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Escape application args
158 | save () {
159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
160 | echo " "
161 | }
162 | APP_ARGS=$(save "$@")
163 |
164 | # Collect all arguments for the java command, following the shell quoting and substitution rules
165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
166 |
167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
169 | cd "$(dirname "$0")"
170 | fi
171 |
172 | exec "$JAVACMD" "$@"
173 |
--------------------------------------------------------------------------------
/hn-android-client/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | set DIRNAME=%~dp0
12 | if "%DIRNAME%" == "" set DIRNAME=.
13 | set APP_BASE_NAME=%~n0
14 | set APP_HOME=%DIRNAME%
15 |
16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
17 | set DEFAULT_JVM_OPTS=
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windows variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 |
53 | :win9xME_args
54 | @rem Slurp the command line arguments.
55 | set CMD_LINE_ARGS=
56 | set _SKIP=2
57 |
58 | :win9xME_args_slurp
59 | if "x%~1" == "x" goto execute
60 |
61 | set CMD_LINE_ARGS=%*
62 |
63 | :execute
64 | @rem Setup the command line
65 |
66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
67 |
68 | @rem Execute Gradle
69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
70 |
71 | :end
72 | @rem End local scope for the variables with windows NT shell
73 | if "%ERRORLEVEL%"=="0" goto mainEnd
74 |
75 | :fail
76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
77 | rem the _cmd.exe /c_ return code!
78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
79 | exit /b 1
80 |
81 | :mainEnd
82 | if "%OS%"=="Windows_NT" endlocal
83 |
84 | :omega
85 |
--------------------------------------------------------------------------------
/hn-android-client/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 | rootProject.name = "NH Client"
--------------------------------------------------------------------------------
/hn-backend/.gitignore:
--------------------------------------------------------------------------------
1 | /.gradle
2 | /.idea
3 | /out
4 | /build
5 | *.iml
6 | *.ipr
7 | *.iws
8 | ### Kotlin template
9 | # Compiled class file
10 | *.class
11 |
12 | # Log file
13 | *.log
14 |
15 | # BlueJ files
16 | *.ctxt
17 |
18 | # Mobile Tools for Java (J2ME)
19 | .mtj.tmp/
20 |
21 | # Package Files #
22 | *.jar
23 | *.war
24 | *.nar
25 | *.ear
26 | *.zip
27 | *.tar.gz
28 | *.rar
29 |
30 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
31 | hs_err_pid*
32 |
33 | ### JetBrains template
34 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
35 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
36 |
37 | # User-specific stuff
38 | .idea/**/workspace.xml
39 | .idea/**/tasks.xml
40 | .idea/**/usage.statistics.xml
41 | .idea/**/dictionaries
42 | .idea/**/shelf
43 |
44 | # Generated files
45 | .idea/**/contentModel.xml
46 |
47 | # Sensitive or high-churn files
48 | .idea/**/dataSources/
49 | .idea/**/dataSources.ids
50 | .idea/**/dataSources.local.xml
51 | .idea/**/sqlDataSources.xml
52 | .idea/**/dynamic.xml
53 | .idea/**/uiDesigner.xml
54 | .idea/**/dbnavigator.xml
55 |
56 | # Gradle
57 | .idea/**/gradle.xml
58 | .idea/**/libraries
59 |
60 | # Gradle and Maven with auto-import
61 | # When using Gradle or Maven with auto-import, you should exclude module files,
62 | # since they will be recreated, and may cause churn. Uncomment if using
63 | # auto-import.
64 | # .idea/artifacts
65 | # .idea/compiler.xml
66 | # .idea/jarRepositories.xml
67 | # .idea/modules.xml
68 | # .idea/*.iml
69 | # .idea/modules
70 | # *.iml
71 | # *.ipr
72 |
73 | # CMake
74 | cmake-build-*/
75 |
76 | # Mongo Explorer plugin
77 | .idea/**/mongoSettings.xml
78 |
79 | # File-based project format
80 | *.iws
81 |
82 | # IntelliJ
83 | out/
84 |
85 | # mpeltonen/sbt-idea plugin
86 | .idea_modules/
87 |
88 | # JIRA plugin
89 | atlassian-ide-plugin.xml
90 |
91 | # Cursive Clojure plugin
92 | .idea/replstate.xml
93 |
94 | # Crashlytics plugin (for Android Studio and IntelliJ)
95 | com_crashlytics_export_strings.xml
96 | crashlytics.properties
97 | crashlytics-build.properties
98 | fabric.properties
99 |
100 | # Editor-based Rest Client
101 | .idea/httpRequests
102 |
103 | # Android studio 3.1+ serialized cache file
104 | .idea/caches/build_file_checksums.ser
105 |
106 | ### Gradle template
107 | .gradle
108 | **/build/
109 | !src/**/build/
110 |
111 | # Ignore Gradle GUI config
112 | gradle-app.setting
113 |
114 | # Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored)
115 | !gradle-wrapper.jar
116 |
117 | # Cache of project
118 | .gradletasknamecache
119 |
120 | # # Work around https://youtrack.jetbrains.com/issue/IDEA-116898
121 | # gradle/wrapper/gradle-wrapper.properties
122 |
123 |
--------------------------------------------------------------------------------
/hn-backend/build.gradle.kts:
--------------------------------------------------------------------------------
1 | import org.jetbrains.kotlin.gradle.dsl.Coroutines
2 | import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
3 |
4 | val ktor_version: String by project
5 | val kotlin_version: String by project
6 | val logback_version: String by project
7 | val kotlin_serialization_version: String by project
8 |
9 | plugins {
10 | application
11 | kotlin("jvm") version "1.5.30"
12 | }
13 |
14 | group = "com.prof18.hn.backend"
15 | version = "0.0.2"
16 |
17 | application {
18 | mainClass.set("io.ktor.server.netty.EngineMain")
19 | }
20 |
21 | repositories {
22 | mavenLocal()
23 | mavenCentral()
24 | }
25 |
26 | dependencies {
27 | implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version")
28 | implementation("io.ktor:ktor-server-netty:$ktor_version")
29 | implementation("ch.qos.logback:logback-classic:$logback_version")
30 | implementation("io.ktor:ktor-server-core:$ktor_version")
31 |
32 | implementation("io.ktor:ktor-serialization:$ktor_version")
33 | implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:$kotlin_serialization_version")
34 |
35 | implementation("com.prof18.hn.foundation:hn-foundation-jvm:2.0.0")
36 |
37 | testImplementation("io.ktor:ktor-server-tests:$ktor_version")
38 |
39 |
40 |
41 | }
42 |
43 | kotlin.sourceSets["main"].kotlin.srcDirs("src")
44 | kotlin.sourceSets["test"].kotlin.srcDirs("test")
45 |
46 | sourceSets["main"].resources.srcDirs("resources")
47 | sourceSets["test"].resources.srcDirs("testresources")
48 |
--------------------------------------------------------------------------------
/hn-backend/gradle.properties:
--------------------------------------------------------------------------------
1 | ktor_version=1.6.3
2 | kotlin.code.style=official
3 | kotlin_version=1.5.30
4 | logback_version=1.2.5
5 | kotlin_serialization_version=1.2.2
6 |
--------------------------------------------------------------------------------
/hn-backend/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/prof18/shared-hn-android-ios-backend/271a86050cbce6021fc8caeb7ebc6f80319105d9/hn-backend/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/hn-backend/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.1.1-bin.zip
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 |
--------------------------------------------------------------------------------
/hn-backend/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Attempt to set APP_HOME
10 | # Resolve links: $0 may be a link
11 | PRG="$0"
12 | # Need this for relative symlinks.
13 | while [ -h "$PRG" ] ; do
14 | ls=`ls -ld "$PRG"`
15 | link=`expr "$ls" : '.*-> \(.*\)$'`
16 | if expr "$link" : '/.*' > /dev/null; then
17 | PRG="$link"
18 | else
19 | PRG=`dirname "$PRG"`"/$link"
20 | fi
21 | done
22 | SAVED="`pwd`"
23 | cd "`dirname \"$PRG\"`/" >/dev/null
24 | APP_HOME="`pwd -P`"
25 | cd "$SAVED" >/dev/null
26 |
27 | APP_NAME="Gradle"
28 | APP_BASE_NAME=`basename "$0"`
29 |
30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
31 | DEFAULT_JVM_OPTS=""
32 |
33 | # Use the maximum available, or set MAX_FD != -1 to use that value.
34 | MAX_FD="maximum"
35 |
36 | warn () {
37 | echo "$*"
38 | }
39 |
40 | die () {
41 | echo
42 | echo "$*"
43 | echo
44 | exit 1
45 | }
46 |
47 | # OS specific support (must be 'true' or 'false').
48 | cygwin=false
49 | msys=false
50 | darwin=false
51 | nonstop=false
52 | case "`uname`" in
53 | CYGWIN* )
54 | cygwin=true
55 | ;;
56 | Darwin* )
57 | darwin=true
58 | ;;
59 | MINGW* )
60 | msys=true
61 | ;;
62 | NONSTOP* )
63 | nonstop=true
64 | ;;
65 | esac
66 |
67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
68 |
69 | # Determine the Java command to use to start the JVM.
70 | if [ -n "$JAVA_HOME" ] ; then
71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
72 | # IBM's JDK on AIX uses strange locations for the executables
73 | JAVACMD="$JAVA_HOME/jre/sh/java"
74 | else
75 | JAVACMD="$JAVA_HOME/bin/java"
76 | fi
77 | if [ ! -x "$JAVACMD" ] ; then
78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
79 |
80 | Please set the JAVA_HOME variable in your environment to match the
81 | location of your Java installation."
82 | fi
83 | else
84 | JAVACMD="java"
85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
86 |
87 | Please set the JAVA_HOME variable in your environment to match the
88 | location of your Java installation."
89 | fi
90 |
91 | # Increase the maximum file descriptors if we can.
92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
93 | MAX_FD_LIMIT=`ulimit -H -n`
94 | if [ $? -eq 0 ] ; then
95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
96 | MAX_FD="$MAX_FD_LIMIT"
97 | fi
98 | ulimit -n $MAX_FD
99 | if [ $? -ne 0 ] ; then
100 | warn "Could not set maximum file descriptor limit: $MAX_FD"
101 | fi
102 | else
103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
104 | fi
105 | fi
106 |
107 | # For Darwin, add options to specify how the application appears in the dock
108 | if $darwin; then
109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
110 | fi
111 |
112 | # For Cygwin, switch paths to Windows format before running java
113 | if $cygwin ; then
114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
116 | JAVACMD=`cygpath --unix "$JAVACMD"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Escape application args
158 | save () {
159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
160 | echo " "
161 | }
162 | APP_ARGS=$(save "$@")
163 |
164 | # Collect all arguments for the java command, following the shell quoting and substitution rules
165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
166 |
167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
169 | cd "$(dirname "$0")"
170 | fi
171 |
172 | exec "$JAVACMD" "$@"
173 |
--------------------------------------------------------------------------------
/hn-backend/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | set DIRNAME=%~dp0
12 | if "%DIRNAME%" == "" set DIRNAME=.
13 | set APP_BASE_NAME=%~n0
14 | set APP_HOME=%DIRNAME%
15 |
16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
17 | set DEFAULT_JVM_OPTS=
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windows variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 |
53 | :win9xME_args
54 | @rem Slurp the command line arguments.
55 | set CMD_LINE_ARGS=
56 | set _SKIP=2
57 |
58 | :win9xME_args_slurp
59 | if "x%~1" == "x" goto execute
60 |
61 | set CMD_LINE_ARGS=%*
62 |
63 | :execute
64 | @rem Setup the command line
65 |
66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
67 |
68 | @rem Execute Gradle
69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
70 |
71 | :end
72 | @rem End local scope for the variables with windows NT shell
73 | if "%ERRORLEVEL%"=="0" goto mainEnd
74 |
75 | :fail
76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
77 | rem the _cmd.exe /c_ return code!
78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
79 | exit /b 1
80 |
81 | :mainEnd
82 | if "%OS%"=="Windows_NT" endlocal
83 |
84 | :omega
85 |
--------------------------------------------------------------------------------
/hn-backend/resources/application.conf:
--------------------------------------------------------------------------------
1 | ktor {
2 | deployment {
3 | port = 8080
4 | port = ${?PORT}
5 | }
6 | application {
7 | modules = [ com.prof18.hn.backend.ApplicationKt.module ]
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/hn-backend/resources/logback.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | %d{YYYY-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/hn-backend/settings.gradle.kts:
--------------------------------------------------------------------------------
1 | rootProject.name = "hn-backend"
2 |
--------------------------------------------------------------------------------
/hn-backend/src/Application.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.hn.backend
2 |
3 | import io.ktor.application.*
4 | import io.ktor.response.*
5 | import io.ktor.routing.*
6 | import io.ktor.http.*
7 | import io.ktor.features.*
8 | import io.ktor.http.ContentType.Application.Json
9 | import io.ktor.serialization.*
10 | import kotlinx.serialization.json.Json
11 |
12 | fun main(args: Array): Unit = io.ktor.server.netty.EngineMain.main(args)
13 |
14 | @Suppress("unused") // Referenced in application.conf
15 | @kotlin.jvm.JvmOverloads
16 | fun Application.module(testing: Boolean = false) {
17 | install(ContentNegotiation) {
18 | json(
19 | contentType = Json,
20 | json = Json { prettyPrint = true }
21 | )
22 | }
23 |
24 | val repository = NewsRepositoryImpl()
25 |
26 | routing {
27 | get("/") {
28 | call.respondText("HELLO WORLD!", contentType = ContentType.Text.Plain)
29 | }
30 |
31 | get("/hn/topStories") {
32 | call.respond(repository.getTopStories())
33 | }
34 | }
35 | }
36 |
37 |
--------------------------------------------------------------------------------
/hn-backend/src/NewsRepository.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.hn.backend
2 |
3 | import com.prof18.hn.dto.NewsDTO
4 | import com.prof18.hn.dto.NewsListDTO
5 |
6 | interface NewsRepository {
7 | fun getTopStories(): NewsListDTO
8 | }
--------------------------------------------------------------------------------
/hn-backend/test/ApplicationTest.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.hn.backend
2 |
3 | import io.ktor.application.*
4 | import io.ktor.response.*
5 | import io.ktor.request.*
6 | import io.ktor.routing.*
7 | import io.ktor.http.*
8 | import com.fasterxml.jackson.databind.*
9 | import io.ktor.jackson.*
10 | import io.ktor.features.*
11 | import kotlin.test.*
12 | import io.ktor.server.testing.*
13 |
14 | class ApplicationTest {
15 | @Test
16 | fun testRoot() {
17 | withTestApplication({ module(testing = true) }) {
18 | handleRequest(HttpMethod.Get, "/").apply {
19 | assertEquals(HttpStatusCode.OK, response.status())
20 | assertEquals("HELLO WORLD!", response.content)
21 | }
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/hn-foundation/.gitignore:
--------------------------------------------------------------------------------
1 | # Created by .ignore support plugin (hsz.mobi)
2 | ### Kotlin template
3 | # Compiled class file
4 | *.class
5 |
6 | # Log file
7 | *.log
8 |
9 | # BlueJ files
10 | *.ctxt
11 |
12 | # Mobile Tools for Java (J2ME)
13 | .mtj.tmp/
14 |
15 | # Package Files #
16 | *.jar
17 | *.war
18 | *.nar
19 | *.ear
20 | *.zip
21 | *.tar.gz
22 | *.rar
23 |
24 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
25 | hs_err_pid*
26 |
27 | ### JetBrains template
28 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
29 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
30 |
31 | # User-specific stuff
32 | .idea/**/workspace.xml
33 | .idea/**/tasks.xml
34 | .idea/**/usage.statistics.xml
35 | .idea/**/dictionaries
36 | .idea/**/shelf
37 |
38 | # Generated files
39 | .idea/**/contentModel.xml
40 |
41 | # Sensitive or high-churn files
42 | .idea/**/dataSources/
43 | .idea/**/dataSources.ids
44 | .idea/**/dataSources.local.xml
45 | .idea/**/sqlDataSources.xml
46 | .idea/**/dynamic.xml
47 | .idea/**/uiDesigner.xml
48 | .idea/**/dbnavigator.xml
49 |
50 | # Gradle
51 | .idea/**/gradle.xml
52 | .idea/**/libraries
53 |
54 | # Gradle and Maven with auto-import
55 | # When using Gradle or Maven with auto-import, you should exclude module files,
56 | # since they will be recreated, and may cause churn. Uncomment if using
57 | # auto-import.
58 | # .idea/artifacts
59 | # .idea/compiler.xml
60 | # .idea/jarRepositories.xml
61 | # .idea/modules.xml
62 | # .idea/*.iml
63 | # .idea/modules
64 | # *.iml
65 | # *.ipr
66 |
67 | # CMake
68 | cmake-build-*/
69 |
70 | # Mongo Explorer plugin
71 | .idea/**/mongoSettings.xml
72 |
73 | # File-based project format
74 | *.iws
75 |
76 | # IntelliJ
77 | out/
78 |
79 | # mpeltonen/sbt-idea plugin
80 | .idea_modules/
81 |
82 | # JIRA plugin
83 | atlassian-ide-plugin.xml
84 |
85 | # Cursive Clojure plugin
86 | .idea/replstate.xml
87 |
88 | # Crashlytics plugin (for Android Studio and IntelliJ)
89 | com_crashlytics_export_strings.xml
90 | crashlytics.properties
91 | crashlytics-build.properties
92 | fabric.properties
93 |
94 | # Editor-based Rest Client
95 | .idea/httpRequests
96 |
97 | # Android studio 3.1+ serialized cache file
98 | .idea/caches/build_file_checksums.ser
99 |
100 | /.gradle
101 |
102 | /build
103 | /build/
104 | /.idea/
105 |
--------------------------------------------------------------------------------
/hn-foundation/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 | # IDE (e.g. Android Studio) users:
3 | # Gradle settings configured through the IDE *will override*
4 | # any settings specified in this file.
5 | # For more details on how to configure your build environment visit
6 | # http://www.gradle.org/docs/current/userguide/build_environment.html
7 | # Specifies the JVM arguments used for the daemon process.
8 | # The setting is particularly useful for tweaking memory settings.
9 | org.gradle.jvmargs=-Xmx1536m
10 | # When configured, Gradle will run in incubating parallel mode.
11 | # This option should only be used with decoupled projects. More details, visit
12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
13 | # org.gradle.parallel=true
14 | # AndroidX package structure to make it clearer which packages are bundled with the
15 | # Android operating system, and which are packaged with your app's APK
16 | # https://developer.android.com/topic/libraries/support-library/androidx-rn
17 | android.useAndroidX=true
18 | # Automatically convert third-party libraries to use AndroidX
19 | android.enableJetifier=false
20 | # Kotlin code style for this project: "official" or "obsolete":
21 | kotlin.code.style=official
22 | kotlin.mpp.enableGranularSourceSetsMetadata=true
23 | kotlin.native.enableDependencyPropagation=false
--------------------------------------------------------------------------------
/hn-foundation/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Thu Dec 12 14:16:10 EST 2019
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.1.1-bin.zip
7 |
--------------------------------------------------------------------------------
/hn-foundation/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Attempt to set APP_HOME
10 | # Resolve links: $0 may be a link
11 | PRG="$0"
12 | # Need this for relative symlinks.
13 | while [ -h "$PRG" ] ; do
14 | ls=`ls -ld "$PRG"`
15 | link=`expr "$ls" : '.*-> \(.*\)$'`
16 | if expr "$link" : '/.*' > /dev/null; then
17 | PRG="$link"
18 | else
19 | PRG=`dirname "$PRG"`"/$link"
20 | fi
21 | done
22 | SAVED="`pwd`"
23 | cd "`dirname \"$PRG\"`/" >/dev/null
24 | APP_HOME="`pwd -P`"
25 | cd "$SAVED" >/dev/null
26 |
27 | APP_NAME="Gradle"
28 | APP_BASE_NAME=`basename "$0"`
29 |
30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
31 | DEFAULT_JVM_OPTS=""
32 |
33 | # Use the maximum available, or set MAX_FD != -1 to use that value.
34 | MAX_FD="maximum"
35 |
36 | warn () {
37 | echo "$*"
38 | }
39 |
40 | die () {
41 | echo
42 | echo "$*"
43 | echo
44 | exit 1
45 | }
46 |
47 | # OS specific support (must be 'true' or 'false').
48 | cygwin=false
49 | msys=false
50 | darwin=false
51 | nonstop=false
52 | case "`uname`" in
53 | CYGWIN* )
54 | cygwin=true
55 | ;;
56 | Darwin* )
57 | darwin=true
58 | ;;
59 | MINGW* )
60 | msys=true
61 | ;;
62 | NONSTOP* )
63 | nonstop=true
64 | ;;
65 | esac
66 |
67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
68 |
69 | # Determine the Java command to use to start the JVM.
70 | if [ -n "$JAVA_HOME" ] ; then
71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
72 | # IBM's JDK on AIX uses strange locations for the executables
73 | JAVACMD="$JAVA_HOME/jre/sh/java"
74 | else
75 | JAVACMD="$JAVA_HOME/bin/java"
76 | fi
77 | if [ ! -x "$JAVACMD" ] ; then
78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
79 |
80 | Please set the JAVA_HOME variable in your environment to match the
81 | location of your Java installation."
82 | fi
83 | else
84 | JAVACMD="java"
85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
86 |
87 | Please set the JAVA_HOME variable in your environment to match the
88 | location of your Java installation."
89 | fi
90 |
91 | # Increase the maximum file descriptors if we can.
92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
93 | MAX_FD_LIMIT=`ulimit -H -n`
94 | if [ $? -eq 0 ] ; then
95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
96 | MAX_FD="$MAX_FD_LIMIT"
97 | fi
98 | ulimit -n $MAX_FD
99 | if [ $? -ne 0 ] ; then
100 | warn "Could not set maximum file descriptor limit: $MAX_FD"
101 | fi
102 | else
103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
104 | fi
105 | fi
106 |
107 | # For Darwin, add options to specify how the application appears in the dock
108 | if $darwin; then
109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
110 | fi
111 |
112 | # For Cygwin, switch paths to Windows format before running java
113 | if $cygwin ; then
114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
116 | JAVACMD=`cygpath --unix "$JAVACMD"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Escape application args
158 | save () {
159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
160 | echo " "
161 | }
162 | APP_ARGS=$(save "$@")
163 |
164 | # Collect all arguments for the java command, following the shell quoting and substitution rules
165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
166 |
167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
169 | cd "$(dirname "$0")"
170 | fi
171 |
172 | exec "$JAVACMD" "$@"
173 |
--------------------------------------------------------------------------------
/hn-foundation/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | set DIRNAME=%~dp0
12 | if "%DIRNAME%" == "" set DIRNAME=.
13 | set APP_BASE_NAME=%~n0
14 | set APP_HOME=%DIRNAME%
15 |
16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
17 | set DEFAULT_JVM_OPTS=
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windows variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 |
53 | :win9xME_args
54 | @rem Slurp the command line arguments.
55 | set CMD_LINE_ARGS=
56 | set _SKIP=2
57 |
58 | :win9xME_args_slurp
59 | if "x%~1" == "x" goto execute
60 |
61 | set CMD_LINE_ARGS=%*
62 |
63 | :execute
64 | @rem Setup the command line
65 |
66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
67 |
68 | @rem Execute Gradle
69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
70 |
71 | :end
72 | @rem End local scope for the variables with windows NT shell
73 | if "%ERRORLEVEL%"=="0" goto mainEnd
74 |
75 | :fail
76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
77 | rem the _cmd.exe /c_ return code!
78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
79 | exit /b 1
80 |
81 | :mainEnd
82 | if "%OS%"=="Windows_NT" endlocal
83 |
84 | :omega
85 |
--------------------------------------------------------------------------------
/hn-foundation/local.properties:
--------------------------------------------------------------------------------
1 | ## This file must *NOT* be checked into Version Control Systems,
2 | # as it contains information specific to your local configuration.
3 | #
4 | # Location of the SDK. This is only used by Gradle.
5 | # For customization when using a Version Control System, please read the
6 | # header note.
7 | #Sat Sep 18 14:08:54 CEST 2021
8 | sdk.dir=/Users/marcogomiero/Library/Android/sdk
9 |
--------------------------------------------------------------------------------
/hn-foundation/settings.gradle.kts:
--------------------------------------------------------------------------------
1 | pluginManagement {
2 | repositories {
3 | gradlePluginPortal()
4 | google()
5 | jcenter()
6 | mavenCentral()
7 | }
8 | resolutionStrategy {
9 | eachPlugin {
10 | if (requested.id.namespace == "com.android" || requested.id.name == "kotlin-android-extensions") {
11 | useModule("com.android.tools.build:gradle:4.2.0")
12 | }
13 | }
14 | }
15 | }
16 | rootProject.name = "hn-foundation"
17 |
18 |
--------------------------------------------------------------------------------
/hn-foundation/src/androidMain/kotlin/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/prof18/shared-hn-android-ios-backend/271a86050cbce6021fc8caeb7ebc6f80319105d9/hn-foundation/src/androidMain/kotlin/.gitkeep
--------------------------------------------------------------------------------
/hn-foundation/src/androidMain/resources/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/prof18/shared-hn-android-ios-backend/271a86050cbce6021fc8caeb7ebc6f80319105d9/hn-foundation/src/androidMain/resources/.gitkeep
--------------------------------------------------------------------------------
/hn-foundation/src/androidTest/kotlin/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/prof18/shared-hn-android-ios-backend/271a86050cbce6021fc8caeb7ebc6f80319105d9/hn-foundation/src/androidTest/kotlin/.gitkeep
--------------------------------------------------------------------------------
/hn-foundation/src/androidTest/resources/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/prof18/shared-hn-android-ios-backend/271a86050cbce6021fc8caeb7ebc6f80319105d9/hn-foundation/src/androidTest/resources/.gitkeep
--------------------------------------------------------------------------------
/hn-foundation/src/commonMain/kotlin/com/prof18/hn/dto/BaseDTO.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.hn.dto
2 |
3 | import co.touchlab.stately.freeze
4 | import kotlinx.serialization.json.Json
5 |
6 | abstract class BaseDTO {
7 |
8 | @Throws(Exception::class)
9 | abstract fun deserialize(jsonString: String): BaseDTO
10 |
11 | protected val json = Json { ignoreUnknownKeys = true }
12 |
13 | fun makeFrozen() {
14 | freeze()
15 | }
16 | }
--------------------------------------------------------------------------------
/hn-foundation/src/commonMain/kotlin/com/prof18/hn/dto/NewsDTO.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.hn.dto
2 |
3 | import kotlinx.serialization.Serializable
4 | import kotlinx.serialization.decodeFromString
5 |
6 | @Serializable
7 | data class NewsDTO(
8 | val author: String,
9 | val id: Long,
10 | val score: Int,
11 | val timestamp: Long,
12 | val title: String,
13 | val type: String,
14 | val url: String
15 | ) : BaseDTO() {
16 |
17 | override fun deserialize(jsonString: String): NewsDTO {
18 | val newsDTO: NewsDTO = json.decodeFromString(jsonString)
19 | newsDTO.makeFrozen()
20 | return newsDTO
21 | }
22 | }
--------------------------------------------------------------------------------
/hn-foundation/src/commonMain/kotlin/com/prof18/hn/dto/NewsListDTO.kt:
--------------------------------------------------------------------------------
1 | package com.prof18.hn.dto
2 |
3 | import kotlinx.serialization.Serializable
4 | import kotlinx.serialization.decodeFromString
5 |
6 | @Serializable
7 | data class NewsListDTO(
8 | val news: List
9 | ): BaseDTO() {
10 |
11 | override fun deserialize(jsonString: String): BaseDTO {
12 | val newsListDTO: NewsListDTO = json.decodeFromString(jsonString)
13 | newsListDTO.makeFrozen()
14 | return newsListDTO
15 | }
16 | }
--------------------------------------------------------------------------------
/hn-foundation/src/commonMain/resources/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/prof18/shared-hn-android-ios-backend/271a86050cbce6021fc8caeb7ebc6f80319105d9/hn-foundation/src/commonMain/resources/.gitkeep
--------------------------------------------------------------------------------
/hn-foundation/src/commonTest/kotlin/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/prof18/shared-hn-android-ios-backend/271a86050cbce6021fc8caeb7ebc6f80319105d9/hn-foundation/src/commonTest/kotlin/.gitkeep
--------------------------------------------------------------------------------
/hn-foundation/src/commonTest/resources/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/prof18/shared-hn-android-ios-backend/271a86050cbce6021fc8caeb7ebc6f80319105d9/hn-foundation/src/commonTest/resources/.gitkeep
--------------------------------------------------------------------------------
/hn-foundation/src/iosMain/kotlin/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/prof18/shared-hn-android-ios-backend/271a86050cbce6021fc8caeb7ebc6f80319105d9/hn-foundation/src/iosMain/kotlin/.gitkeep
--------------------------------------------------------------------------------
/hn-foundation/src/iosMain/resources/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/prof18/shared-hn-android-ios-backend/271a86050cbce6021fc8caeb7ebc6f80319105d9/hn-foundation/src/iosMain/resources/.gitkeep
--------------------------------------------------------------------------------
/hn-foundation/src/iosTest/kotlin/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/prof18/shared-hn-android-ios-backend/271a86050cbce6021fc8caeb7ebc6f80319105d9/hn-foundation/src/iosTest/kotlin/.gitkeep
--------------------------------------------------------------------------------
/hn-foundation/src/iosTest/resources/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/prof18/shared-hn-android-ios-backend/271a86050cbce6021fc8caeb7ebc6f80319105d9/hn-foundation/src/iosTest/resources/.gitkeep
--------------------------------------------------------------------------------
/hn-foundation/src/jvmMain/kotlin/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/prof18/shared-hn-android-ios-backend/271a86050cbce6021fc8caeb7ebc6f80319105d9/hn-foundation/src/jvmMain/kotlin/.gitkeep
--------------------------------------------------------------------------------
/hn-foundation/src/jvmMain/resources/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/prof18/shared-hn-android-ios-backend/271a86050cbce6021fc8caeb7ebc6f80319105d9/hn-foundation/src/jvmMain/resources/.gitkeep
--------------------------------------------------------------------------------
/hn-foundation/src/jvmTest/kotlin/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/prof18/shared-hn-android-ios-backend/271a86050cbce6021fc8caeb7ebc6f80319105d9/hn-foundation/src/jvmTest/kotlin/.gitkeep
--------------------------------------------------------------------------------
/hn-foundation/src/jvmTest/resources/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/prof18/shared-hn-android-ios-backend/271a86050cbce6021fc8caeb7ebc6f80319105d9/hn-foundation/src/jvmTest/resources/.gitkeep
--------------------------------------------------------------------------------
/hn-foundation/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/hn-ios-client/HN Client/HN Client.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/hn-ios-client/HN Client/HN Client.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/hn-ios-client/HN Client/HN Client.xcodeproj/project.xcworkspace/xcuserdata/marco.xcuserdatad/UserInterfaceState.xcuserstate:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/prof18/shared-hn-android-ios-backend/271a86050cbce6021fc8caeb7ebc6f80319105d9/hn-ios-client/HN Client/HN Client.xcodeproj/project.xcworkspace/xcuserdata/marco.xcuserdatad/UserInterfaceState.xcuserstate
--------------------------------------------------------------------------------
/hn-ios-client/HN Client/HN Client.xcodeproj/xcuserdata/marco.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | HN Client.xcscheme_^#shared#^_
8 |
9 | orderHint
10 | 3
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/hn-ios-client/HN Client/HN Client.xcodeproj/xcuserdata/marcogomiero.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | HN Client.xcscheme_^#shared#^_
8 |
9 | orderHint
10 | 3
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/hn-ios-client/HN Client/HN Client.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/hn-ios-client/HN Client/HN Client.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/hn-ios-client/HN Client/HN Client.xcworkspace/xcuserdata/marco.xcuserdatad/UserInterfaceState.xcuserstate:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/prof18/shared-hn-android-ios-backend/271a86050cbce6021fc8caeb7ebc6f80319105d9/hn-ios-client/HN Client/HN Client.xcworkspace/xcuserdata/marco.xcuserdatad/UserInterfaceState.xcuserstate
--------------------------------------------------------------------------------
/hn-ios-client/HN Client/HN Client.xcworkspace/xcuserdata/marco.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
--------------------------------------------------------------------------------
/hn-ios-client/HN Client/HN Client.xcworkspace/xcuserdata/marcogomiero.xcuserdatad/UserInterfaceState.xcuserstate:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/prof18/shared-hn-android-ios-backend/271a86050cbce6021fc8caeb7ebc6f80319105d9/hn-ios-client/HN Client/HN Client.xcworkspace/xcuserdata/marcogomiero.xcuserdatad/UserInterfaceState.xcuserstate
--------------------------------------------------------------------------------
/hn-ios-client/HN Client/HN Client/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // HN Client
4 | //
5 | // Created by Marco Gomiero on 08/09/2020.
6 | // Copyright © 2020 Marco Gomiero. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | @UIApplicationMain
12 | class AppDelegate: UIResponder, UIApplicationDelegate {
13 |
14 |
15 |
16 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
17 | // Override point for customization after application launch.
18 | return true
19 | }
20 |
21 | // MARK: UISceneSession Lifecycle
22 |
23 | func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
24 | // Called when a new scene session is being created.
25 | // Use this method to select a configuration to create the new scene with.
26 | return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
27 | }
28 |
29 | func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set) {
30 | // Called when the user discards a scene session.
31 | // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.
32 | // Use this method to release any resources that were specific to the discarded scenes, as they will not return.
33 | }
34 |
35 |
36 | }
37 |
38 |
--------------------------------------------------------------------------------
/hn-ios-client/HN Client/HN Client/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "scale" : "2x",
6 | "size" : "20x20"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "scale" : "3x",
11 | "size" : "20x20"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "scale" : "2x",
16 | "size" : "29x29"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "scale" : "3x",
21 | "size" : "29x29"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "scale" : "2x",
26 | "size" : "40x40"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "scale" : "3x",
31 | "size" : "40x40"
32 | },
33 | {
34 | "idiom" : "iphone",
35 | "scale" : "2x",
36 | "size" : "60x60"
37 | },
38 | {
39 | "idiom" : "iphone",
40 | "scale" : "3x",
41 | "size" : "60x60"
42 | },
43 | {
44 | "idiom" : "ipad",
45 | "scale" : "1x",
46 | "size" : "20x20"
47 | },
48 | {
49 | "idiom" : "ipad",
50 | "scale" : "2x",
51 | "size" : "20x20"
52 | },
53 | {
54 | "idiom" : "ipad",
55 | "scale" : "1x",
56 | "size" : "29x29"
57 | },
58 | {
59 | "idiom" : "ipad",
60 | "scale" : "2x",
61 | "size" : "29x29"
62 | },
63 | {
64 | "idiom" : "ipad",
65 | "scale" : "1x",
66 | "size" : "40x40"
67 | },
68 | {
69 | "idiom" : "ipad",
70 | "scale" : "2x",
71 | "size" : "40x40"
72 | },
73 | {
74 | "idiom" : "ipad",
75 | "scale" : "1x",
76 | "size" : "76x76"
77 | },
78 | {
79 | "idiom" : "ipad",
80 | "scale" : "2x",
81 | "size" : "76x76"
82 | },
83 | {
84 | "idiom" : "ipad",
85 | "scale" : "2x",
86 | "size" : "83.5x83.5"
87 | },
88 | {
89 | "idiom" : "ios-marketing",
90 | "scale" : "1x",
91 | "size" : "1024x1024"
92 | }
93 | ],
94 | "info" : {
95 | "author" : "xcode",
96 | "version" : 1
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/hn-ios-client/HN Client/HN Client/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/hn-ios-client/HN Client/HN Client/Base.lproj/LaunchScreen.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 |
--------------------------------------------------------------------------------
/hn-ios-client/HN Client/HN Client/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE)
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 | LSRequiresIPhoneOS
22 |
23 | UIApplicationSceneManifest
24 |
25 | UIApplicationSupportsMultipleScenes
26 |
27 | UISceneConfigurations
28 |
29 | UIWindowSceneSessionRoleApplication
30 |
31 |
32 | UISceneConfigurationName
33 | Default Configuration
34 | UISceneDelegateClassName
35 | $(PRODUCT_MODULE_NAME).SceneDelegate
36 |
37 |
38 |
39 |
40 | UILaunchStoryboardName
41 | LaunchScreen
42 | UIRequiredDeviceCapabilities
43 |
44 | armv7
45 |
46 | UISupportedInterfaceOrientations
47 |
48 | UIInterfaceOrientationPortrait
49 | UIInterfaceOrientationLandscapeLeft
50 | UIInterfaceOrientationLandscapeRight
51 |
52 | UISupportedInterfaceOrientations~ipad
53 |
54 | UIInterfaceOrientationPortrait
55 | UIInterfaceOrientationPortraitUpsideDown
56 | UIInterfaceOrientationLandscapeLeft
57 | UIInterfaceOrientationLandscapeRight
58 |
59 |
60 |
61 |
--------------------------------------------------------------------------------
/hn-ios-client/HN Client/HN Client/Preview Content/Preview Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/hn-ios-client/HN Client/HN Client/SceneDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SceneDelegate.swift
3 | // HN Client
4 | //
5 | // Created by Marco Gomiero on 08/09/2020.
6 | // Copyright © 2020 Marco Gomiero. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import SwiftUI
11 |
12 | class SceneDelegate: UIResponder, UIWindowSceneDelegate {
13 |
14 | var window: UIWindow?
15 |
16 |
17 | func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
18 | // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.
19 | // If using a storyboard, the `window` property will automatically be initialized and attached to the scene.
20 | // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead).
21 |
22 | // Create the SwiftUI view that provides the window contents.
23 | let contentView = MainView()
24 |
25 | // Use a UIHostingController as window root view controller.
26 | if let windowScene = scene as? UIWindowScene {
27 | let window = UIWindow(windowScene: windowScene)
28 | window.rootViewController = UIHostingController(rootView: contentView)
29 | self.window = window
30 | window.makeKeyAndVisible()
31 | }
32 | }
33 |
34 | func sceneDidDisconnect(_ scene: UIScene) {
35 | // Called as the scene is being released by the system.
36 | // This occurs shortly after the scene enters the background, or when its session is discarded.
37 | // Release any resources associated with this scene that can be re-created the next time the scene connects.
38 | // The scene may re-connect later, as its session was not neccessarily discarded (see `application:didDiscardSceneSessions` instead).
39 | }
40 |
41 | func sceneDidBecomeActive(_ scene: UIScene) {
42 | // Called when the scene has moved from an inactive state to an active state.
43 | // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive.
44 | }
45 |
46 | func sceneWillResignActive(_ scene: UIScene) {
47 | // Called when the scene will move from an active state to an inactive state.
48 | // This may occur due to temporary interruptions (ex. an incoming phone call).
49 | }
50 |
51 | func sceneWillEnterForeground(_ scene: UIScene) {
52 | // Called as the scene transitions from the background to the foreground.
53 | // Use this method to undo the changes made on entering the background.
54 | }
55 |
56 | func sceneDidEnterBackground(_ scene: UIScene) {
57 | // Called as the scene transitions from the foreground to the background.
58 | // Use this method to save data, release shared resources, and store enough scene-specific state information
59 | // to restore the scene back to its current state.
60 | }
61 |
62 |
63 | }
64 |
65 |
--------------------------------------------------------------------------------
/hn-ios-client/HN Client/HN Client/data/CustomSerializer.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CustomSerializer.swift
3 | // HN Client
4 | //
5 | // Created by Marco Gomiero on 05/01/21.
6 | // Copyright © 2021 Marco Gomiero. All rights reserved.
7 | //
8 | import Foundation
9 | import Alamofire
10 | import HNFoundation
11 |
12 | struct CustomSerializer: ResponseSerializer {
13 |
14 | func serialize(request: URLRequest?, response: HTTPURLResponse?, data: Data?, error: Error?) throws -> T {
15 |
16 | guard error == nil else { throw error! }
17 |
18 | guard let data = data, !data.isEmpty else {
19 | guard emptyResponseAllowed(forRequest: request, response: response) else {
20 | throw AFError.responseSerializationFailed(reason: .inputDataNilOrZeroLength)
21 | }
22 |
23 | guard let emptyResponseType = T.self as? EmptyResponse.Type, let emptyValue = emptyResponseType.emptyValue() as? T else {
24 | throw AFError.responseSerializationFailed(reason: .invalidEmptyResponse(type: "\(T.self)"))
25 | }
26 |
27 | return emptyValue
28 | }
29 |
30 | do {
31 | let jsonString = try StringResponseSerializer().serialize(request: request,
32 | response: response,
33 | data: data,
34 | error: error)
35 |
36 | let deserializedObject = try T().deserialize(jsonString: jsonString) as! T
37 | deserializedObject.makeFrozen()
38 | return deserializedObject
39 |
40 | } catch {
41 | throw AFError.responseSerializationFailed(reason: .decodingFailed(error: error))
42 |
43 | }
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/hn-ios-client/HN Client/HN Client/data/model/AppState.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppState.swift
3 | // HN Client
4 | //
5 | // Created by Marco Gomiero on 08/09/2020.
6 | // Copyright © 2020 Marco Gomiero. All rights reserved.
7 | //
8 |
9 | struct AppState {
10 | var newsState: NewsState?
11 | }
12 |
13 |
--------------------------------------------------------------------------------
/hn-ios-client/HN Client/HN Client/data/model/News.swift:
--------------------------------------------------------------------------------
1 | //
2 | // News.swift
3 | // HN Client
4 | //
5 | // Created by Marco Gomiero on 08/09/2020.
6 | // Copyright © 2020 Marco Gomiero. All rights reserved.
7 | //
8 |
9 | struct News: Hashable {
10 | var id: Int64
11 | let title: String
12 | let formattedDate: String
13 | let url: String
14 | }
15 |
--------------------------------------------------------------------------------
/hn-ios-client/HN Client/HN Client/data/model/NewsState.swift:
--------------------------------------------------------------------------------
1 | //
2 | // NewsState.swift
3 | // HN Client
4 | //
5 | // Created by Marco Gomiero on 08/09/2020.
6 | // Copyright © 2020 Marco Gomiero. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | protocol NewsState {}
12 |
13 | struct LoadingState: NewsState {}
14 | struct SuccessState: NewsState {
15 | let news: [News]
16 |
17 | init(news: [News]) {
18 | self.news = news
19 | }
20 | }
21 | struct ErrorState: NewsState {
22 | let reason: String
23 |
24 | init(reason: String) {
25 | self.reason = reason
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/hn-ios-client/HN Client/HN Client/ui/MainView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // MainView.swift
3 | // HN Client
4 | //
5 | // Created by Marco Gomiero on 08/09/2020.
6 | // Copyright © 2020 Marco Gomiero. All rights reserved.
7 | //
8 |
9 | import SwiftUI
10 |
11 | struct MainView: View {
12 |
13 | @ObservedObject var viewModel = MainViewModel()
14 | @State private var shouldAnimate = true
15 |
16 | init() {
17 | viewModel.loadData()
18 | }
19 |
20 | var body: some View {
21 | switch self.viewModel.appState.newsState {
22 | case _ as LoadingState:
23 | return AnyView(LoadingView(shouldAnimate: self.$shouldAnimate))
24 | case let error as ErrorState:
25 | return AnyView(ErrorView(reason: error.reason, viewModel: self.viewModel))
26 | case let success as SuccessState:
27 | return AnyView(NewsList(newsList: success.news))
28 | default:
29 | return AnyView(EmptyView())
30 | }
31 | }
32 | }
33 |
34 | struct ContentView_Previews: PreviewProvider {
35 | static var previews: some View {
36 | MainView()
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/hn-ios-client/HN Client/HN Client/ui/MainViewModel.swift:
--------------------------------------------------------------------------------
1 | //
2 | // MainViewModel.swift
3 | // HN Client
4 | //
5 | // Created by Marco Gomiero on 08/09/2020.
6 | // Copyright © 2020 Marco Gomiero. All rights reserved.
7 | //
8 |
9 | import SwiftUI
10 | import Alamofire
11 | import HNFoundation
12 |
13 | class MainViewModel: ObservableObject {
14 |
15 | @Published private(set) var appState: AppState = AppState()
16 |
17 | func loadData() {
18 | self.appState = AppState(newsState: LoadingState())
19 |
20 | AF.request("http://192.168.0.147:8080/hn/topStories")
21 | .response(responseSerializer: CustomSerializer()) { response in
22 | if let newsListDTO = response.value {
23 | DispatchQueue.main.async {
24 | let news: [News] = newsListDTO.news.compactMap {
25 |
26 | return News(id: $0.id, title: $0.title, formattedDate: self.getStringTime(time: $0.timestamp), url: $0.url)
27 | }
28 |
29 | self.appState = AppState(newsState: SuccessState(news: news))
30 | }
31 | }
32 | }
33 | }
34 |
35 | private func getStringTime(time: Int64) -> String {
36 | let d = Date(timeIntervalSince1970: TimeInterval(time))
37 | let df = DateFormatter()
38 | df.dateFormat = "d MMM yyyy"
39 | return df.string(from: d)
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/hn-ios-client/HN Client/HN Client/ui/components/ErrorView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ErrorView.swift
3 | // HN Client
4 | //
5 | // Created by Marco Gomiero on 08/09/2020.
6 | // Copyright © 2020 Marco Gomiero. All rights reserved.
7 | //
8 |
9 | import SwiftUI
10 |
11 | struct ErrorView: View {
12 |
13 | let reason: String
14 | let viewModel: MainViewModel
15 |
16 | init(reason: String, viewModel: MainViewModel) {
17 | self.reason = reason
18 | self.viewModel = viewModel
19 | }
20 |
21 | var body: some View {
22 | VStack {
23 | Text(self.reason)
24 | Spacer()
25 | .frame(height: 16)
26 | Button(action: {
27 | self.viewModel.loadData()
28 | }) {
29 | Text("Refresh")
30 | }
31 | }
32 | }
33 | }
34 |
35 | struct ErrorView_Previews: PreviewProvider {
36 | static var previews: some View {
37 | ErrorView(reason: "This is a random error", viewModel: MainViewModel())
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/hn-ios-client/HN Client/HN Client/ui/components/LoadingView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LoadingView.swift
3 | // HN Client
4 | //
5 | // Created by Marco Gomiero on 08/09/2020.
6 | // Copyright © 2020 Marco Gomiero. All rights reserved.
7 | //
8 |
9 | import SwiftUI
10 |
11 | struct LoadingView: UIViewRepresentable {
12 |
13 | @Binding var shouldAnimate: Bool
14 |
15 | func makeUIView(context: Context) -> UIActivityIndicatorView {
16 | return UIActivityIndicatorView()
17 | }
18 |
19 | func updateUIView(_ uiView: UIActivityIndicatorView,
20 | context: Context) {
21 | if self.shouldAnimate {
22 | uiView.startAnimating()
23 | } else {
24 | uiView.stopAnimating()
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/hn-ios-client/HN Client/HN Client/ui/components/NewsCard.swift:
--------------------------------------------------------------------------------
1 | //
2 | // NewsCard.swift
3 | // HN Client
4 | //
5 | // Created by Marco Gomiero on 08/09/2020.
6 | // Copyright © 2020 Marco Gomiero. All rights reserved.
7 | //
8 |
9 | import SwiftUI
10 |
11 | struct NewsCard: View {
12 | let news: News
13 |
14 | var body: some View {
15 | HStack() {
16 | VStack(alignment: .leading) {
17 | Text(self.news.title)
18 | .font(.system(size: 18))
19 | Spacer()
20 | .frame(height: 9)
21 | Text(self.news.formattedDate)
22 | .font(.system(size: 14))
23 | .italic()
24 | }
25 | .layoutPriority(100)
26 | Spacer()
27 | }
28 | .padding()
29 | .background(Color.white)
30 | .cornerRadius(15)
31 | .shadow(color: Color.black.opacity(0.2), radius: 7, x: 0, y: 2)
32 | .onTapGesture {
33 | if let url = URL(string: self.news.url), !url.absoluteString.isEmpty {
34 | UIApplication.shared.open(url, options: [:], completionHandler: nil)
35 |
36 | }
37 | }
38 | }
39 | }
40 |
41 |
42 | //struct NewsCard_Previews: PreviewProvider {
43 | // static var previews: some View {
44 | // NewsCard(news: newsList[1])
45 | // }
46 | //}
47 |
--------------------------------------------------------------------------------
/hn-ios-client/HN Client/HN Client/ui/components/NewsList.swift:
--------------------------------------------------------------------------------
1 | //
2 | // NewsList.swift
3 | // HN Client
4 | //
5 | // Created by Marco Gomiero on 08/09/2020.
6 | // Copyright © 2020 Marco Gomiero. All rights reserved.
7 | //
8 |
9 | import SwiftUI
10 |
11 | struct NewsList: View {
12 |
13 | var newsList: [News]
14 |
15 | init(newsList: [News]) {
16 | self.newsList = newsList
17 | UITableView.appearance().separatorStyle = .none
18 | }
19 |
20 | var body: some View {
21 | NavigationView {
22 | List {
23 | ForEach(self.newsList, id: \.self) { news in
24 | NewsCard(news: news)
25 | }
26 | }
27 | .navigationBarTitle(Text("Declarative iOs HN"))
28 | }
29 | }
30 | }
31 |
32 | //struct NewsList_Previews: PreviewProvider {
33 | // static var previews: some View {
34 | // NewsList(newsList: newsList)
35 | // }
36 | //}
37 |
--------------------------------------------------------------------------------
/hn-ios-client/HN Client/HN ClientTests/HN_ClientTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // HN_ClientTests.swift
3 | // HN ClientTests
4 | //
5 | // Created by Marco Gomiero on 20/09/2020.
6 | // Copyright © 2020 Marco Gomiero. All rights reserved.
7 | //
8 |
9 | import XCTest
10 | //import HNFoundation
11 |
12 | @testable import HN_Client
13 |
14 | class HN_ClientTests: XCTestCase {
15 |
16 | override func setUpWithError() throws {
17 | // Put setup code here. This method is called before the invocation of each test method in the class.
18 | }
19 |
20 | override func tearDownWithError() throws {
21 | // Put teardown code here. This method is called after the invocation of each test method in the class.
22 | }
23 |
24 | func testExample() throws {
25 | // This is an example of a functional test case.
26 | // Use XCTAssert and related functions to verify your tests produce the correct results.
27 |
28 |
29 | let news = NewsDTODecodable(author: "John", id: 13515, score: 35135, timestamp: 115135, title: "Title", type: "news", url: "www.google.com")
30 |
31 | XCTAssertEqual(news.author, "John")
32 | }
33 |
34 | func testPerformanceExample() throws {
35 | // This is an example of a performance test case.
36 | measure {
37 | // Put the code you want to measure the time of here.
38 | }
39 | }
40 |
41 | }
42 |
--------------------------------------------------------------------------------
/hn-ios-client/HN Client/HN ClientTests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE)
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 |
22 |
23 |
--------------------------------------------------------------------------------
/hn-ios-client/HN Client/Podfile:
--------------------------------------------------------------------------------
1 | # Uncomment the next line to define a global platform for your project
2 | # platform :ios, '9.0'
3 |
4 | target 'HN Client' do
5 | # Comment the next line if you don't want to use dynamic frameworks
6 | use_frameworks!
7 |
8 | # Pods for HN Client
9 |
10 | # For develop releases:
11 | # pod 'HNFoundation', :git => "git@github.com:prof18/hn-foundation-cocoa-xcframework.git", :branch => 'develop'
12 |
13 | # For stable releases
14 | pod 'HNFoundation', :git => "git@github.com:prof18/hn-foundation-cocoa-xcframework.git", :tag => '2.0.0'
15 |
16 | pod 'Alamofire', '~> 5.2'
17 |
18 |
19 | end
20 |
--------------------------------------------------------------------------------
/hn-ios-client/HN Client/Podfile.lock:
--------------------------------------------------------------------------------
1 | PODS:
2 | - Alamofire (5.4.3)
3 | - HNFoundation (2.0.0)
4 |
5 | DEPENDENCIES:
6 | - Alamofire (~> 5.2)
7 | - "HNFoundation (from `git@github.com:prof18/hn-foundation-cocoa-xcframework.git`, tag `2.0.0`)"
8 |
9 | SPEC REPOS:
10 | trunk:
11 | - Alamofire
12 |
13 | EXTERNAL SOURCES:
14 | HNFoundation:
15 | :git: "git@github.com:prof18/hn-foundation-cocoa-xcframework.git"
16 | :tag: 2.0.0
17 |
18 | CHECKOUT OPTIONS:
19 | HNFoundation:
20 | :git: "git@github.com:prof18/hn-foundation-cocoa-xcframework.git"
21 | :tag: 2.0.0
22 |
23 | SPEC CHECKSUMS:
24 | Alamofire: e447a2774a40c996748296fa2c55112fdbbc42f9
25 | HNFoundation: c299d34d38a14256b485f6b58ec13e959d5c15aa
26 |
27 | PODFILE CHECKSUM: bd24eb8eb26a44a3229799e17b478572ae76286e
28 |
29 | COCOAPODS: 1.10.2
30 |
--------------------------------------------------------------------------------
/hn-ios-client/HN Client/Pods/Alamofire/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2014-2021 Alamofire Software Foundation (http://alamofire.org/)
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy
4 | of this software and associated documentation files (the "Software"), to deal
5 | in the Software without restriction, including without limitation the rights
6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | copies of the Software, and to permit persons to whom the Software is
8 | furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in
11 | all copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19 | THE SOFTWARE.
20 |
--------------------------------------------------------------------------------
/hn-ios-client/HN Client/Pods/Alamofire/Source/Alamofire.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Alamofire.swift
3 | //
4 | // Copyright (c) 2014-2021 Alamofire Software Foundation (http://alamofire.org/)
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | // THE SOFTWARE.
23 | //
24 |
25 | /// Reference to `Session.default` for quick bootstrapping and examples.
26 | public let AF = Session.default
27 |
28 | /// Current Alamofire version. Necessary since SPM doesn't use dynamic libraries. Plus this will be more accurate.
29 | let version = "5.4.3"
30 |
--------------------------------------------------------------------------------
/hn-ios-client/HN Client/Pods/Alamofire/Source/AlamofireExtended.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AlamofireExtended.swift
3 | //
4 | // Copyright (c) 2019 Alamofire Software Foundation (http://alamofire.org/)
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | // THE SOFTWARE.
23 | //
24 |
25 | /// Type that acts as a generic extension point for all `AlamofireExtended` types.
26 | public struct AlamofireExtension {
27 | /// Stores the type or meta-type of any extended type.
28 | public private(set) var type: ExtendedType
29 |
30 | /// Create an instance from the provided value.
31 | ///
32 | /// - Parameter type: Instance being extended.
33 | public init(_ type: ExtendedType) {
34 | self.type = type
35 | }
36 | }
37 |
38 | /// Protocol describing the `af` extension points for Alamofire extended types.
39 | public protocol AlamofireExtended {
40 | /// Type being extended.
41 | associatedtype ExtendedType
42 |
43 | /// Static Alamofire extension point.
44 | static var af: AlamofireExtension.Type { get set }
45 | /// Instance Alamofire extension point.
46 | var af: AlamofireExtension { get set }
47 | }
48 |
49 | extension AlamofireExtended {
50 | /// Static Alamofire extension point.
51 | public static var af: AlamofireExtension.Type {
52 | get { AlamofireExtension.self }
53 | set {}
54 | }
55 |
56 | /// Instance Alamofire extension point.
57 | public var af: AlamofireExtension {
58 | get { AlamofireExtension(self) }
59 | set {}
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/hn-ios-client/HN Client/Pods/Alamofire/Source/CachedResponseHandler.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CachedResponseHandler.swift
3 | //
4 | // Copyright (c) 2019 Alamofire Software Foundation (http://alamofire.org/)
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | // THE SOFTWARE.
23 | //
24 |
25 | import Foundation
26 |
27 | /// A type that handles whether the data task should store the HTTP response in the cache.
28 | public protocol CachedResponseHandler {
29 | /// Determines whether the HTTP response should be stored in the cache.
30 | ///
31 | /// The `completion` closure should be passed one of three possible options:
32 | ///
33 | /// 1. The cached response provided by the server (this is the most common use case).
34 | /// 2. A modified version of the cached response (you may want to modify it in some way before caching).
35 | /// 3. A `nil` value to prevent the cached response from being stored in the cache.
36 | ///
37 | /// - Parameters:
38 | /// - task: The data task whose request resulted in the cached response.
39 | /// - response: The cached response to potentially store in the cache.
40 | /// - completion: The closure to execute containing cached response, a modified response, or `nil`.
41 | func dataTask(_ task: URLSessionDataTask,
42 | willCacheResponse response: CachedURLResponse,
43 | completion: @escaping (CachedURLResponse?) -> Void)
44 | }
45 |
46 | // MARK: -
47 |
48 | /// `ResponseCacher` is a convenience `CachedResponseHandler` making it easy to cache, not cache, or modify a cached
49 | /// response.
50 | public struct ResponseCacher {
51 | /// Defines the behavior of the `ResponseCacher` type.
52 | public enum Behavior {
53 | /// Stores the cached response in the cache.
54 | case cache
55 | /// Prevents the cached response from being stored in the cache.
56 | case doNotCache
57 | /// Modifies the cached response before storing it in the cache.
58 | case modify((URLSessionDataTask, CachedURLResponse) -> CachedURLResponse?)
59 | }
60 |
61 | /// Returns a `ResponseCacher` with a follow `Behavior`.
62 | public static let cache = ResponseCacher(behavior: .cache)
63 | /// Returns a `ResponseCacher` with a do not follow `Behavior`.
64 | public static let doNotCache = ResponseCacher(behavior: .doNotCache)
65 |
66 | /// The `Behavior` of the `ResponseCacher`.
67 | public let behavior: Behavior
68 |
69 | /// Creates a `ResponseCacher` instance from the `Behavior`.
70 | ///
71 | /// - Parameter behavior: The `Behavior`.
72 | public init(behavior: Behavior) {
73 | self.behavior = behavior
74 | }
75 | }
76 |
77 | extension ResponseCacher: CachedResponseHandler {
78 | public func dataTask(_ task: URLSessionDataTask,
79 | willCacheResponse response: CachedURLResponse,
80 | completion: @escaping (CachedURLResponse?) -> Void) {
81 | switch behavior {
82 | case .cache:
83 | completion(response)
84 | case .doNotCache:
85 | completion(nil)
86 | case let .modify(closure):
87 | let response = closure(task, response)
88 | completion(response)
89 | }
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/hn-ios-client/HN Client/Pods/Alamofire/Source/DispatchQueue+Alamofire.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DispatchQueue+Alamofire.swift
3 | //
4 | // Copyright (c) 2014-2018 Alamofire Software Foundation (http://alamofire.org/)
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | // THE SOFTWARE.
23 | //
24 |
25 | import Dispatch
26 | import Foundation
27 |
28 | extension DispatchQueue {
29 | /// Execute the provided closure after a `TimeInterval`.
30 | ///
31 | /// - Parameters:
32 | /// - delay: `TimeInterval` to delay execution.
33 | /// - closure: Closure to execute.
34 | func after(_ delay: TimeInterval, execute closure: @escaping () -> Void) {
35 | asyncAfter(deadline: .now() + delay, execute: closure)
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/hn-ios-client/HN Client/Pods/Alamofire/Source/HTTPMethod.swift:
--------------------------------------------------------------------------------
1 | //
2 | // HTTPMethod.swift
3 | //
4 | // Copyright (c) 2014-2018 Alamofire Software Foundation (http://alamofire.org/)
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | // THE SOFTWARE.
23 | //
24 |
25 | /// Type representing HTTP methods. Raw `String` value is stored and compared case-sensitively, so
26 | /// `HTTPMethod.get != HTTPMethod(rawValue: "get")`.
27 | ///
28 | /// See https://tools.ietf.org/html/rfc7231#section-4.3
29 | public struct HTTPMethod: RawRepresentable, Equatable, Hashable {
30 | /// `CONNECT` method.
31 | public static let connect = HTTPMethod(rawValue: "CONNECT")
32 | /// `DELETE` method.
33 | public static let delete = HTTPMethod(rawValue: "DELETE")
34 | /// `GET` method.
35 | public static let get = HTTPMethod(rawValue: "GET")
36 | /// `HEAD` method.
37 | public static let head = HTTPMethod(rawValue: "HEAD")
38 | /// `OPTIONS` method.
39 | public static let options = HTTPMethod(rawValue: "OPTIONS")
40 | /// `PATCH` method.
41 | public static let patch = HTTPMethod(rawValue: "PATCH")
42 | /// `POST` method.
43 | public static let post = HTTPMethod(rawValue: "POST")
44 | /// `PUT` method.
45 | public static let put = HTTPMethod(rawValue: "PUT")
46 | /// `TRACE` method.
47 | public static let trace = HTTPMethod(rawValue: "TRACE")
48 |
49 | public let rawValue: String
50 |
51 | public init(rawValue: String) {
52 | self.rawValue = rawValue
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/hn-ios-client/HN Client/Pods/Alamofire/Source/MultipartUpload.swift:
--------------------------------------------------------------------------------
1 | //
2 | // MultipartUpload.swift
3 | //
4 | // Copyright (c) 2014-2018 Alamofire Software Foundation (http://alamofire.org/)
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | // THE SOFTWARE.
23 | //
24 |
25 | import Foundation
26 |
27 | /// Internal type which encapsulates a `MultipartFormData` upload.
28 | final class MultipartUpload {
29 | lazy var result = Result { try build() }
30 |
31 | @Protected
32 | private(set) var multipartFormData: MultipartFormData
33 | let encodingMemoryThreshold: UInt64
34 | let request: URLRequestConvertible
35 | let fileManager: FileManager
36 |
37 | init(encodingMemoryThreshold: UInt64,
38 | request: URLRequestConvertible,
39 | multipartFormData: MultipartFormData) {
40 | self.encodingMemoryThreshold = encodingMemoryThreshold
41 | self.request = request
42 | fileManager = multipartFormData.fileManager
43 | self.multipartFormData = multipartFormData
44 | }
45 |
46 | func build() throws -> UploadRequest.Uploadable {
47 | let uploadable: UploadRequest.Uploadable
48 | if multipartFormData.contentLength < encodingMemoryThreshold {
49 | let data = try multipartFormData.encode()
50 |
51 | uploadable = .data(data)
52 | } else {
53 | let tempDirectoryURL = fileManager.temporaryDirectory
54 | let directoryURL = tempDirectoryURL.appendingPathComponent("org.alamofire.manager/multipart.form.data")
55 | let fileName = UUID().uuidString
56 | let fileURL = directoryURL.appendingPathComponent(fileName)
57 |
58 | try fileManager.createDirectory(at: directoryURL, withIntermediateDirectories: true, attributes: nil)
59 |
60 | do {
61 | try multipartFormData.writeEncodedData(to: fileURL)
62 | } catch {
63 | // Cleanup after attempted write if it fails.
64 | try? fileManager.removeItem(at: fileURL)
65 | throw error
66 | }
67 |
68 | uploadable = .file(fileURL, shouldRemove: true)
69 | }
70 |
71 | return uploadable
72 | }
73 | }
74 |
75 | extension MultipartUpload: UploadConvertible {
76 | func asURLRequest() throws -> URLRequest {
77 | var urlRequest = try request.asURLRequest()
78 |
79 | $multipartFormData.read { multipartFormData in
80 | urlRequest.headers.add(.contentType(multipartFormData.contentType))
81 | }
82 |
83 | return urlRequest
84 | }
85 |
86 | func createUploadable() throws -> UploadRequest.Uploadable {
87 | try result.get()
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/hn-ios-client/HN Client/Pods/Alamofire/Source/Notifications.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Notifications.swift
3 | //
4 | // Copyright (c) 2014-2018 Alamofire Software Foundation (http://alamofire.org/)
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | // THE SOFTWARE.
23 | //
24 |
25 | import Foundation
26 |
27 | extension Request {
28 | /// Posted when a `Request` is resumed. The `Notification` contains the resumed `Request`.
29 | public static let didResumeNotification = Notification.Name(rawValue: "org.alamofire.notification.name.request.didResume")
30 | /// Posted when a `Request` is suspended. The `Notification` contains the suspended `Request`.
31 | public static let didSuspendNotification = Notification.Name(rawValue: "org.alamofire.notification.name.request.didSuspend")
32 | /// Posted when a `Request` is cancelled. The `Notification` contains the cancelled `Request`.
33 | public static let didCancelNotification = Notification.Name(rawValue: "org.alamofire.notification.name.request.didCancel")
34 | /// Posted when a `Request` is finished. The `Notification` contains the completed `Request`.
35 | public static let didFinishNotification = Notification.Name(rawValue: "org.alamofire.notification.name.request.didFinish")
36 |
37 | /// Posted when a `URLSessionTask` is resumed. The `Notification` contains the `Request` associated with the `URLSessionTask`.
38 | public static let didResumeTaskNotification = Notification.Name(rawValue: "org.alamofire.notification.name.request.didResumeTask")
39 | /// Posted when a `URLSessionTask` is suspended. The `Notification` contains the `Request` associated with the `URLSessionTask`.
40 | public static let didSuspendTaskNotification = Notification.Name(rawValue: "org.alamofire.notification.name.request.didSuspendTask")
41 | /// Posted when a `URLSessionTask` is cancelled. The `Notification` contains the `Request` associated with the `URLSessionTask`.
42 | public static let didCancelTaskNotification = Notification.Name(rawValue: "org.alamofire.notification.name.request.didCancelTask")
43 | /// Posted when a `URLSessionTask` is completed. The `Notification` contains the `Request` associated with the `URLSessionTask`.
44 | public static let didCompleteTaskNotification = Notification.Name(rawValue: "org.alamofire.notification.name.request.didCompleteTask")
45 | }
46 |
47 | // MARK: -
48 |
49 | extension Notification {
50 | /// The `Request` contained by the instance's `userInfo`, `nil` otherwise.
51 | public var request: Request? {
52 | userInfo?[String.requestKey] as? Request
53 | }
54 |
55 | /// Convenience initializer for a `Notification` containing a `Request` payload.
56 | ///
57 | /// - Parameters:
58 | /// - name: The name of the notification.
59 | /// - request: The `Request` payload.
60 | init(name: Notification.Name, request: Request) {
61 | self.init(name: name, object: nil, userInfo: [String.requestKey: request])
62 | }
63 | }
64 |
65 | extension NotificationCenter {
66 | /// Convenience function for posting notifications with `Request` payloads.
67 | ///
68 | /// - Parameters:
69 | /// - name: The name of the notification.
70 | /// - request: The `Request` payload.
71 | func postNotification(named name: Notification.Name, with request: Request) {
72 | let notification = Notification(name: name, request: request)
73 | post(notification)
74 | }
75 | }
76 |
77 | extension String {
78 | /// User info dictionary key representing the `Request` associated with the notification.
79 | fileprivate static let requestKey = "org.alamofire.notification.key.request"
80 | }
81 |
82 | /// `EventMonitor` that provides Alamofire's notifications.
83 | public final class AlamofireNotifications: EventMonitor {
84 | public func requestDidResume(_ request: Request) {
85 | NotificationCenter.default.postNotification(named: Request.didResumeNotification, with: request)
86 | }
87 |
88 | public func requestDidSuspend(_ request: Request) {
89 | NotificationCenter.default.postNotification(named: Request.didSuspendNotification, with: request)
90 | }
91 |
92 | public func requestDidCancel(_ request: Request) {
93 | NotificationCenter.default.postNotification(named: Request.didCancelNotification, with: request)
94 | }
95 |
96 | public func requestDidFinish(_ request: Request) {
97 | NotificationCenter.default.postNotification(named: Request.didFinishNotification, with: request)
98 | }
99 |
100 | public func request(_ request: Request, didResumeTask task: URLSessionTask) {
101 | NotificationCenter.default.postNotification(named: Request.didResumeTaskNotification, with: request)
102 | }
103 |
104 | public func request(_ request: Request, didSuspendTask task: URLSessionTask) {
105 | NotificationCenter.default.postNotification(named: Request.didSuspendTaskNotification, with: request)
106 | }
107 |
108 | public func request(_ request: Request, didCancelTask task: URLSessionTask) {
109 | NotificationCenter.default.postNotification(named: Request.didCancelTaskNotification, with: request)
110 | }
111 |
112 | public func request(_ request: Request, didCompleteTask task: URLSessionTask, with error: AFError?) {
113 | NotificationCenter.default.postNotification(named: Request.didCompleteTaskNotification, with: request)
114 | }
115 | }
116 |
--------------------------------------------------------------------------------
/hn-ios-client/HN Client/Pods/Alamofire/Source/OperationQueue+Alamofire.swift:
--------------------------------------------------------------------------------
1 | //
2 | // OperationQueue+Alamofire.swift
3 | //
4 | // Copyright (c) 2014-2018 Alamofire Software Foundation (http://alamofire.org/)
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | // THE SOFTWARE.
23 | //
24 |
25 | import Foundation
26 |
27 | extension OperationQueue {
28 | /// Creates an instance using the provided parameters.
29 | ///
30 | /// - Parameters:
31 | /// - qualityOfService: `QualityOfService` to be applied to the queue. `.default` by default.
32 | /// - maxConcurrentOperationCount: Maximum concurrent operations.
33 | /// `OperationQueue.defaultMaxConcurrentOperationCount` by default.
34 | /// - underlyingQueue: Underlying `DispatchQueue`. `nil` by default.
35 | /// - name: Name for the queue. `nil` by default.
36 | /// - startSuspended: Whether the queue starts suspended. `false` by default.
37 | convenience init(qualityOfService: QualityOfService = .default,
38 | maxConcurrentOperationCount: Int = OperationQueue.defaultMaxConcurrentOperationCount,
39 | underlyingQueue: DispatchQueue? = nil,
40 | name: String? = nil,
41 | startSuspended: Bool = false) {
42 | self.init()
43 | self.qualityOfService = qualityOfService
44 | self.maxConcurrentOperationCount = maxConcurrentOperationCount
45 | self.underlyingQueue = underlyingQueue
46 | self.name = name
47 | isSuspended = startSuspended
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/hn-ios-client/HN Client/Pods/Alamofire/Source/RedirectHandler.swift:
--------------------------------------------------------------------------------
1 | //
2 | // RedirectHandler.swift
3 | //
4 | // Copyright (c) 2014-2018 Alamofire Software Foundation (http://alamofire.org/)
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | // THE SOFTWARE.
23 | //
24 |
25 | import Foundation
26 |
27 | /// A type that handles how an HTTP redirect response from a remote server should be redirected to the new request.
28 | public protocol RedirectHandler {
29 | /// Determines how the HTTP redirect response should be redirected to the new request.
30 | ///
31 | /// The `completion` closure should be passed one of three possible options:
32 | ///
33 | /// 1. The new request specified by the redirect (this is the most common use case).
34 | /// 2. A modified version of the new request (you may want to route it somewhere else).
35 | /// 3. A `nil` value to deny the redirect request and return the body of the redirect response.
36 | ///
37 | /// - Parameters:
38 | /// - task: The `URLSessionTask` whose request resulted in a redirect.
39 | /// - request: The `URLRequest` to the new location specified by the redirect response.
40 | /// - response: The `HTTPURLResponse` containing the server's response to the original request.
41 | /// - completion: The closure to execute containing the new `URLRequest`, a modified `URLRequest`, or `nil`.
42 | func task(_ task: URLSessionTask,
43 | willBeRedirectedTo request: URLRequest,
44 | for response: HTTPURLResponse,
45 | completion: @escaping (URLRequest?) -> Void)
46 | }
47 |
48 | // MARK: -
49 |
50 | /// `Redirector` is a convenience `RedirectHandler` making it easy to follow, not follow, or modify a redirect.
51 | public struct Redirector {
52 | /// Defines the behavior of the `Redirector` type.
53 | public enum Behavior {
54 | /// Follow the redirect as defined in the response.
55 | case follow
56 | /// Do not follow the redirect defined in the response.
57 | case doNotFollow
58 | /// Modify the redirect request defined in the response.
59 | case modify((URLSessionTask, URLRequest, HTTPURLResponse) -> URLRequest?)
60 | }
61 |
62 | /// Returns a `Redirector` with a `.follow` `Behavior`.
63 | public static let follow = Redirector(behavior: .follow)
64 | /// Returns a `Redirector` with a `.doNotFollow` `Behavior`.
65 | public static let doNotFollow = Redirector(behavior: .doNotFollow)
66 |
67 | /// The `Behavior` of the `Redirector`.
68 | public let behavior: Behavior
69 |
70 | /// Creates a `Redirector` instance from the `Behavior`.
71 | ///
72 | /// - Parameter behavior: The `Behavior`.
73 | public init(behavior: Behavior) {
74 | self.behavior = behavior
75 | }
76 | }
77 |
78 | // MARK: -
79 |
80 | extension Redirector: RedirectHandler {
81 | public func task(_ task: URLSessionTask,
82 | willBeRedirectedTo request: URLRequest,
83 | for response: HTTPURLResponse,
84 | completion: @escaping (URLRequest?) -> Void) {
85 | switch behavior {
86 | case .follow:
87 | completion(request)
88 | case .doNotFollow:
89 | completion(nil)
90 | case let .modify(closure):
91 | let request = closure(task, request, response)
92 | completion(request)
93 | }
94 | }
95 | }
96 |
--------------------------------------------------------------------------------
/hn-ios-client/HN Client/Pods/Alamofire/Source/Result+Alamofire.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Result+Alamofire.swift
3 | //
4 | // Copyright (c) 2019 Alamofire Software Foundation (http://alamofire.org/)
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | // THE SOFTWARE.
23 | //
24 |
25 | import Foundation
26 |
27 | /// Default type of `Result` returned by Alamofire, with an `AFError` `Failure` type.
28 | public typealias AFResult = Result
29 |
30 | // MARK: - Internal APIs
31 |
32 | extension Result {
33 | /// Returns whether the instance is `.success`.
34 | var isSuccess: Bool {
35 | guard case .success = self else { return false }
36 | return true
37 | }
38 |
39 | /// Returns whether the instance is `.failure`.
40 | var isFailure: Bool {
41 | !isSuccess
42 | }
43 |
44 | /// Returns the associated value if the result is a success, `nil` otherwise.
45 | var success: Success? {
46 | guard case let .success(value) = self else { return nil }
47 | return value
48 | }
49 |
50 | /// Returns the associated error value if the result is a failure, `nil` otherwise.
51 | var failure: Failure? {
52 | guard case let .failure(error) = self else { return nil }
53 | return error
54 | }
55 |
56 | /// Initializes a `Result` from value or error. Returns `.failure` if the error is non-nil, `.success` otherwise.
57 | ///
58 | /// - Parameters:
59 | /// - value: A value.
60 | /// - error: An `Error`.
61 | init(value: Success, error: Failure?) {
62 | if let error = error {
63 | self = .failure(error)
64 | } else {
65 | self = .success(value)
66 | }
67 | }
68 |
69 | /// Evaluates the specified closure when the `Result` is a success, passing the unwrapped value as a parameter.
70 | ///
71 | /// Use the `tryMap` method with a closure that may throw an error. For example:
72 | ///
73 | /// let possibleData: Result = .success(Data(...))
74 | /// let possibleObject = possibleData.tryMap {
75 | /// try JSONSerialization.jsonObject(with: $0)
76 | /// }
77 | ///
78 | /// - parameter transform: A closure that takes the success value of the instance.
79 | ///
80 | /// - returns: A `Result` containing the result of the given closure. If this instance is a failure, returns the
81 | /// same failure.
82 | func tryMap(_ transform: (Success) throws -> NewSuccess) -> Result {
83 | switch self {
84 | case let .success(value):
85 | do {
86 | return try .success(transform(value))
87 | } catch {
88 | return .failure(error)
89 | }
90 | case let .failure(error):
91 | return .failure(error)
92 | }
93 | }
94 |
95 | /// Evaluates the specified closure when the `Result` is a failure, passing the unwrapped error as a parameter.
96 | ///
97 | /// Use the `tryMapError` function with a closure that may throw an error. For example:
98 | ///
99 | /// let possibleData: Result = .success(Data(...))
100 | /// let possibleObject = possibleData.tryMapError {
101 | /// try someFailableFunction(taking: $0)
102 | /// }
103 | ///
104 | /// - Parameter transform: A throwing closure that takes the error of the instance.
105 | ///
106 | /// - Returns: A `Result` instance containing the result of the transform. If this instance is a success, returns
107 | /// the same success.
108 | func tryMapError(_ transform: (Failure) throws -> NewFailure) -> Result {
109 | switch self {
110 | case let .failure(error):
111 | do {
112 | return try .failure(transform(error))
113 | } catch {
114 | return .failure(error)
115 | }
116 | case let .success(value):
117 | return .success(value)
118 | }
119 | }
120 | }
121 |
--------------------------------------------------------------------------------
/hn-ios-client/HN Client/Pods/Alamofire/Source/StringEncoding+Alamofire.swift:
--------------------------------------------------------------------------------
1 | //
2 | // StringEncoding+Alamofire.swift
3 | //
4 | // Copyright (c) 2020 Alamofire Software Foundation (http://alamofire.org/)
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | // THE SOFTWARE.
23 | //
24 |
25 | import Foundation
26 |
27 | extension String.Encoding {
28 | /// Creates an encoding from the IANA charset name.
29 | ///
30 | /// - Notes: These mappings match those [provided by CoreFoundation](https://opensource.apple.com/source/CF/CF-476.18/CFStringUtilities.c.auto.html)
31 | ///
32 | /// - Parameter name: IANA charset name.
33 | init?(ianaCharsetName name: String) {
34 | switch name.lowercased() {
35 | case "utf-8":
36 | self = .utf8
37 | case "iso-8859-1":
38 | self = .isoLatin1
39 | case "unicode-1-1", "iso-10646-ucs-2", "utf-16":
40 | self = .utf16
41 | case "utf-16be":
42 | self = .utf16BigEndian
43 | case "utf-16le":
44 | self = .utf16LittleEndian
45 | case "utf-32":
46 | self = .utf32
47 | case "utf-32be":
48 | self = .utf32BigEndian
49 | case "utf-32le":
50 | self = .utf32LittleEndian
51 | default:
52 | return nil
53 | }
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/hn-ios-client/HN Client/Pods/Alamofire/Source/URLConvertible+URLRequestConvertible.swift:
--------------------------------------------------------------------------------
1 | //
2 | // URLConvertible+URLRequestConvertible.swift
3 | //
4 | // Copyright (c) 2014-2018 Alamofire Software Foundation (http://alamofire.org/)
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | // THE SOFTWARE.
23 | //
24 |
25 | import Foundation
26 |
27 | /// Types adopting the `URLConvertible` protocol can be used to construct `URL`s, which can then be used to construct
28 | /// `URLRequests`.
29 | public protocol URLConvertible {
30 | /// Returns a `URL` from the conforming instance or throws.
31 | ///
32 | /// - Returns: The `URL` created from the instance.
33 | /// - Throws: Any error thrown while creating the `URL`.
34 | func asURL() throws -> URL
35 | }
36 |
37 | extension String: URLConvertible {
38 | /// Returns a `URL` if `self` can be used to initialize a `URL` instance, otherwise throws.
39 | ///
40 | /// - Returns: The `URL` initialized with `self`.
41 | /// - Throws: An `AFError.invalidURL` instance.
42 | public func asURL() throws -> URL {
43 | guard let url = URL(string: self) else { throw AFError.invalidURL(url: self) }
44 |
45 | return url
46 | }
47 | }
48 |
49 | extension URL: URLConvertible {
50 | /// Returns `self`.
51 | public func asURL() throws -> URL { self }
52 | }
53 |
54 | extension URLComponents: URLConvertible {
55 | /// Returns a `URL` if the `self`'s `url` is not nil, otherwise throws.
56 | ///
57 | /// - Returns: The `URL` from the `url` property.
58 | /// - Throws: An `AFError.invalidURL` instance.
59 | public func asURL() throws -> URL {
60 | guard let url = url else { throw AFError.invalidURL(url: self) }
61 |
62 | return url
63 | }
64 | }
65 |
66 | // MARK: -
67 |
68 | /// Types adopting the `URLRequestConvertible` protocol can be used to safely construct `URLRequest`s.
69 | public protocol URLRequestConvertible {
70 | /// Returns a `URLRequest` or throws if an `Error` was encountered.
71 | ///
72 | /// - Returns: A `URLRequest`.
73 | /// - Throws: Any error thrown while constructing the `URLRequest`.
74 | func asURLRequest() throws -> URLRequest
75 | }
76 |
77 | extension URLRequestConvertible {
78 | /// The `URLRequest` returned by discarding any `Error` encountered.
79 | public var urlRequest: URLRequest? { try? asURLRequest() }
80 | }
81 |
82 | extension URLRequest: URLRequestConvertible {
83 | /// Returns `self`.
84 | public func asURLRequest() throws -> URLRequest { self }
85 | }
86 |
87 | // MARK: -
88 |
89 | extension URLRequest {
90 | /// Creates an instance with the specified `url`, `method`, and `headers`.
91 | ///
92 | /// - Parameters:
93 | /// - url: The `URLConvertible` value.
94 | /// - method: The `HTTPMethod`.
95 | /// - headers: The `HTTPHeaders`, `nil` by default.
96 | /// - Throws: Any error thrown while converting the `URLConvertible` to a `URL`.
97 | public init(url: URLConvertible, method: HTTPMethod, headers: HTTPHeaders? = nil) throws {
98 | let url = try url.asURL()
99 |
100 | self.init(url: url)
101 |
102 | httpMethod = method.rawValue
103 | allHTTPHeaderFields = headers?.dictionary
104 | }
105 | }
106 |
--------------------------------------------------------------------------------
/hn-ios-client/HN Client/Pods/Alamofire/Source/URLRequest+Alamofire.swift:
--------------------------------------------------------------------------------
1 | //
2 | // URLRequest+Alamofire.swift
3 | //
4 | // Copyright (c) 2019 Alamofire Software Foundation (http://alamofire.org/)
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | // THE SOFTWARE.
23 | //
24 |
25 | import Foundation
26 |
27 | extension URLRequest {
28 | /// Returns the `httpMethod` as Alamofire's `HTTPMethod` type.
29 | public var method: HTTPMethod? {
30 | get { httpMethod.flatMap(HTTPMethod.init) }
31 | set { httpMethod = newValue?.rawValue }
32 | }
33 |
34 | public func validate() throws {
35 | if method == .get, let bodyData = httpBody {
36 | throw AFError.urlRequestValidationFailed(reason: .bodyDataInGETRequest(bodyData))
37 | }
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/hn-ios-client/HN Client/Pods/Alamofire/Source/URLSessionConfiguration+Alamofire.swift:
--------------------------------------------------------------------------------
1 | //
2 | // URLSessionConfiguration+Alamofire.swift
3 | //
4 | // Copyright (c) 2014-2018 Alamofire Software Foundation (http://alamofire.org/)
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | // THE SOFTWARE.
23 | //
24 |
25 | import Foundation
26 |
27 | extension URLSessionConfiguration: AlamofireExtended {}
28 | extension AlamofireExtension where ExtendedType: URLSessionConfiguration {
29 | /// Alamofire's default configuration. Same as `URLSessionConfiguration.default` but adds Alamofire default
30 | /// `Accept-Language`, `Accept-Encoding`, and `User-Agent` headers.
31 | public static var `default`: URLSessionConfiguration {
32 | let configuration = URLSessionConfiguration.default
33 | configuration.headers = .default
34 |
35 | return configuration
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/hn-ios-client/HN Client/Pods/HNFoundation/HNFoundation.xcframework/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | AvailableLibraries
6 |
7 |
8 | LibraryIdentifier
9 | ios-arm64
10 | LibraryPath
11 | HNFoundation.framework
12 | SupportedArchitectures
13 |
14 | arm64
15 |
16 | SupportedPlatform
17 | ios
18 |
19 |
20 | LibraryIdentifier
21 | ios-x86_64-simulator
22 | LibraryPath
23 | HNFoundation.framework
24 | SupportedArchitectures
25 |
26 | x86_64
27 |
28 | SupportedPlatform
29 | ios
30 | SupportedPlatformVariant
31 | simulator
32 |
33 |
34 | CFBundlePackageType
35 | XFWK
36 | XCFrameworkFormatVersion
37 | 1.0
38 |
39 |
40 |
--------------------------------------------------------------------------------
/hn-ios-client/HN Client/Pods/HNFoundation/HNFoundation.xcframework/ios-arm64/HNFoundation.framework/HNFoundation:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/prof18/shared-hn-android-ios-backend/271a86050cbce6021fc8caeb7ebc6f80319105d9/hn-ios-client/HN Client/Pods/HNFoundation/HNFoundation.xcframework/ios-arm64/HNFoundation.framework/HNFoundation
--------------------------------------------------------------------------------
/hn-ios-client/HN Client/Pods/HNFoundation/HNFoundation.xcframework/ios-arm64/HNFoundation.framework/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleExecutable
6 | HNFoundation
7 | CFBundleIdentifier
8 | com.prof18.hn.dto.HNFoundation
9 | CFBundleInfoDictionaryVersion
10 | 6.0
11 | CFBundleName
12 | HNFoundation
13 | CFBundlePackageType
14 | FMWK
15 | CFBundleShortVersionString
16 | 1.0
17 | CFBundleSupportedPlatforms
18 |
19 | iPhoneOS
20 |
21 | CFBundleVersion
22 | 1
23 | MinimumOSVersion
24 | 9.0
25 | UIDeviceFamily
26 |
27 | 1
28 | 2
29 |
30 | UIRequiredDeviceCapabilities
31 |
32 | arm64
33 |
34 |
35 |
--------------------------------------------------------------------------------
/hn-ios-client/HN Client/Pods/HNFoundation/HNFoundation.xcframework/ios-arm64/HNFoundation.framework/Modules/module.modulemap:
--------------------------------------------------------------------------------
1 | framework module HNFoundation {
2 | umbrella header "HNFoundation.h"
3 |
4 | export *
5 | module * { export * }
6 | }
--------------------------------------------------------------------------------
/hn-ios-client/HN Client/Pods/HNFoundation/HNFoundation.xcframework/ios-x86_64-simulator/HNFoundation.framework/HNFoundation:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/prof18/shared-hn-android-ios-backend/271a86050cbce6021fc8caeb7ebc6f80319105d9/hn-ios-client/HN Client/Pods/HNFoundation/HNFoundation.xcframework/ios-x86_64-simulator/HNFoundation.framework/HNFoundation
--------------------------------------------------------------------------------
/hn-ios-client/HN Client/Pods/HNFoundation/HNFoundation.xcframework/ios-x86_64-simulator/HNFoundation.framework/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleExecutable
6 | HNFoundation
7 | CFBundleIdentifier
8 | com.prof18.hn.dto.HNFoundation
9 | CFBundleInfoDictionaryVersion
10 | 6.0
11 | CFBundleName
12 | HNFoundation
13 | CFBundlePackageType
14 | FMWK
15 | CFBundleShortVersionString
16 | 1.0
17 | CFBundleSupportedPlatforms
18 |
19 | iPhoneSimulator
20 |
21 | CFBundleVersion
22 | 1
23 | MinimumOSVersion
24 | 9.0
25 | UIDeviceFamily
26 |
27 | 1
28 | 2
29 |
30 |
31 |
--------------------------------------------------------------------------------
/hn-ios-client/HN Client/Pods/HNFoundation/HNFoundation.xcframework/ios-x86_64-simulator/HNFoundation.framework/Modules/module.modulemap:
--------------------------------------------------------------------------------
1 | framework module HNFoundation {
2 | umbrella header "HNFoundation.h"
3 |
4 | export *
5 | module * { export * }
6 | }
--------------------------------------------------------------------------------
/hn-ios-client/HN Client/Pods/HNFoundation/README.md:
--------------------------------------------------------------------------------
1 | # hn-foundation-cocoa
2 | CocoaPods repo for the https://github.com/prof18/shared-hn-android-ios-backend/ project
3 |
--------------------------------------------------------------------------------
/hn-ios-client/HN Client/Pods/Local Podspecs/HNFoundation.podspec.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "HNFoundation",
3 | "version": "2.0.0",
4 | "summary": "HNFoundation KMP library",
5 | "homepage": "https://github.com/prof18/hn-foundation-cocoa-xcframework",
6 | "license": "Apache",
7 | "authors": {
8 | "Marco Gomiero": "mg@me.com"
9 | },
10 | "vendored_frameworks": "HNFoundation.xcframework",
11 | "source": {
12 | "git": "git@github.com:prof18/hn-foundation-cocoa-xcframework",
13 | "tag": "2.0.0"
14 | },
15 | "exclude_files": "Classes/Exclude",
16 | "platforms": {
17 | "osx": null,
18 | "ios": null,
19 | "tvos": null,
20 | "watchos": null
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/hn-ios-client/HN Client/Pods/Manifest.lock:
--------------------------------------------------------------------------------
1 | PODS:
2 | - Alamofire (5.4.3)
3 | - HNFoundation (2.0.0)
4 |
5 | DEPENDENCIES:
6 | - Alamofire (~> 5.2)
7 | - "HNFoundation (from `git@github.com:prof18/hn-foundation-cocoa-xcframework.git`, tag `2.0.0`)"
8 |
9 | SPEC REPOS:
10 | trunk:
11 | - Alamofire
12 |
13 | EXTERNAL SOURCES:
14 | HNFoundation:
15 | :git: "git@github.com:prof18/hn-foundation-cocoa-xcframework.git"
16 | :tag: 2.0.0
17 |
18 | CHECKOUT OPTIONS:
19 | HNFoundation:
20 | :git: "git@github.com:prof18/hn-foundation-cocoa-xcframework.git"
21 | :tag: 2.0.0
22 |
23 | SPEC CHECKSUMS:
24 | Alamofire: e447a2774a40c996748296fa2c55112fdbbc42f9
25 | HNFoundation: c299d34d38a14256b485f6b58ec13e959d5c15aa
26 |
27 | PODFILE CHECKSUM: bd24eb8eb26a44a3229799e17b478572ae76286e
28 |
29 | COCOAPODS: 1.10.2
30 |
--------------------------------------------------------------------------------
/hn-ios-client/HN Client/Pods/Pods.xcodeproj/xcuserdata/marcogomiero.xcuserdatad/xcschemes/Alamofire.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
43 |
44 |
50 |
51 |
53 |
54 |
57 |
58 |
59 |
--------------------------------------------------------------------------------
/hn-ios-client/HN Client/Pods/Pods.xcodeproj/xcuserdata/marcogomiero.xcuserdatad/xcschemes/HNFoundation.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
43 |
44 |
50 |
51 |
53 |
54 |
57 |
58 |
59 |
--------------------------------------------------------------------------------
/hn-ios-client/HN Client/Pods/Pods.xcodeproj/xcuserdata/marcogomiero.xcuserdatad/xcschemes/Pods-HN Client.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
43 |
44 |
50 |
51 |
53 |
54 |
57 |
58 |
59 |
--------------------------------------------------------------------------------
/hn-ios-client/HN Client/Pods/Pods.xcodeproj/xcuserdata/marcogomiero.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | Alamofire.xcscheme
8 |
9 | isShown
10 |
11 | orderHint
12 | 0
13 |
14 | HNFoundation.xcscheme
15 |
16 | isShown
17 |
18 | orderHint
19 | 1
20 |
21 | Pods-HN Client.xcscheme
22 |
23 | isShown
24 |
25 | orderHint
26 | 2
27 |
28 |
29 | SuppressBuildableAutocreation
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/hn-ios-client/HN Client/Pods/Target Support Files/Alamofire/Alamofire-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 | FMWK
17 | CFBundleShortVersionString
18 | 5.4.3
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | ${CURRENT_PROJECT_VERSION}
23 | NSPrincipalClass
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/hn-ios-client/HN Client/Pods/Target Support Files/Alamofire/Alamofire-dummy.m:
--------------------------------------------------------------------------------
1 | #import
2 | @interface PodsDummy_Alamofire : NSObject
3 | @end
4 | @implementation PodsDummy_Alamofire
5 | @end
6 |
--------------------------------------------------------------------------------
/hn-ios-client/HN Client/Pods/Target Support Files/Alamofire/Alamofire-prefix.pch:
--------------------------------------------------------------------------------
1 | #ifdef __OBJC__
2 | #import
3 | #else
4 | #ifndef FOUNDATION_EXPORT
5 | #if defined(__cplusplus)
6 | #define FOUNDATION_EXPORT extern "C"
7 | #else
8 | #define FOUNDATION_EXPORT extern
9 | #endif
10 | #endif
11 | #endif
12 |
13 |
--------------------------------------------------------------------------------
/hn-ios-client/HN Client/Pods/Target Support Files/Alamofire/Alamofire-umbrella.h:
--------------------------------------------------------------------------------
1 | #ifdef __OBJC__
2 | #import
3 | #else
4 | #ifndef FOUNDATION_EXPORT
5 | #if defined(__cplusplus)
6 | #define FOUNDATION_EXPORT extern "C"
7 | #else
8 | #define FOUNDATION_EXPORT extern
9 | #endif
10 | #endif
11 | #endif
12 |
13 |
14 | FOUNDATION_EXPORT double AlamofireVersionNumber;
15 | FOUNDATION_EXPORT const unsigned char AlamofireVersionString[];
16 |
17 |
--------------------------------------------------------------------------------
/hn-ios-client/HN Client/Pods/Target Support Files/Alamofire/Alamofire.debug.xcconfig:
--------------------------------------------------------------------------------
1 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO
2 | CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/Alamofire
3 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
4 | OTHER_LDFLAGS = $(inherited) -framework "CFNetwork"
5 | OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS
6 | PODS_BUILD_DIR = ${BUILD_DIR}
7 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
8 | PODS_ROOT = ${SRCROOT}
9 | PODS_TARGET_SRCROOT = ${PODS_ROOT}/Alamofire
10 | PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates
11 | PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier}
12 | SKIP_INSTALL = YES
13 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES
14 |
--------------------------------------------------------------------------------
/hn-ios-client/HN Client/Pods/Target Support Files/Alamofire/Alamofire.modulemap:
--------------------------------------------------------------------------------
1 | framework module Alamofire {
2 | umbrella header "Alamofire-umbrella.h"
3 |
4 | export *
5 | module * { export * }
6 | }
7 |
--------------------------------------------------------------------------------
/hn-ios-client/HN Client/Pods/Target Support Files/Alamofire/Alamofire.release.xcconfig:
--------------------------------------------------------------------------------
1 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO
2 | CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/Alamofire
3 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
4 | OTHER_LDFLAGS = $(inherited) -framework "CFNetwork"
5 | OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS
6 | PODS_BUILD_DIR = ${BUILD_DIR}
7 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
8 | PODS_ROOT = ${SRCROOT}
9 | PODS_TARGET_SRCROOT = ${PODS_ROOT}/Alamofire
10 | PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates
11 | PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier}
12 | SKIP_INSTALL = YES
13 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES
14 |
--------------------------------------------------------------------------------
/hn-ios-client/HN Client/Pods/Target Support Files/HNFoundation/HNFoundation-copy-dsyms-input-files.xcfilelist:
--------------------------------------------------------------------------------
1 | ${PODS_ROOT}/HNFoundation/HNFoundation.framework.dSYM
--------------------------------------------------------------------------------
/hn-ios-client/HN Client/Pods/Target Support Files/HNFoundation/HNFoundation-copy-dsyms-output-files.xcfilelist:
--------------------------------------------------------------------------------
1 | ${DWARF_DSYM_FOLDER_PATH}/HNFoundation.framework.dSYM
--------------------------------------------------------------------------------
/hn-ios-client/HN Client/Pods/Target Support Files/HNFoundation/HNFoundation-copy-dsyms.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | set -e
3 | set -u
4 | set -o pipefail
5 |
6 | function on_error {
7 | echo "$(realpath -mq "${0}"):$1: error: Unexpected failure"
8 | }
9 | trap 'on_error $LINENO' ERR
10 |
11 | # Used as a return value for each invocation of `strip_invalid_archs` function.
12 | STRIP_BINARY_RETVAL=0
13 |
14 | # Strip invalid architectures
15 | strip_invalid_archs() {
16 | binary="$1"
17 | warn_missing_arch=${2:-true}
18 | # Get architectures for current target binary
19 | binary_archs="$(lipo -info "$binary" | rev | cut -d ':' -f1 | awk '{$1=$1;print}' | rev)"
20 | # Intersect them with the architectures we are building for
21 | intersected_archs="$(echo ${ARCHS[@]} ${binary_archs[@]} | tr ' ' '\n' | sort | uniq -d)"
22 | # If there are no archs supported by this binary then warn the user
23 | if [[ -z "$intersected_archs" ]]; then
24 | if [[ "$warn_missing_arch" == "true" ]]; then
25 | echo "warning: [CP] Vendored binary '$binary' contains architectures ($binary_archs) none of which match the current build architectures ($ARCHS)."
26 | fi
27 | STRIP_BINARY_RETVAL=1
28 | return
29 | fi
30 | stripped=""
31 | for arch in $binary_archs; do
32 | if ! [[ "${ARCHS}" == *"$arch"* ]]; then
33 | # Strip non-valid architectures in-place
34 | lipo -remove "$arch" -output "$binary" "$binary"
35 | stripped="$stripped $arch"
36 | fi
37 | done
38 | if [[ "$stripped" ]]; then
39 | echo "Stripped $binary of architectures:$stripped"
40 | fi
41 | STRIP_BINARY_RETVAL=0
42 | }
43 |
44 | # This protects against multiple targets copying the same framework dependency at the same time. The solution
45 | # was originally proposed here: https://lists.samba.org/archive/rsync/2008-February/020158.html
46 | RSYNC_PROTECT_TMP_FILES=(--filter "P .*.??????")
47 |
48 | # Copies and strips a vendored dSYM
49 | install_dsym() {
50 | local source="$1"
51 | warn_missing_arch=${2:-true}
52 | if [ -r "$source" ]; then
53 | # Copy the dSYM into the targets temp dir.
54 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${DERIVED_FILES_DIR}\""
55 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${DERIVED_FILES_DIR}"
56 |
57 | local basename
58 | basename="$(basename -s .dSYM "$source")"
59 | binary_name="$(ls "$source/Contents/Resources/DWARF")"
60 | binary="${DERIVED_FILES_DIR}/${basename}.dSYM/Contents/Resources/DWARF/${binary_name}"
61 |
62 | # Strip invalid architectures from the dSYM.
63 | if [[ "$(file "$binary")" == *"Mach-O "*"dSYM companion"* ]]; then
64 | strip_invalid_archs "$binary" "$warn_missing_arch"
65 | fi
66 | if [[ $STRIP_BINARY_RETVAL == 0 ]]; then
67 | # Move the stripped file into its final destination.
68 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --links --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${DERIVED_FILES_DIR}/${basename}.framework.dSYM\" \"${DWARF_DSYM_FOLDER_PATH}\""
69 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --links --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${DERIVED_FILES_DIR}/${basename}.dSYM" "${DWARF_DSYM_FOLDER_PATH}"
70 | else
71 | # The dSYM was not stripped at all, in this case touch a fake folder so the input/output paths from Xcode do not reexecute this script because the file is missing.
72 | touch "${DWARF_DSYM_FOLDER_PATH}/${basename}.dSYM"
73 | fi
74 | fi
75 | }
76 |
77 | # Copies the bcsymbolmap files of a vendored framework
78 | install_bcsymbolmap() {
79 | local bcsymbolmap_path="$1"
80 | local destination="${BUILT_PRODUCTS_DIR}"
81 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${bcsymbolmap_path}" "${destination}""
82 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${bcsymbolmap_path}" "${destination}"
83 | }
84 |
85 | install_dsym "${PODS_ROOT}/HNFoundation/HNFoundation.framework.dSYM"
86 |
--------------------------------------------------------------------------------
/hn-ios-client/HN Client/Pods/Target Support Files/HNFoundation/HNFoundation-xcframeworks-input-files.xcfilelist:
--------------------------------------------------------------------------------
1 | ${PODS_ROOT}/Target Support Files/HNFoundation/HNFoundation-xcframeworks.sh
2 | ${PODS_ROOT}/HNFoundation/HNFoundation.xcframework
--------------------------------------------------------------------------------
/hn-ios-client/HN Client/Pods/Target Support Files/HNFoundation/HNFoundation-xcframeworks-output-files.xcfilelist:
--------------------------------------------------------------------------------
1 | ${PODS_XCFRAMEWORKS_BUILD_DIR}/HNFoundation
--------------------------------------------------------------------------------
/hn-ios-client/HN Client/Pods/Target Support Files/HNFoundation/HNFoundation-xcframeworks.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | set -e
3 | set -u
4 | set -o pipefail
5 |
6 | function on_error {
7 | echo "$(realpath -mq "${0}"):$1: error: Unexpected failure"
8 | }
9 | trap 'on_error $LINENO' ERR
10 |
11 |
12 | # This protects against multiple targets copying the same framework dependency at the same time. The solution
13 | # was originally proposed here: https://lists.samba.org/archive/rsync/2008-February/020158.html
14 | RSYNC_PROTECT_TMP_FILES=(--filter "P .*.??????")
15 |
16 |
17 | copy_dir()
18 | {
19 | local source="$1"
20 | local destination="$2"
21 |
22 | # Use filter instead of exclude so missing patterns don't throw errors.
23 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --links --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" \"${source}\" \"${destination}\""
24 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --links --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" "${source}" "${destination}"
25 | }
26 |
27 | SELECT_SLICE_RETVAL=""
28 |
29 | select_slice() {
30 | local paths=("$@")
31 | # Locate the correct slice of the .xcframework for the current architectures
32 | local target_path=""
33 |
34 | # Split archs on space so we can find a slice that has all the needed archs
35 | local target_archs=$(echo $ARCHS | tr " " "\n")
36 |
37 | local target_variant=""
38 | if [[ "$PLATFORM_NAME" == *"simulator" ]]; then
39 | target_variant="simulator"
40 | fi
41 | if [[ ! -z ${EFFECTIVE_PLATFORM_NAME+x} && "$EFFECTIVE_PLATFORM_NAME" == *"maccatalyst" ]]; then
42 | target_variant="maccatalyst"
43 | fi
44 | for i in ${!paths[@]}; do
45 | local matched_all_archs="1"
46 | for target_arch in $target_archs
47 | do
48 | if ! [[ "${paths[$i]}" == *"$target_variant"* ]]; then
49 | matched_all_archs="0"
50 | break
51 | fi
52 |
53 | # Verifies that the path contains the variant string (simulator or maccatalyst) if the variant is set.
54 | if [[ -z "$target_variant" && ("${paths[$i]}" == *"simulator"* || "${paths[$i]}" == *"maccatalyst"*) ]]; then
55 | matched_all_archs="0"
56 | break
57 | fi
58 |
59 | # This regex matches all possible variants of the arch in the folder name:
60 | # Let's say the folder name is: ios-armv7_armv7s_arm64_arm64e/CoconutLib.framework
61 | # We match the following: -armv7_, _armv7s_, _arm64_ and _arm64e/.
62 | # If we have a specific variant: ios-i386_x86_64-simulator/CoconutLib.framework
63 | # We match the following: -i386_ and _x86_64-
64 | # When the .xcframework wraps a static library, the folder name does not include
65 | # any .framework. In that case, the folder name can be: ios-arm64_armv7
66 | # We also match _armv7$ to handle that case.
67 | local target_arch_regex="[_\-]${target_arch}([\/_\-]|$)"
68 | if ! [[ "${paths[$i]}" =~ $target_arch_regex ]]; then
69 | matched_all_archs="0"
70 | break
71 | fi
72 | done
73 |
74 | if [[ "$matched_all_archs" == "1" ]]; then
75 | # Found a matching slice
76 | echo "Selected xcframework slice ${paths[$i]}"
77 | SELECT_SLICE_RETVAL=${paths[$i]}
78 | break
79 | fi
80 | done
81 | }
82 |
83 | install_library() {
84 | local source="$1"
85 | local name="$2"
86 | local destination="${PODS_XCFRAMEWORKS_BUILD_DIR}/${name}"
87 |
88 | # Libraries can contain headers, module maps, and a binary, so we'll copy everything in the folder over
89 |
90 | local source="$binary"
91 | echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --links --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" \"${source}/*\" \"${destination}\""
92 | rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --links --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" "${source}/*" "${destination}"
93 | }
94 |
95 | # Copies a framework to derived data for use in later build phases
96 | install_framework()
97 | {
98 | local source="$1"
99 | local name="$2"
100 | local destination="${PODS_XCFRAMEWORKS_BUILD_DIR}/${name}"
101 |
102 | if [ ! -d "$destination" ]; then
103 | mkdir -p "$destination"
104 | fi
105 |
106 | copy_dir "$source" "$destination"
107 | echo "Copied $source to $destination"
108 | }
109 |
110 | install_xcframework_library() {
111 | local basepath="$1"
112 | local name="$2"
113 | local paths=("$@")
114 |
115 | # Locate the correct slice of the .xcframework for the current architectures
116 | select_slice "${paths[@]}"
117 | local target_path="$SELECT_SLICE_RETVAL"
118 | if [[ -z "$target_path" ]]; then
119 | echo "warning: [CP] Unable to find matching .xcframework slice in '${paths[@]}' for the current build architectures ($ARCHS)."
120 | return
121 | fi
122 |
123 | install_framework "$basepath/$target_path" "$name"
124 | }
125 |
126 | install_xcframework() {
127 | local basepath="$1"
128 | local name="$2"
129 | local package_type="$3"
130 | local paths=("$@")
131 |
132 | # Locate the correct slice of the .xcframework for the current architectures
133 | select_slice "${paths[@]}"
134 | local target_path="$SELECT_SLICE_RETVAL"
135 | if [[ -z "$target_path" ]]; then
136 | echo "warning: [CP] Unable to find matching .xcframework slice in '${paths[@]}' for the current build architectures ($ARCHS)."
137 | return
138 | fi
139 | local source="$basepath/$target_path"
140 |
141 | local destination="${PODS_XCFRAMEWORKS_BUILD_DIR}/${name}"
142 |
143 | if [ ! -d "$destination" ]; then
144 | mkdir -p "$destination"
145 | fi
146 |
147 | copy_dir "$source/" "$destination"
148 |
149 | echo "Copied $source to $destination"
150 | }
151 |
152 | install_xcframework "${PODS_ROOT}/HNFoundation/HNFoundation.xcframework" "HNFoundation" "framework" "ios-arm64" "ios-x86_64-simulator"
153 |
154 |
--------------------------------------------------------------------------------
/hn-ios-client/HN Client/Pods/Target Support Files/HNFoundation/HNFoundation.debug.xcconfig:
--------------------------------------------------------------------------------
1 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO
2 | CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/HNFoundation
3 | FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/HNFoundation" "${PODS_XCFRAMEWORKS_BUILD_DIR}/HNFoundation"
4 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
5 | PODS_BUILD_DIR = ${BUILD_DIR}
6 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
7 | PODS_ROOT = ${SRCROOT}
8 | PODS_TARGET_SRCROOT = ${PODS_ROOT}/HNFoundation
9 | PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates
10 | PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier}
11 | SKIP_INSTALL = YES
12 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES
13 |
--------------------------------------------------------------------------------
/hn-ios-client/HN Client/Pods/Target Support Files/HNFoundation/HNFoundation.release.xcconfig:
--------------------------------------------------------------------------------
1 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO
2 | CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/HNFoundation
3 | FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/HNFoundation" "${PODS_XCFRAMEWORKS_BUILD_DIR}/HNFoundation"
4 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
5 | PODS_BUILD_DIR = ${BUILD_DIR}
6 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
7 | PODS_ROOT = ${SRCROOT}
8 | PODS_TARGET_SRCROOT = ${PODS_ROOT}/HNFoundation
9 | PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates
10 | PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier}
11 | SKIP_INSTALL = YES
12 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES
13 |
--------------------------------------------------------------------------------
/hn-ios-client/HN Client/Pods/Target Support Files/Pods-HN Client/Pods-HN Client-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 | FMWK
17 | CFBundleShortVersionString
18 | 1.0.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | ${CURRENT_PROJECT_VERSION}
23 | NSPrincipalClass
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/hn-ios-client/HN Client/Pods/Target Support Files/Pods-HN Client/Pods-HN Client-acknowledgements.markdown:
--------------------------------------------------------------------------------
1 | # Acknowledgements
2 | This application makes use of the following third party libraries:
3 |
4 | ## Alamofire
5 |
6 | Copyright (c) 2014-2021 Alamofire Software Foundation (http://alamofire.org/)
7 |
8 | Permission is hereby granted, free of charge, to any person obtaining a copy
9 | of this software and associated documentation files (the "Software"), to deal
10 | in the Software without restriction, including without limitation the rights
11 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | copies of the Software, and to permit persons to whom the Software is
13 | furnished to do so, subject to the following conditions:
14 |
15 | The above copyright notice and this permission notice shall be included in
16 | all copies or substantial portions of the Software.
17 |
18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 | THE SOFTWARE.
25 |
26 | Generated by CocoaPods - https://cocoapods.org
27 |
--------------------------------------------------------------------------------
/hn-ios-client/HN Client/Pods/Target Support Files/Pods-HN Client/Pods-HN Client-acknowledgements.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | PreferenceSpecifiers
6 |
7 |
8 | FooterText
9 | This application makes use of the following third party libraries:
10 | Title
11 | Acknowledgements
12 | Type
13 | PSGroupSpecifier
14 |
15 |
16 | FooterText
17 | Copyright (c) 2014-2021 Alamofire Software Foundation (http://alamofire.org/)
18 |
19 | Permission is hereby granted, free of charge, to any person obtaining a copy
20 | of this software and associated documentation files (the "Software"), to deal
21 | in the Software without restriction, including without limitation the rights
22 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
23 | copies of the Software, and to permit persons to whom the Software is
24 | furnished to do so, subject to the following conditions:
25 |
26 | The above copyright notice and this permission notice shall be included in
27 | all copies or substantial portions of the Software.
28 |
29 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
30 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
31 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
32 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
33 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
34 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
35 | THE SOFTWARE.
36 |
37 | License
38 | MIT
39 | Title
40 | Alamofire
41 | Type
42 | PSGroupSpecifier
43 |
44 |
45 | FooterText
46 | Generated by CocoaPods - https://cocoapods.org
47 | Title
48 |
49 | Type
50 | PSGroupSpecifier
51 |
52 |
53 | StringsTable
54 | Acknowledgements
55 | Title
56 | Acknowledgements
57 |
58 |
59 |
--------------------------------------------------------------------------------
/hn-ios-client/HN Client/Pods/Target Support Files/Pods-HN Client/Pods-HN Client-dummy.m:
--------------------------------------------------------------------------------
1 | #import
2 | @interface PodsDummy_Pods_HN_Client : NSObject
3 | @end
4 | @implementation PodsDummy_Pods_HN_Client
5 | @end
6 |
--------------------------------------------------------------------------------
/hn-ios-client/HN Client/Pods/Target Support Files/Pods-HN Client/Pods-HN Client-frameworks-Debug-input-files.xcfilelist:
--------------------------------------------------------------------------------
1 | ${PODS_ROOT}/Target Support Files/Pods-HN Client/Pods-HN Client-frameworks.sh
2 | ${BUILT_PRODUCTS_DIR}/Alamofire/Alamofire.framework
3 | ${PODS_XCFRAMEWORKS_BUILD_DIR}/HNFoundation/HNFoundation.framework/HNFoundation
--------------------------------------------------------------------------------
/hn-ios-client/HN Client/Pods/Target Support Files/Pods-HN Client/Pods-HN Client-frameworks-Debug-output-files.xcfilelist:
--------------------------------------------------------------------------------
1 | ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Alamofire.framework
2 | ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/HNFoundation.framework
--------------------------------------------------------------------------------
/hn-ios-client/HN Client/Pods/Target Support Files/Pods-HN Client/Pods-HN Client-frameworks-Release-input-files.xcfilelist:
--------------------------------------------------------------------------------
1 | ${PODS_ROOT}/Target Support Files/Pods-HN Client/Pods-HN Client-frameworks.sh
2 | ${BUILT_PRODUCTS_DIR}/Alamofire/Alamofire.framework
3 | ${PODS_XCFRAMEWORKS_BUILD_DIR}/HNFoundation/HNFoundation.framework/HNFoundation
--------------------------------------------------------------------------------
/hn-ios-client/HN Client/Pods/Target Support Files/Pods-HN Client/Pods-HN Client-frameworks-Release-output-files.xcfilelist:
--------------------------------------------------------------------------------
1 | ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Alamofire.framework
2 | ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/HNFoundation.framework
--------------------------------------------------------------------------------
/hn-ios-client/HN Client/Pods/Target Support Files/Pods-HN Client/Pods-HN Client-umbrella.h:
--------------------------------------------------------------------------------
1 | #ifdef __OBJC__
2 | #import
3 | #else
4 | #ifndef FOUNDATION_EXPORT
5 | #if defined(__cplusplus)
6 | #define FOUNDATION_EXPORT extern "C"
7 | #else
8 | #define FOUNDATION_EXPORT extern
9 | #endif
10 | #endif
11 | #endif
12 |
13 |
14 | FOUNDATION_EXPORT double Pods_HN_ClientVersionNumber;
15 | FOUNDATION_EXPORT const unsigned char Pods_HN_ClientVersionString[];
16 |
17 |
--------------------------------------------------------------------------------
/hn-ios-client/HN Client/Pods/Target Support Files/Pods-HN Client/Pods-HN Client.debug.xcconfig:
--------------------------------------------------------------------------------
1 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES
2 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO
3 | FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Alamofire" "${PODS_ROOT}/HNFoundation" "${PODS_XCFRAMEWORKS_BUILD_DIR}/HNFoundation"
4 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
5 | HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Alamofire/Alamofire.framework/Headers"
6 | LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks'
7 | OTHER_LDFLAGS = $(inherited) -framework "Alamofire" -framework "CFNetwork" -framework "HNFoundation"
8 | OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS
9 | PODS_BUILD_DIR = ${BUILD_DIR}
10 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
11 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/.
12 | PODS_ROOT = ${SRCROOT}/Pods
13 | PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates
14 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES
15 |
--------------------------------------------------------------------------------
/hn-ios-client/HN Client/Pods/Target Support Files/Pods-HN Client/Pods-HN Client.modulemap:
--------------------------------------------------------------------------------
1 | framework module Pods_HN_Client {
2 | umbrella header "Pods-HN Client-umbrella.h"
3 |
4 | export *
5 | module * { export * }
6 | }
7 |
--------------------------------------------------------------------------------
/hn-ios-client/HN Client/Pods/Target Support Files/Pods-HN Client/Pods-HN Client.release.xcconfig:
--------------------------------------------------------------------------------
1 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES
2 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO
3 | FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Alamofire" "${PODS_ROOT}/HNFoundation" "${PODS_XCFRAMEWORKS_BUILD_DIR}/HNFoundation"
4 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
5 | HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Alamofire/Alamofire.framework/Headers"
6 | LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks'
7 | OTHER_LDFLAGS = $(inherited) -framework "Alamofire" -framework "CFNetwork" -framework "HNFoundation"
8 | OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS
9 | PODS_BUILD_DIR = ${BUILD_DIR}
10 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
11 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/.
12 | PODS_ROOT = ${SRCROOT}/Pods
13 | PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates
14 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES
15 |
--------------------------------------------------------------------------------
/utils/hacker_news.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "by": "rbanffy",
4 | "id": 24401439,
5 | "score": 47,
6 | "time": 1599503461,
7 | "title": "Arm Announces Cortex-R82: First 64-Bit Real Time Processor",
8 | "type": "story",
9 | "url": "https://www.anandtech.com/show/16056/arm-announces-cortexr82-first-64bit-real-time-processor"
10 | },
11 | {
12 | "by": "tdhttt",
13 | "id": 24401462,
14 | "score": 29,
15 | "time": 1599503654,
16 | "title": "One of quantum physics’ greatest paradoxes may have lost its leading explanation",
17 | "type": "story",
18 | "url": "https://www.sciencemag.org/news/2020/09/one-quantum-physics-greatest-paradoxes-may-have-lost-its-leading-explanation"
19 | },
20 | {
21 | "by": "tomohawk",
22 | "id": 24401664,
23 | "score": 15,
24 | "time": 1599504852,
25 | "title": "The US Army Spent Millions Developing Giant, Six-Legged Walking Trucks in 1980s",
26 | "type": "story",
27 | "url": "https://www.thedrive.com/news/36157/the-us-army-spent-millions-developing-giant-six-legged-walking-trucks-in-the-1980s"
28 | },
29 | {
30 | "by": "pjmlp",
31 | "id": 24398469,
32 | "score": 19,
33 | "time": 1599475969,
34 | "title": "Pony, Actors, Causality, Types, and Garbage Collection",
35 | "type": "story",
36 | "url": "https://www.infoq.com/presentations/pony-types-garbage-collection/"
37 | },
38 | {
39 | "by": "praveenscience",
40 | "id": 24401398,
41 | "score": 12,
42 | "time": 1599503133,
43 | "title": "Something strange happens on Mars during a solar eclipse",
44 | "type": "story",
45 | "url": "https://www.sciencealert.com/something-strange-happens-on-mars-during-a-solar-eclipse"
46 | },
47 | {
48 | "by": "rbanffy",
49 | "id": 24399392,
50 | "score": 84,
51 | "time": 1599486418,
52 | "title": "Calculating the sample size required for developing a clinical prediction model",
53 | "type": "story",
54 | "url": "https://www.bmj.com/content/368/bmj.m441/rr"
55 | },
56 | {
57 | "by": "43t344efsg",
58 | "id": 24401565,
59 | "score": 6,
60 | "time": 1599504272,
61 | "title": "Gary Marcus's Kafkaesque Critique of GPT-3",
62 | "type": "story",
63 | "url": "https://nostalgebraist.tumblr.com/post/628024664310136832/gary-marcus-has-co-authored-a-brief-critique-of"
64 | },
65 | {
66 | "by": "based2",
67 | "id": 24390893,
68 | "score": 39,
69 | "time": 1599395286,
70 | "title": "Simple Bugs with Complex Exploits",
71 | "type": "story",
72 | "url": "https://www.elttam.com/blog/simple-bugs-with-complex-exploits/"
73 | },
74 | {
75 | "by": "alex_hirner",
76 | "id": 24382360,
77 | "score": 155,
78 | "time": 1599296806,
79 | "title": "Geometric Algebra for Python",
80 | "type": "story",
81 | "url": "https://github.com/pygae/clifford"
82 | },
83 | {
84 | "by": "dfgdghdf",
85 | "id": 24397772,
86 | "score": 9,
87 | "time": 1599468440,
88 | "title": "The 10,000 Year Clock",
89 | "type": "story",
90 | "url": "https://longnow.org/clock/"
91 | },
92 | {
93 | "by": "jairajs89",
94 | "id": 24400779,
95 | "score": 1,
96 | "time": 1599498264,
97 | "title": "Substack (YC W18) Is Hiring to Build a Better Business Model for Writing",
98 | "type": "job",
99 | "url": "https://substack.com/jobs"
100 | },
101 | {
102 | "by": "aaron-santos",
103 | "id": 24401085,
104 | "score": 7,
105 | "time": 1599500646,
106 | "title": "Bash Pitfalls",
107 | "type": "story",
108 | "url": "https://mywiki.wooledge.org/BashPitfalls"
109 | },
110 | {
111 | "by": "colinprince",
112 | "id": 24382953,
113 | "score": 9,
114 | "time": 1599307162,
115 | "title": "Smart Watches Could Do More for Wheelchair Users",
116 | "type": "story",
117 | "url": "https://fivethirtyeight.com/features/smart-watches-could-do-more-for-wheelchair-users/"
118 | },
119 | {
120 | "by": "panic",
121 | "id": 24386120,
122 | "score": 7,
123 | "time": 1599333188,
124 | "title": "How can you make subjective time go slower?",
125 | "type": "story",
126 | "url": "http://theoryengine.org/life/tips-for-a-longer-life/"
127 | },
128 | {
129 | "by": "mmerlin",
130 | "id": 24398485,
131 | "score": 73,
132 | "time": 1599476163,
133 | "title": "800x480 Touchscreen Raspberry Pi 3B+ Hackable Linux Handheld",
134 | "type": "story",
135 | "url": "http://yarh.io/yarh-io-mki.html"
136 | },
137 | {
138 | "by": "ycombinete",
139 | "id": 24390778,
140 | "score": 127,
141 | "time": 1599393804,
142 | "title": "Does Storing Bread in the Fridge Make it Last Longer? (2019)",
143 | "type": "story",
144 | "url": "https://culinarylore.com/food-science:does-storing-bread-in-the-fridge-make-it-last-longer/"
145 | },
146 | {
147 | "by": "jrhouston",
148 | "id": 24397111,
149 | "score": 3,
150 | "time": 1599460888,
151 | "title": "Eliza, the Rogerian Therapist (1999)",
152 | "type": "story",
153 | "url": "http://psych.fullerton.edu/mbirnbaum/psych101/Eliza.htm"
154 | },
155 | {
156 | "by": "kwhitefoot",
157 | "id": 24390855,
158 | "score": 98,
159 | "time": 1599394809,
160 | "title": "Why it is Important that Software Projects Fail (2008)",
161 | "type": "story",
162 | "url": "https://www.berglas.org/Articles/ImportantThatSoftwareFails/ImportantThatSoftwareFails.html"
163 | },
164 | {
165 | "by": "mindcrime",
166 | "id": 24396987,
167 | "score": 173,
168 | "time": 1599459028,
169 | "title": "International Space Station 437.800 MHz cross band FM repeater activated",
170 | "type": "story",
171 | "url": "https://amsat-uk.org/2020/09/02/iss-fm-repeater-activated/"
172 | },
173 | {
174 | "by": "maydemir",
175 | "id": 24397867,
176 | "score": 4,
177 | "time": 1599469246,
178 | "title": "Withings' ScanWatch packs ECG and SpO2 sensors alongside the usual tools",
179 | "type": "story",
180 | "url": "https://www.engadget.com/withings-scanwatch-hands-on-ifa-2020-070001875.html"
181 | }
182 | ]
--------------------------------------------------------------------------------
/utils/news-generator.py:
--------------------------------------------------------------------------------
1 | import requests
2 | import json
3 |
4 | r = requests.get("https://hacker-news.firebaseio.com/v0/topstories.json?print=pretty").text
5 | ids = json.loads(r)
6 | articles = []
7 | for article_id in ids[:20]:
8 | url = "https://hacker-news.firebaseio.com/v0/item/{}.json?print=pretty".format(article_id)
9 | detail_r = requests.get(url).text
10 | article_json = json.loads(detail_r)
11 | if 'descendants' in article_json:
12 | del article_json["descendants"]
13 | if 'kids' in article_json:
14 | del article_json["kids"]
15 | articles.append(article_json)
16 |
17 | articles = json.dumps(articles)
18 | print(articles)
19 |
20 | with open("hacker_news.json", "w") as text_file:
21 | text_file.write(articles)
22 |
--------------------------------------------------------------------------------