mirror of
https://github.com/hmalik144/Weather-apps.git
synced 2026-01-31 02:51:46 +00:00
- Fastlane completed
- Circleci config completed - Flavours build completed
This commit is contained in:
@@ -15,9 +15,15 @@ commands:
|
|||||||
steps:
|
steps:
|
||||||
- checkout
|
- checkout
|
||||||
- android/restore-gradle-cache
|
- android/restore-gradle-cache
|
||||||
|
build_gradle:
|
||||||
|
description: Build the gradle
|
||||||
|
steps:
|
||||||
|
- android/restore-gradle-cache
|
||||||
- run:
|
- run:
|
||||||
name: Download Dependencies
|
name: Download Dependencies
|
||||||
command: ./gradlew androidDependencies
|
command: |
|
||||||
|
sudo chmod +x ./gradlew
|
||||||
|
./gradlew androidDependencies
|
||||||
- android/save-gradle-cache
|
- android/save-gradle-cache
|
||||||
run_tests:
|
run_tests:
|
||||||
description: run tests for flavour specified
|
description: run tests for flavour specified
|
||||||
@@ -26,14 +32,17 @@ commands:
|
|||||||
type: string
|
type: string
|
||||||
default: "AtlasWeather"
|
default: "AtlasWeather"
|
||||||
steps:
|
steps:
|
||||||
# The next step will run the unit tests
|
# The next step will run the unit tests
|
||||||
- android/run-tests:
|
- build_gradle
|
||||||
test-command: ./gradlew test<< parameters.flavour >>DebugUnitTest --continue
|
- run:
|
||||||
- store_artifacts:
|
name: Run non-instrumentation unit tests
|
||||||
path: app/build/reports
|
command: |
|
||||||
destination: reports
|
./gradlew test<< parameters.flavour >>DebugUnitTest --continue
|
||||||
- store_test_results:
|
- store_artifacts:
|
||||||
path: app/build/test-results
|
path: app/build/reports
|
||||||
|
destination: reports
|
||||||
|
- store_test_results:
|
||||||
|
path: app/build/test-results
|
||||||
run_ui_tests:
|
run_ui_tests:
|
||||||
description: run tests for flavour specified
|
description: run tests for flavour specified
|
||||||
parameters:
|
parameters:
|
||||||
@@ -41,27 +50,44 @@ commands:
|
|||||||
type: string
|
type: string
|
||||||
default: "AtlasWeather"
|
default: "AtlasWeather"
|
||||||
steps:
|
steps:
|
||||||
- android/start-emulator-and-run-tests:
|
- build_gradle
|
||||||
post-emulator-launch-assemble-command: ./gradlew assemble<< parameters.flavour >>DebugAndroidTest
|
- android/start-emulator-and-run-tests:
|
||||||
test-command: ./gradlew connected<< parameters.flavour >>DebugAndroidTest
|
post-emulator-launch-assemble-command: ./gradlew assemble<< parameters.flavour >>DebugAndroidTest
|
||||||
system-image: system-images;android-25;google_apis;x86
|
test-command: ./gradlew connected<< parameters.flavour >>DebugAndroidTest
|
||||||
max-tries: 1
|
system-image: system-images;android-25;google_apis;x86
|
||||||
kill-emulators: false
|
pull-data: true
|
||||||
- run:
|
pull-data-path: /storage/emulated/0/Android/data/
|
||||||
name: Pull screenshots from device
|
pull-data-target: ~/app-data
|
||||||
command: |
|
# store test reports
|
||||||
mkdir ~/screenshots
|
- store_artifacts:
|
||||||
adb pull /storage/emulated/0/Android/data/com.appttude.h_mal.atlas_weather/files/screengrab/en-US/images/screenshots ~/screenshots
|
path: app/build/reports/androidTests/connected
|
||||||
when: on_fail
|
destination: reports
|
||||||
# store test reports
|
# store screenshots for failed ui tests
|
||||||
- store_artifacts:
|
- store_artifacts:
|
||||||
path: app/build/reports/androidTests/connected
|
path: ~/app-data
|
||||||
destination: reports
|
destination: screenshots
|
||||||
# store screenshots for failed ui tests
|
deploy_to_play_store:
|
||||||
- store_artifacts:
|
description: deploy to playstore based on flavour
|
||||||
path: ~/screenshots
|
parameters:
|
||||||
destination: screenshots
|
flavour:
|
||||||
|
type: string
|
||||||
|
default: "AtlasWeather"
|
||||||
|
steps:
|
||||||
|
# The next step will run the unit tests
|
||||||
|
- android/decode-keystore:
|
||||||
|
keystore-location: "./app/keystore.jks"
|
||||||
|
- run:
|
||||||
|
name: Setup playstore key
|
||||||
|
command: |
|
||||||
|
echo "$GOOGLE_PLAY_KEY" > "google-play-key.json"
|
||||||
|
- build_gradle
|
||||||
|
- run:
|
||||||
|
name: Run fastlane command to deploy to playstore
|
||||||
|
command: |
|
||||||
|
pwd
|
||||||
|
bundle exec fastlane deploy<< parameters.flavour >>
|
||||||
|
- store_test_results:
|
||||||
|
path: fastlane/report.xml
|
||||||
# Define a job to be invoked later in a workflow.
|
# Define a job to be invoked later in a workflow.
|
||||||
# See: https://circleci.com/docs/2.0/configuration-reference/#jobs
|
# See: https://circleci.com/docs/2.0/configuration-reference/#jobs
|
||||||
jobs:
|
jobs:
|
||||||
@@ -83,54 +109,60 @@ jobs:
|
|||||||
- setup_repo
|
- setup_repo
|
||||||
- run_tests:
|
- run_tests:
|
||||||
flavour: << parameters.flavour >>
|
flavour: << parameters.flavour >>
|
||||||
ui-test-and-release:
|
- run_ui_tests:
|
||||||
# Parameters used for determining
|
flavour: << parameters.flavour >>
|
||||||
|
deploy-to-playstore:
|
||||||
parameters:
|
parameters:
|
||||||
flavour:
|
flavour:
|
||||||
type: string
|
type: string
|
||||||
default: "AtlasWeather"
|
default: "Driver"
|
||||||
executor:
|
docker:
|
||||||
name: android/android-machine
|
- image: cimg/android:2023.07-browsers
|
||||||
tag: 2023.05.1
|
auth:
|
||||||
|
username: ${DOCKER_USERNAME}
|
||||||
|
password: ${DOCKER_PASSWORD}
|
||||||
steps:
|
steps:
|
||||||
- setup_repo
|
- setup_repo
|
||||||
- run_ui_tests
|
- deploy_to_play_store:
|
||||||
- run:
|
flavour: << parameters.flavour >>
|
||||||
name: Setup variables for release
|
|
||||||
command: |
|
|
||||||
echo "$RELEASE_KEYSTORE_BASE64" | base64 --decode > "android/app/release_keystore.jks"
|
|
||||||
echo "$GOOGLE_PLAY_KEY" > "android/playstore.json"
|
|
||||||
# And finally run the release build
|
|
||||||
- run:
|
|
||||||
name: Assemble and Upload to PlayStore
|
|
||||||
command: |
|
|
||||||
pwd
|
|
||||||
bundle exec fastlane deploy<< parameters.flavour >>
|
|
||||||
|
|
||||||
# Invoke jobs via workflows
|
# Invoke jobs via workflows
|
||||||
# See: https://circleci.com/docs/2.0/configuration-reference/#workflows
|
# See: https://circleci.com/docs/2.0/configuration-reference/#workflows
|
||||||
workflows:
|
workflows:
|
||||||
version: 2
|
version: 2
|
||||||
|
build-release-mono:
|
||||||
|
jobs:
|
||||||
|
- build-and-test:
|
||||||
|
context: appttude
|
||||||
|
flavour: "MonoWeather"
|
||||||
|
filters:
|
||||||
|
branches:
|
||||||
|
ignore:
|
||||||
|
- main_atlas
|
||||||
|
- deploy-to-playstore:
|
||||||
|
context: appttude
|
||||||
|
flavour: "MonoWeather"
|
||||||
|
filters:
|
||||||
|
branches:
|
||||||
|
only:
|
||||||
|
- main_mono
|
||||||
|
requires:
|
||||||
|
- build-and-test
|
||||||
build-release-atlas:
|
build-release-atlas:
|
||||||
jobs:
|
jobs:
|
||||||
- build-and-test:
|
- build-and-test:
|
||||||
|
context: appttude
|
||||||
flavour: "AtlasWeather"
|
flavour: "AtlasWeather"
|
||||||
- ui-test-and-release:
|
filters:
|
||||||
|
branches:
|
||||||
|
ignore:
|
||||||
|
- main_mono
|
||||||
|
- deploy-to-playstore:
|
||||||
|
context: appttude
|
||||||
flavour: "AtlasWeather"
|
flavour: "AtlasWeather"
|
||||||
filters:
|
filters:
|
||||||
branches:
|
branches:
|
||||||
only:
|
only:
|
||||||
- main_atlas
|
- main_atlas
|
||||||
requires:
|
|
||||||
- build-and-test
|
|
||||||
build-release-mono:
|
|
||||||
jobs:
|
|
||||||
- build-and-test:
|
|
||||||
flavour: "MonoWeather"
|
|
||||||
- ui-test-and-release:
|
|
||||||
flavour: "MonoWeather"
|
|
||||||
filters:
|
|
||||||
branches:
|
|
||||||
only: main_admin
|
|
||||||
requires:
|
requires:
|
||||||
- build-and-test
|
- build-and-test
|
||||||
26
.idea/androidTestResultsUserPreferences.xml
generated
26
.idea/androidTestResultsUserPreferences.xml
generated
@@ -16,6 +16,19 @@
|
|||||||
</AndroidTestResultsTableState>
|
</AndroidTestResultsTableState>
|
||||||
</value>
|
</value>
|
||||||
</entry>
|
</entry>
|
||||||
|
<entry key="-2008434490">
|
||||||
|
<value>
|
||||||
|
<AndroidTestResultsTableState>
|
||||||
|
<option name="preferredColumnWidths">
|
||||||
|
<map>
|
||||||
|
<entry key="Duration" value="90" />
|
||||||
|
<entry key="Pixel_2_API_27" value="120" />
|
||||||
|
<entry key="Tests" value="360" />
|
||||||
|
</map>
|
||||||
|
</option>
|
||||||
|
</AndroidTestResultsTableState>
|
||||||
|
</value>
|
||||||
|
</entry>
|
||||||
<entry key="170536241">
|
<entry key="170536241">
|
||||||
<value>
|
<value>
|
||||||
<AndroidTestResultsTableState>
|
<AndroidTestResultsTableState>
|
||||||
@@ -29,6 +42,19 @@
|
|||||||
</AndroidTestResultsTableState>
|
</AndroidTestResultsTableState>
|
||||||
</value>
|
</value>
|
||||||
</entry>
|
</entry>
|
||||||
|
<entry key="287238248">
|
||||||
|
<value>
|
||||||
|
<AndroidTestResultsTableState>
|
||||||
|
<option name="preferredColumnWidths">
|
||||||
|
<map>
|
||||||
|
<entry key="Duration" value="90" />
|
||||||
|
<entry key="Pixel_2_API_27" value="120" />
|
||||||
|
<entry key="Tests" value="360" />
|
||||||
|
</map>
|
||||||
|
</option>
|
||||||
|
</AndroidTestResultsTableState>
|
||||||
|
</value>
|
||||||
|
</entry>
|
||||||
<entry key="1127175145">
|
<entry key="1127175145">
|
||||||
<value>
|
<value>
|
||||||
<AndroidTestResultsTableState>
|
<AndroidTestResultsTableState>
|
||||||
|
|||||||
@@ -4,15 +4,19 @@ import android.Manifest
|
|||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import android.view.View
|
||||||
import androidx.test.core.app.ActivityScenario
|
import androidx.test.core.app.ActivityScenario
|
||||||
import androidx.test.espresso.internal.inject.InstrumentationContext
|
import androidx.test.espresso.Espresso
|
||||||
|
import androidx.test.espresso.UiController
|
||||||
|
import androidx.test.espresso.ViewAction
|
||||||
|
import androidx.test.espresso.matcher.ViewMatchers
|
||||||
import androidx.test.platform.app.InstrumentationRegistry
|
import androidx.test.platform.app.InstrumentationRegistry
|
||||||
import androidx.test.rule.GrantPermissionRule
|
import androidx.test.rule.GrantPermissionRule
|
||||||
import com.appttude.h_mal.atlas_weather.application.TestAppClass
|
import com.appttude.h_mal.atlas_weather.application.TestAppClass
|
||||||
import com.appttude.h_mal.atlas_weather.helper.GenericsHelper.getGenericClassAt
|
|
||||||
import com.appttude.h_mal.atlas_weather.helpers.SnapshotRule
|
import com.appttude.h_mal.atlas_weather.helpers.SnapshotRule
|
||||||
import com.appttude.h_mal.atlas_weather.utils.Stubs
|
import com.appttude.h_mal.atlas_weather.utils.Stubs
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
|
import org.hamcrest.Matcher
|
||||||
import org.junit.After
|
import org.junit.After
|
||||||
import org.junit.Before
|
import org.junit.Before
|
||||||
import org.junit.Rule
|
import org.junit.Rule
|
||||||
@@ -26,6 +30,7 @@ open class BaseTest<A : Activity>(
|
|||||||
|
|
||||||
lateinit var scenario: ActivityScenario<A>
|
lateinit var scenario: ActivityScenario<A>
|
||||||
private lateinit var testApp: TestAppClass
|
private lateinit var testApp: TestAppClass
|
||||||
|
private lateinit var testActivity: Activity
|
||||||
|
|
||||||
@get:Rule
|
@get:Rule
|
||||||
var permissionRule = GrantPermissionRule.grant(Manifest.permission.ACCESS_COARSE_LOCATION)
|
var permissionRule = GrantPermissionRule.grant(Manifest.permission.ACCESS_COARSE_LOCATION)
|
||||||
@@ -36,19 +41,22 @@ open class BaseTest<A : Activity>(
|
|||||||
@Before
|
@Before
|
||||||
fun setUp() {
|
fun setUp() {
|
||||||
Screengrab.setDefaultScreenshotStrategy(UiAutomatorScreenshotStrategy())
|
Screengrab.setDefaultScreenshotStrategy(UiAutomatorScreenshotStrategy())
|
||||||
val startIntent = Intent(InstrumentationRegistry.getInstrumentation().targetContext, activity)
|
val startIntent =
|
||||||
|
Intent(InstrumentationRegistry.getInstrumentation().targetContext, activity)
|
||||||
if (intentBundle != null) {
|
if (intentBundle != null) {
|
||||||
startIntent.replaceExtras(intentBundle)
|
startIntent.replaceExtras(intentBundle)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
testApp = InstrumentationRegistry.getInstrumentation().targetContext.applicationContext as TestAppClass
|
||||||
|
runBlocking {
|
||||||
|
beforeLaunch()
|
||||||
|
}
|
||||||
|
|
||||||
scenario = ActivityScenario.launch(startIntent)
|
scenario = ActivityScenario.launch(startIntent)
|
||||||
scenario.onActivity {
|
scenario.onActivity {
|
||||||
runBlocking {
|
testActivity = it
|
||||||
testApp = it.application as TestAppClass
|
afterLaunch()
|
||||||
beforeLaunch()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
afterLaunch()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun stubEndpoint(url: String, stub: Stubs) {
|
fun stubEndpoint(url: String, stub: Stubs) {
|
||||||
@@ -59,6 +67,8 @@ open class BaseTest<A : Activity>(
|
|||||||
testApp.removeUrlStub(url)
|
testApp.removeUrlStub(url)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun getActivity() = testActivity
|
||||||
|
|
||||||
@After
|
@After
|
||||||
fun tearDown() {
|
fun tearDown() {
|
||||||
testFinished()
|
testFinished()
|
||||||
@@ -67,4 +77,14 @@ open class BaseTest<A : Activity>(
|
|||||||
open fun beforeLaunch() {}
|
open fun beforeLaunch() {}
|
||||||
open fun afterLaunch() {}
|
open fun afterLaunch() {}
|
||||||
open fun testFinished() {}
|
open fun testFinished() {}
|
||||||
|
|
||||||
|
fun waitFor(delay: Long) {
|
||||||
|
Espresso.onView(ViewMatchers.isRoot()).perform(object : ViewAction {
|
||||||
|
override fun getConstraints(): Matcher<View> = ViewMatchers.isRoot()
|
||||||
|
override fun getDescription(): String = "wait for $delay milliseconds"
|
||||||
|
override fun perform(uiController: UiController, v: View?) {
|
||||||
|
uiController.loopMainThreadForAtLeast(delay)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
package com.appttude.h_mal.atlas_weather.data.location
|
package com.appttude.h_mal.atlas_weather.data.location
|
||||||
|
|
||||||
import com.appttude.h_mal.atlas_weather.data.location.LocationProvider
|
|
||||||
import com.appttude.h_mal.atlas_weather.model.types.LocationType
|
import com.appttude.h_mal.atlas_weather.model.types.LocationType
|
||||||
|
|
||||||
class MockLocationProvider : LocationProvider {
|
class MockLocationProvider : LocationProvider {
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import com.appttude.h_mal.atlas_weather.ui.MainActivity
|
|||||||
import com.appttude.h_mal.atlas_weather.utils.Stubs
|
import com.appttude.h_mal.atlas_weather.utils.Stubs
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
|
|
||||||
class HomePageUITest : BaseTest<MainActivity>(activity = MainActivity::class.java) {
|
class HomePageUITest : BaseTest<MainActivity>(MainActivity::class.java) {
|
||||||
|
|
||||||
override fun beforeLaunch() {
|
override fun beforeLaunch() {
|
||||||
stubEndpoint("https://api.openweathermap.org/data/2.5/onecall", Stubs.Valid)
|
stubEndpoint("https://api.openweathermap.org/data/2.5/onecall", Stubs.Valid)
|
||||||
@@ -16,6 +16,7 @@ class HomePageUITest : BaseTest<MainActivity>(activity = MainActivity::class.jav
|
|||||||
@Test
|
@Test
|
||||||
fun loadApp_validWeatherResponse_returnsValidPage() {
|
fun loadApp_validWeatherResponse_returnsValidPage() {
|
||||||
homeScreen {
|
homeScreen {
|
||||||
|
waitFor(2000)
|
||||||
verifyCurrentTemperature(2)
|
verifyCurrentTemperature(2)
|
||||||
verifyCurrentLocation("Mock Location")
|
verifyCurrentLocation("Mock Location")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools">
|
||||||
package="com.appttude.h_mal.atlas_weather"
|
|
||||||
tools:node="merge">
|
|
||||||
|
|
||||||
<application
|
<application
|
||||||
android:name="com.appttude.h_mal.atlas_weather.application.AppClass"
|
android:name="com.appttude.h_mal.atlas_weather.application.AppClass"
|
||||||
|
|||||||
@@ -1,55 +0,0 @@
|
|||||||
package com.appttude.h_mal.atlas_weather.ui
|
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
|
||||||
import android.content.pm.PackageManager
|
|
||||||
import android.view.View
|
|
||||||
import androidx.core.app.ActivityCompat
|
|
||||||
import androidx.fragment.app.Fragment
|
|
||||||
import androidx.lifecycle.Observer
|
|
||||||
import com.appttude.h_mal.atlas_weather.utils.Event
|
|
||||||
import com.appttude.h_mal.atlas_weather.utils.displayToast
|
|
||||||
import com.appttude.h_mal.atlas_weather.utils.hide
|
|
||||||
import com.appttude.h_mal.atlas_weather.utils.show
|
|
||||||
import kotlinx.coroutines.CoroutineScope
|
|
||||||
import kotlinx.coroutines.Dispatchers
|
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
|
|
||||||
abstract class BaseFragment: Fragment(){
|
|
||||||
|
|
||||||
// toggle visibility of progress spinner while async operations are taking place
|
|
||||||
fun progressBarStateObserver(progressBar: View) = Observer<Event<Boolean>> {
|
|
||||||
when(it.getContentIfNotHandled()){
|
|
||||||
true -> {
|
|
||||||
progressBar.show()
|
|
||||||
}
|
|
||||||
false -> {
|
|
||||||
progressBar.hide()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// display a toast when operation fails
|
|
||||||
fun errorObserver() = Observer<Event<String>> {
|
|
||||||
it.getContentIfNotHandled()?.let { message ->
|
|
||||||
displayToast(message)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressLint("MissingPermission")
|
|
||||||
fun getPermissionResult(
|
|
||||||
permission: String,
|
|
||||||
permissionCode: Int,
|
|
||||||
permissionGranted: () -> Unit
|
|
||||||
){
|
|
||||||
if (ActivityCompat.checkSelfPermission(requireContext(), permission) != PackageManager.PERMISSION_GRANTED) {
|
|
||||||
requestPermissions(arrayOf(permission), permissionCode)
|
|
||||||
return
|
|
||||||
}else{
|
|
||||||
CoroutineScope(Dispatchers.Main).launch{
|
|
||||||
permissionGranted.invoke()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
package com.appttude.h_mal.atlas_weather.ui.dialog
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.res.Resources
|
||||||
|
import android.os.Build
|
||||||
|
import android.text.Html
|
||||||
|
import androidx.annotation.RequiresApi
|
||||||
|
import androidx.annotation.StringRes
|
||||||
|
import androidx.core.content.ContextCompat
|
||||||
|
|
||||||
|
interface DeclarationBuilder{
|
||||||
|
val link: String
|
||||||
|
val message: String
|
||||||
|
|
||||||
|
fun Context.readFromResources(@StringRes id: Int) = resources.getString(id)
|
||||||
|
|
||||||
|
fun buildMessage(): CharSequence? {
|
||||||
|
val link1 = "<font color='blue'><a href=\"$link\">here</a></font>"
|
||||||
|
val message = "$message See my privacy policy: $link1"
|
||||||
|
return Html.fromHtml(message, Html.FROM_HTML_MODE_LEGACY)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
package com.appttude.h_mal.atlas_weather.ui.dialog
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.text.method.LinkMovementMethod
|
||||||
|
import android.view.View
|
||||||
|
import android.widget.TextView
|
||||||
|
import androidx.appcompat.app.AlertDialog
|
||||||
|
|
||||||
|
|
||||||
|
class PermissionsDeclarationDialog(context: Context) : BaseDeclarationDialog(context) {
|
||||||
|
|
||||||
|
override val link: String = "https://sites.google.com/view/hmaldev/home/monochrome"
|
||||||
|
override val message: String = "Hi, thank you for downloading my app. Google play isn't letting me upload my app to the Playstore until I have a privacy declaration :(. My app is basically used to demonstrate my code=ing to potential employers and others. I do NOT store or process any information. The location permission in the app is there just to provide the end user with weather data."
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class BaseDeclarationDialog(val context: Context): DeclarationBuilder {
|
||||||
|
abstract override val link: String
|
||||||
|
abstract override val message: String
|
||||||
|
|
||||||
|
lateinit var dialog: AlertDialog
|
||||||
|
|
||||||
|
fun showDialog(agreeCallback: () -> Unit = { }, disagreeCallback: () -> Unit = { }) {
|
||||||
|
val myMessage = buildMessage()
|
||||||
|
|
||||||
|
val builder = AlertDialog.Builder(context)
|
||||||
|
.setPositiveButton("agree") { _, _ ->
|
||||||
|
agreeCallback()
|
||||||
|
}
|
||||||
|
.setNegativeButton("disagree") { _, _ ->
|
||||||
|
disagreeCallback()
|
||||||
|
}
|
||||||
|
.setMessage(myMessage)
|
||||||
|
.setCancelable(false)
|
||||||
|
|
||||||
|
dialog = builder.create()
|
||||||
|
dialog.show()
|
||||||
|
|
||||||
|
// Make the textview clickable. Must be called after show()
|
||||||
|
val msgTxt = dialog.findViewById<View>(android.R.id.message) as TextView?
|
||||||
|
msgTxt?.movementMethod = LinkMovementMethod.getInstance()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun dismiss() = dialog.dismiss()
|
||||||
|
}
|
||||||
|
|
||||||
@@ -1,24 +1,27 @@
|
|||||||
package com.appttude.h_mal.atlas_weather.ui.home
|
package com.appttude.h_mal.atlas_weather.ui.home
|
||||||
|
|
||||||
import android.Manifest
|
import android.Manifest
|
||||||
|
import android.Manifest.permission.ACCESS_COARSE_LOCATION
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.content.pm.PackageManager
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.LayoutInflater
|
import android.view.Menu
|
||||||
|
import android.view.MenuInflater
|
||||||
|
import android.view.MenuItem
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import androidx.fragment.app.activityViewModels
|
import androidx.fragment.app.activityViewModels
|
||||||
import androidx.lifecycle.observe
|
import androidx.navigation.Navigation.findNavController
|
||||||
|
import androidx.navigation.ui.onNavDestinationSelected
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import com.appttude.h_mal.atlas_weather.R
|
import com.appttude.h_mal.atlas_weather.R
|
||||||
import com.appttude.h_mal.atlas_weather.application.LOCATION_PERMISSION_REQUEST
|
import com.appttude.h_mal.atlas_weather.application.LOCATION_PERMISSION_REQUEST
|
||||||
import com.appttude.h_mal.atlas_weather.ui.BaseFragment
|
import com.appttude.h_mal.atlas_weather.model.forecast.Forecast
|
||||||
|
import com.appttude.h_mal.atlas_weather.ui.dialog.PermissionsDeclarationDialog
|
||||||
import com.appttude.h_mal.atlas_weather.ui.home.adapter.WeatherRecyclerAdapter
|
import com.appttude.h_mal.atlas_weather.ui.home.adapter.WeatherRecyclerAdapter
|
||||||
import com.appttude.h_mal.atlas_weather.utils.displayToast
|
|
||||||
import com.appttude.h_mal.atlas_weather.utils.navigateTo
|
import com.appttude.h_mal.atlas_weather.utils.navigateTo
|
||||||
import com.appttude.h_mal.atlas_weather.viewmodel.ApplicationViewModelFactory
|
import com.appttude.h_mal.atlas_weather.viewmodel.ApplicationViewModelFactory
|
||||||
import com.appttude.h_mal.atlas_weather.viewmodel.MainViewModel
|
import com.appttude.h_mal.atlas_weather.viewmodel.MainViewModel
|
||||||
|
import com.appttude.h_mal.monoWeather.ui.BaseFragment
|
||||||
import kotlinx.android.synthetic.main.fragment_home.*
|
import kotlinx.android.synthetic.main.fragment_home.*
|
||||||
import org.kodein.di.KodeinAware
|
import org.kodein.di.KodeinAware
|
||||||
import org.kodein.di.android.x.kodein
|
import org.kodein.di.android.x.kodein
|
||||||
@@ -30,43 +33,29 @@ import org.kodein.di.generic.instance
|
|||||||
* A simple [Fragment] subclass.
|
* A simple [Fragment] subclass.
|
||||||
* create an instance of this fragment.
|
* create an instance of this fragment.
|
||||||
*/
|
*/
|
||||||
class HomeFragment : BaseFragment(), KodeinAware {
|
class HomeFragment : BaseFragment(R.layout.fragment_home) {
|
||||||
override val kodein by kodein()
|
private val viewModel by getFragmentViewModel<MainViewModel>()
|
||||||
private val factory by instance<ApplicationViewModelFactory>()
|
|
||||||
|
|
||||||
private val viewModel by activityViewModels<MainViewModel> { factory }
|
|
||||||
|
|
||||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
|
|
||||||
savedInstanceState: Bundle?): View? {
|
|
||||||
// Inflate the layout for this fragment
|
|
||||||
return inflater.inflate(R.layout.fragment_home, container, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressLint("MissingPermission")
|
@SuppressLint("MissingPermission")
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
setHasOptionsMenu(true)
|
||||||
|
|
||||||
val recyclerAdapter = WeatherRecyclerAdapter {
|
val recyclerAdapter = WeatherRecyclerAdapter(itemClick = {
|
||||||
val directions =
|
navigateToFurtherDetails(it)
|
||||||
HomeFragmentDirections.actionHomeFragmentToFurtherDetailsFragment(it)
|
})
|
||||||
navigateTo(directions)
|
|
||||||
}
|
|
||||||
|
|
||||||
forecast_listview.apply {
|
forecast_listview.apply {
|
||||||
layoutManager = LinearLayoutManager(context)
|
layoutManager = LinearLayoutManager(context)
|
||||||
adapter = recyclerAdapter
|
adapter = recyclerAdapter
|
||||||
}
|
}
|
||||||
|
|
||||||
getPermissionResult(Manifest.permission.ACCESS_FINE_LOCATION, LOCATION_PERMISSION_REQUEST){
|
|
||||||
viewModel.fetchData()
|
|
||||||
}
|
|
||||||
|
|
||||||
swipe_refresh.apply {
|
swipe_refresh.apply {
|
||||||
setOnRefreshListener {
|
setOnRefreshListener {
|
||||||
getPermissionResult(Manifest.permission.ACCESS_FINE_LOCATION, LOCATION_PERMISSION_REQUEST){
|
getPermissionResult(ACCESS_COARSE_LOCATION, LOCATION_PERMISSION_REQUEST) {
|
||||||
viewModel.fetchData()
|
viewModel.fetchData()
|
||||||
|
isRefreshing = true
|
||||||
}
|
}
|
||||||
isRefreshing = true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -76,24 +65,45 @@ class HomeFragment : BaseFragment(), KodeinAware {
|
|||||||
|
|
||||||
viewModel.operationState.observe(viewLifecycleOwner, progressBarStateObserver(progressBar))
|
viewModel.operationState.observe(viewLifecycleOwner, progressBarStateObserver(progressBar))
|
||||||
viewModel.operationError.observe(viewLifecycleOwner, errorObserver())
|
viewModel.operationError.observe(viewLifecycleOwner, errorObserver())
|
||||||
|
viewModel.operationRefresh.observe(viewLifecycleOwner) { it ->
|
||||||
|
it.getContentIfNotHandled()?.let {
|
||||||
|
swipe_refresh.isRefreshing = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
viewModel.operationState.observe(viewLifecycleOwner){
|
viewModel.operationState.observe(viewLifecycleOwner) {
|
||||||
swipe_refresh.isRefreshing = false
|
swipe_refresh.isRefreshing = false
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressLint("MissingPermission")
|
@SuppressLint("MissingPermission")
|
||||||
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String?>, grantResults: IntArray) {
|
override fun onStart() {
|
||||||
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
|
super.onStart()
|
||||||
if (requestCode == LOCATION_PERMISSION_REQUEST) {
|
|
||||||
if (grantResults.isNotEmpty()
|
getPermissionResult(ACCESS_COARSE_LOCATION, LOCATION_PERMISSION_REQUEST) {
|
||||||
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
|
viewModel.fetchData()
|
||||||
viewModel.fetchData()
|
|
||||||
displayToast("Permission granted")
|
|
||||||
} else {
|
|
||||||
displayToast("Permission denied")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressLint("MissingPermission")
|
||||||
|
override fun permissionsGranted() {
|
||||||
|
viewModel.fetchData()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun navigateToFurtherDetails(forecast: Forecast) {
|
||||||
|
val directions = HomeFragmentDirections
|
||||||
|
.actionHomeFragmentToFurtherDetailsFragment(forecast)
|
||||||
|
navigateTo(directions)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
||||||
|
// Inflate the menu; this adds items to the action bar if it is present.
|
||||||
|
inflater.inflate(R.menu.menu_main, menu)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||||
|
val navController = findNavController(requireActivity(), R.id.container)
|
||||||
|
return item.onNavDestinationSelected(navController) || super.onOptionsItemSelected(item)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -17,7 +17,7 @@ class ViewHolderCurrent(listItemView: View) : RecyclerView.ViewHolder(listItemVi
|
|||||||
var tempUnit: TextView = listItemView.findViewById(R.id.temp_unit_4)
|
var tempUnit: TextView = listItemView.findViewById(R.id.temp_unit_4)
|
||||||
|
|
||||||
fun bindData(weather: WeatherDisplay?){
|
fun bindData(weather: WeatherDisplay?){
|
||||||
locationTV.text = weather?.location
|
locationTV.text = weather?.displayName
|
||||||
conditionTV.text = weather?.description
|
conditionTV.text = weather?.description
|
||||||
weatherIV.loadImage(weather?.iconURL)
|
weatherIV.loadImage(weather?.iconURL)
|
||||||
avgTempTV.text = weather?.averageTemp?.toInt().toString()
|
avgTempTV.text = weather?.averageTemp?.toInt().toString()
|
||||||
|
|||||||
@@ -7,28 +7,20 @@ import android.view.ViewGroup
|
|||||||
import androidx.fragment.app.viewModels
|
import androidx.fragment.app.viewModels
|
||||||
import androidx.lifecycle.observe
|
import androidx.lifecycle.observe
|
||||||
import com.appttude.h_mal.atlas_weather.R
|
import com.appttude.h_mal.atlas_weather.R
|
||||||
import com.appttude.h_mal.atlas_weather.ui.BaseFragment
|
|
||||||
import com.appttude.h_mal.atlas_weather.utils.displayToast
|
import com.appttude.h_mal.atlas_weather.utils.displayToast
|
||||||
import com.appttude.h_mal.atlas_weather.utils.goBack
|
import com.appttude.h_mal.atlas_weather.utils.goBack
|
||||||
import com.appttude.h_mal.atlas_weather.viewmodel.ApplicationViewModelFactory
|
import com.appttude.h_mal.atlas_weather.viewmodel.ApplicationViewModelFactory
|
||||||
import com.appttude.h_mal.atlas_weather.viewmodel.WorldViewModel
|
import com.appttude.h_mal.atlas_weather.viewmodel.WorldViewModel
|
||||||
|
import com.appttude.h_mal.monoWeather.ui.BaseFragment
|
||||||
import kotlinx.android.synthetic.main.activity_add_forecast.*
|
import kotlinx.android.synthetic.main.activity_add_forecast.*
|
||||||
import org.kodein.di.KodeinAware
|
import org.kodein.di.KodeinAware
|
||||||
import org.kodein.di.android.x.kodein
|
import org.kodein.di.android.x.kodein
|
||||||
import org.kodein.di.generic.instance
|
import org.kodein.di.generic.instance
|
||||||
|
|
||||||
|
|
||||||
class AddLocationFragment : BaseFragment(), KodeinAware {
|
class AddLocationFragment : BaseFragment(R.layout.activity_add_forecast) {
|
||||||
override val kodein by kodein()
|
|
||||||
private val factory by instance<ApplicationViewModelFactory>()
|
|
||||||
|
|
||||||
private val viewModel by viewModels<WorldViewModel> { factory }
|
private val viewModel by getFragmentViewModel<WorldViewModel>()
|
||||||
|
|
||||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
|
|
||||||
savedInstanceState: Bundle?): View? {
|
|
||||||
// Inflate the layout for this fragment
|
|
||||||
return inflater.inflate(R.layout.activity_add_forecast, container, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
|||||||
@@ -9,12 +9,10 @@ import androidx.fragment.app.viewModels
|
|||||||
import androidx.lifecycle.observe
|
import androidx.lifecycle.observe
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import com.appttude.h_mal.atlas_weather.R
|
import com.appttude.h_mal.atlas_weather.R
|
||||||
import com.appttude.h_mal.atlas_weather.ui.world.WorldRecyclerAdapter
|
|
||||||
import com.appttude.h_mal.atlas_weather.ui.BaseFragment
|
|
||||||
import com.appttude.h_mal.atlas_weather.ui.world.WorldFragmentDirections
|
|
||||||
import com.appttude.h_mal.atlas_weather.utils.navigateTo
|
import com.appttude.h_mal.atlas_weather.utils.navigateTo
|
||||||
import com.appttude.h_mal.atlas_weather.viewmodel.ApplicationViewModelFactory
|
import com.appttude.h_mal.atlas_weather.viewmodel.ApplicationViewModelFactory
|
||||||
import com.appttude.h_mal.atlas_weather.viewmodel.WorldViewModel
|
import com.appttude.h_mal.atlas_weather.viewmodel.WorldViewModel
|
||||||
|
import com.appttude.h_mal.monoWeather.ui.BaseFragment
|
||||||
import kotlinx.android.synthetic.main.fragment_add_location.*
|
import kotlinx.android.synthetic.main.fragment_add_location.*
|
||||||
import org.kodein.di.KodeinAware
|
import org.kodein.di.KodeinAware
|
||||||
import org.kodein.di.android.x.kodein
|
import org.kodein.di.android.x.kodein
|
||||||
@@ -25,17 +23,8 @@ import org.kodein.di.generic.instance
|
|||||||
* A simple [Fragment] subclass.
|
* A simple [Fragment] subclass.
|
||||||
* create an instance of this fragment.
|
* create an instance of this fragment.
|
||||||
*/
|
*/
|
||||||
class WorldFragment : BaseFragment(), KodeinAware {
|
class WorldFragment : BaseFragment(R.layout.fragment_add_location) {
|
||||||
override val kodein by kodein()
|
val viewModel by getFragmentViewModel<WorldViewModel>()
|
||||||
private val factory by instance<ApplicationViewModelFactory>()
|
|
||||||
|
|
||||||
val viewModel by viewModels<WorldViewModel> { factory }
|
|
||||||
|
|
||||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
|
|
||||||
savedInstanceState: Bundle?): View? {
|
|
||||||
// Inflate the layout for this fragment
|
|
||||||
return inflater.inflate(R.layout.fragment_add_location, container, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
|||||||
10
app/src/atlasWeather/res/drawable/gradient.xml
Normal file
10
app/src/atlasWeather/res/drawable/gradient.xml
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:shape="rectangle">
|
||||||
|
<gradient
|
||||||
|
android:startColor="@color/colour_two"
|
||||||
|
android:centerColor="@color/colour_three"
|
||||||
|
android:endColor="@color/colour_four"
|
||||||
|
android:type="linear"
|
||||||
|
android:angle="45"/>
|
||||||
|
</shape>
|
||||||
BIN
app/src/atlasWeather/res/font/archeologicaps.ttf
Normal file
BIN
app/src/atlasWeather/res/font/archeologicaps.ttf
Normal file
Binary file not shown.
@@ -76,7 +76,7 @@
|
|||||||
android:id="@+id/icon_main_4"
|
android:id="@+id/icon_main_4"
|
||||||
android:layout_width="64dp"
|
android:layout_width="64dp"
|
||||||
android:layout_height="64dp"
|
android:layout_height="64dp"
|
||||||
tools:src="@drawable/day_305" />
|
tools:srcCompat="@drawable/water_drop" />
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
|
|||||||
@@ -48,7 +48,9 @@
|
|||||||
android:id="@+id/list_icon"
|
android:id="@+id/list_icon"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
tools:src="@drawable/day_305" />
|
android:adjustViewBounds="true"
|
||||||
|
tools:layout_width="32dp"
|
||||||
|
tools:srcCompat="@drawable/water_drop" />
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
|
|||||||
@@ -55,4 +55,8 @@
|
|||||||
app:argType="com.appttude.h_mal.atlas_weather.model.forecast.WeatherDisplay" />
|
app:argType="com.appttude.h_mal.atlas_weather.model.forecast.WeatherDisplay" />
|
||||||
</fragment>
|
</fragment>
|
||||||
|
|
||||||
|
<fragment
|
||||||
|
android:id="@+id/settings_fragment"
|
||||||
|
android:name="com.appttude.h_mal.atlas_weather.ui.settings.SettingsFragment"
|
||||||
|
android:label="SettingsFragment" />
|
||||||
</navigation>
|
</navigation>
|
||||||
12
app/src/atlasWeather/res/values/colors.xml
Normal file
12
app/src/atlasWeather/res/values/colors.xml
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<color name="colorPrimary">#3F51B5</color>
|
||||||
|
<color name="colorPrimaryDark">#303F9F</color>
|
||||||
|
<color name="colorAccent">#FF4081</color>
|
||||||
|
|
||||||
|
<color name="colour_one">#E8D0DD</color>
|
||||||
|
<color name="colour_two">#5F8E7B</color>
|
||||||
|
<color name="colour_three">#B3C0CA</color>
|
||||||
|
<color name="colour_four">#8C98AD</color>
|
||||||
|
<color name="colour_five">#2E3532</color>
|
||||||
|
</resources>
|
||||||
@@ -3,24 +3,27 @@
|
|||||||
<!-- Base application theme. -->
|
<!-- Base application theme. -->
|
||||||
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
|
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
|
||||||
<!-- Customize your theme here. -->
|
<!-- Customize your theme here. -->
|
||||||
<item name="colorPrimary">@android:color/black</item>
|
<item name="colorPrimary">@android:color/transparent</item>
|
||||||
<item name="colorPrimaryDark">@color/colour_four</item>
|
<item name="colorPrimaryDark">@color/colour_four</item>
|
||||||
<item name="colorAccent">@color/colour_one</item>
|
<item name="colorAccent">@color/colour_one</item>
|
||||||
|
<item name="android:windowBackground">@drawable/gradient</item>
|
||||||
<item name="fontFamily">sans-serif-light</item>
|
<item name="fontFamily">sans-serif-light</item>
|
||||||
<item name="android:textColor">@color/colorAccent</item>
|
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<style name="AppTheme.NoActionBar">
|
<style name="AppTheme.NoActionBar">
|
||||||
<item name="windowActionBar">false</item>
|
<item name="windowActionBar">false</item>
|
||||||
<item name="windowNoTitle">true</item>
|
<item name="windowNoTitle">true</item>
|
||||||
|
<item name="android:windowBackground">@drawable/gradient</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
|
||||||
<style name="TextAppearance.AppCompat.Widget.ActionBar.Title" parent="@android:style/TextAppearance">
|
<style name="TextAppearance.AppCompat.Widget.ActionBar.Title" parent="@android:style/TextAppearance">
|
||||||
|
<item name="android:fontFamily">@font/archeologicaps</item>
|
||||||
<!--<item name="android:textColor">@color/colour_five</item>-->
|
<!--<item name="android:textColor">@color/colour_five</item>-->
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<style name="titlebar" parent="@android:style/TextAppearance">
|
<style name="titlebar" parent="@android:style/TextAppearance">
|
||||||
|
<item name="android:fontFamily">@font/archeologicaps</item>
|
||||||
<!--<item name="android:textColor">@color/colour_five</item>-->
|
<!--<item name="android:textColor">@color/colour_five</item>-->
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
@@ -42,12 +45,4 @@
|
|||||||
<item name="android:textSize">32sp</item>
|
<item name="android:textSize">32sp</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<style name="icon_style__further_deatils">
|
</resources>
|
||||||
<item name="android:layout_width">64dp</item>
|
|
||||||
<item name="android:layout_height">64dp</item>
|
|
||||||
<item name="android:adjustViewBounds">true</item>
|
|
||||||
<item name="android:layout_gravity">center</item>
|
|
||||||
<item name="android:tint">@color/colorAccent</item>
|
|
||||||
</style>
|
|
||||||
|
|
||||||
</resources>
|
|
||||||
@@ -7,6 +7,8 @@
|
|||||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||||
<uses-permission android:name="android.permission.INTERNET" />
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
<uses-permission android:name="com.android.alarm.permission.SET_ALARM" />
|
<uses-permission android:name="com.android.alarm.permission.SET_ALARM" />
|
||||||
|
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
||||||
|
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
|
||||||
|
|
||||||
<application android:networkSecurityConfig="@xml/network_security_config" />
|
<application android:networkSecurityConfig="@xml/network_security_config" />
|
||||||
|
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ import kotlin.coroutines.suspendCoroutine
|
|||||||
|
|
||||||
class LocationProviderImpl(
|
class LocationProviderImpl(
|
||||||
private val applicationContext: Context
|
private val applicationContext: Context
|
||||||
) : com.appttude.h_mal.atlas_weather.data.location.LocationProvider, com.appttude.h_mal.atlas_weather.data.location.LocationHelper(applicationContext) {
|
) : LocationProvider, LocationHelper(applicationContext) {
|
||||||
private var locationManager =
|
private var locationManager =
|
||||||
applicationContext.getSystemService(Context.LOCATION_SERVICE) as LocationManager?
|
applicationContext.getSystemService(Context.LOCATION_SERVICE) as LocationManager?
|
||||||
private val client = FusedLocationProviderClient(applicationContext)
|
private val client = FusedLocationProviderClient(applicationContext)
|
||||||
|
|||||||
@@ -26,7 +26,7 @@
|
|||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:background="@android:color/black"
|
android:background="@android:color/black"
|
||||||
android:visibility="gone"
|
android:visibility="gone"
|
||||||
tools:visibility="visible">
|
tools:visibility="gone">
|
||||||
<ProgressBar
|
<ProgressBar
|
||||||
android:layout_gravity="center"
|
android:layout_gravity="center"
|
||||||
style="?android:attr/progressBarStyle"
|
style="?android:attr/progressBarStyle"
|
||||||
|
|||||||
@@ -27,4 +27,12 @@
|
|||||||
<item name="android:textColor">#ffffff</item>
|
<item name="android:textColor">#ffffff</item>
|
||||||
<item name="android:textSize">12sp</item>
|
<item name="android:textSize">12sp</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
<style name="icon_style__further_deatils">
|
||||||
|
<item name="android:layout_width">48dp</item>
|
||||||
|
<item name="android:layout_height">48dp</item>
|
||||||
|
<item name="android:adjustViewBounds">true</item>
|
||||||
|
<item name="android:layout_gravity">center</item>
|
||||||
|
<item name="android:tint">@color/colorAccent</item>
|
||||||
|
</style>
|
||||||
</resources>
|
</resources>
|
||||||
@@ -2,9 +2,6 @@
|
|||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:tools="http://schemas.android.com/tools">
|
xmlns:tools="http://schemas.android.com/tools">
|
||||||
|
|
||||||
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
|
||||||
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
|
|
||||||
|
|
||||||
<application
|
<application
|
||||||
android:name="com.appttude.h_mal.atlas_weather.application.AppClass"
|
android:name="com.appttude.h_mal.atlas_weather.application.AppClass"
|
||||||
android:allowBackup="true"
|
android:allowBackup="true"
|
||||||
|
|||||||
@@ -66,12 +66,4 @@
|
|||||||
<item name="android:textSize">32sp</item>
|
<item name="android:textSize">32sp</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<style name="icon_style__further_deatils">
|
|
||||||
<item name="android:layout_width">48dp</item>
|
|
||||||
<item name="android:layout_height">48dp</item>
|
|
||||||
<item name="android:adjustViewBounds">true</item>
|
|
||||||
<item name="android:layout_gravity">center</item>
|
|
||||||
<item name="android:tint">@color/colorAccent</item>
|
|
||||||
</style>
|
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -1,2 +0,0 @@
|
|||||||
json_key_file("") # Path to the json secret file - Follow https://docs.fastlane.tools/actions/supply/#setup to get one
|
|
||||||
package_name("") # e.g. com.krausefx.app
|
|
||||||
@@ -16,23 +16,30 @@
|
|||||||
default_platform(:android)
|
default_platform(:android)
|
||||||
|
|
||||||
platform :android do
|
platform :android do
|
||||||
desc "Runs all the tests"
|
|
||||||
lane :test do
|
desc "Deploy a new Mono Weather version to the Google Play"
|
||||||
gradle(task: "test")
|
lane :deployMono do
|
||||||
|
gradle(
|
||||||
|
task: "clean bundle",
|
||||||
|
flavor: "MonoWeather",
|
||||||
|
build_type: "Release",
|
||||||
|
)
|
||||||
|
upload_to_play_store(
|
||||||
|
aab: "app/build/outputs/bundle/monoWeather/app-driver-release.aab",
|
||||||
|
json_key: "google-play-key.json",
|
||||||
|
package_name: "h_mal.appttude.com.monoWeather")
|
||||||
end
|
end
|
||||||
|
|
||||||
desc "Submit a new Beta Build to Crashlytics Beta"
|
desc "Deploy a new Atlas Weather version to the Google Play"
|
||||||
lane :beta do
|
lane :deployMono do
|
||||||
gradle(task: "clean assembleRelease")
|
gradle(
|
||||||
crashlytics
|
task: "clean bundle",
|
||||||
|
flavor: "AtlasWeather",
|
||||||
# sh "your_script.sh"
|
build_type: "Release",
|
||||||
# You can also use other beta testing services here
|
)
|
||||||
end
|
upload_to_play_store(
|
||||||
|
aab: "app/build/outputs/bundle/atlasWeather/app-driver-release.aab",
|
||||||
desc "Deploy a new version to the Google Play"
|
json_key: "google-play-key.json",
|
||||||
lane :deploy do
|
package_name: "h_mal.appttude.com.monoWeather")
|
||||||
gradle(task: "clean assembleRelease")
|
|
||||||
upload_to_play_store
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
Reference in New Issue
Block a user