Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 204c625e authored by Amit Kumar's avatar Amit Kumar 💻
Browse files

Add random city array and fix issue with location picking with map

parent cee5f827
Loading
Loading
Loading
Loading
Loading
+65 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2021 E FOUNDATION
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */

package foundation.e.privacycentralapp.dummy

import kotlin.random.Random

data class City(val name: String, val latitude: Double, val longitude: Double) {

    fun toRandomLocation(): Location {
        return Location(LocationMode.RANDOM_LOCATION, this.latitude, this.longitude)
    }
}

object CityDataSource {
    private val BARCELONA = Pair(41.3851, 2.1734)
    private val BUDAPEST = Pair(47.4979, 19.0402)
    private val ABU_DHABI = Pair(24.4539, 54.3773)
    private val HYDERABAD = Pair(17.3850, 78.4867)
    private val QUEZON_CITY = Pair(14.6760, 121.0437)
    private val PARIS = Pair(48.8566, 2.3522)
    private val LONDON = Pair(51.5074, 0.1278)
    private val SHANGHAI = Pair(31.2304, 121.4737)
    private val MADRID = Pair(40.4168, 3.7038)
    private val LAHORE = Pair(31.5204, 74.3587)
    private val CHICAGO = Pair(41.8781, 87.6298)

    // LatLong Array, the order should be the same as that of R.array.cities
    private val latLongArray = arrayOf(
        BARCELONA,
        BUDAPEST,
        ABU_DHABI,
        HYDERABAD,
        QUEZON_CITY,
        PARIS,
        LONDON,
        SHANGHAI,
        MADRID,
        LAHORE,
        CHICAGO
    )

    fun getRandomCity(cities: Array<String>): City {
        if (cities.size != latLongArray.size) {
            throw IllegalStateException("LatLong array must have the same number of element as in cities array.")
        }
        val randomIndex = Random.nextInt(cities.size)
        val latLong = latLongArray[randomIndex]
        return City(cities[randomIndex], latLong.first, latLong.second)
    }
}
+4 −1
Original line number Diff line number Diff line
@@ -185,7 +185,10 @@ object DummyDataSource {
            LocationMode.REAL_LOCATION ->
                _location.value =
                    Location(LocationMode.REAL_LOCATION, 24.39, 71.80)
            LocationMode.RANDOM_LOCATION -> _location.value = randomLocation()
            LocationMode.RANDOM_LOCATION -> {
                requireNotNull(location) { "Custom location should be null" }
                _location.value = location
            }
            LocationMode.CUSTOM_LOCATION -> {
                requireNotNull(location) { "Custom location should be null" }
                _location.value = location.copy(mode = LocationMode.CUSTOM_LOCATION)
+70 −23
Original line number Diff line number Diff line
@@ -18,16 +18,17 @@
package foundation.e.privacycentralapp.features.location

import android.util.Log
import com.mapbox.mapboxsdk.geometry.LatLng
import foundation.e.flowmvi.Actor
import foundation.e.flowmvi.Reducer
import foundation.e.flowmvi.SingleEventProducer
import foundation.e.flowmvi.feature.BaseFeature
import foundation.e.privacycentralapp.dummy.CityDataSource
import foundation.e.privacycentralapp.dummy.DummyDataSource
import foundation.e.privacycentralapp.dummy.Location
import foundation.e.privacycentralapp.dummy.LocationMode
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.map

// Define a state machine for Fake location feature
class FakeLocationFeature(
@@ -44,10 +45,7 @@ class FakeLocationFeature(
    { message -> Log.d("FakeLocationFeature", message) },
    singleEventProducer
) {
    sealed class State {
        object InitialState : State()
        data class LocationState(val location: Location) : State()
    }
    data class State(val location: Location)

    sealed class SingleEvent {
        object RandomLocationSelectedEvent : SingleEvent()
@@ -57,47 +55,91 @@ class FakeLocationFeature(
    }

    sealed class Action {
        object ObserveLocationAction : Action()
        data class UpdateLocationAction(val latLng: LatLng) : Action()
        object UseRealLocationAction : Action()
        object UseRandomLocationAction : Action()
        data class UseRandomLocationAction(val cities: Array<String>) : Action() {
            override fun equals(other: Any?): Boolean {
                if (this === other) return true
                if (javaClass != other?.javaClass) return false

                other as UseRandomLocationAction

                if (!cities.contentEquals(other.cities)) return false

                return true
            }

            override fun hashCode(): Int {
                return cities.contentHashCode()
            }
        }

        object UseSpecificLocationAction : Action()
        data class AddSpecificLocationAction(val latitude: Double, val longitude: Double) : Action()
        data class SetFakeLocationAction(val latitude: Double, val longitude: Double) : Action()
    }

    sealed class Effect {
        data class LocationUpdatedEffect(val location: Location) : Effect()
        data class LocationUpdatedEffect(val latitude: Double, val longitude: Double) : Effect()
        object RealLocationSelectedEffect : Effect()
        object RandomLocationSelectedEffect : Effect()
        data class SpecificLocationSelectedEffect(val location: Location) : Effect()
        object SpecificLocationSelectedEffect : Effect()
        object SpecificLocationSavedEffect : Effect()
        data class ErrorEffect(val message: String) : Effect()
    }

    companion object {
        fun create(
            initialState: State = State.InitialState,
            initialState: State = State(
                Location(
                    LocationMode.REAL_LOCATION,
                    0.0,
                    0.0
                )
            ),
            coroutineScope: CoroutineScope
        ) = FakeLocationFeature(
            initialState, coroutineScope,
            reducer = { state, effect ->
                when (effect) {
                    Effect.RandomLocationSelectedEffect,
                    Effect.RealLocationSelectedEffect, is Effect.ErrorEffect, Effect.SpecificLocationSavedEffect -> state
                    is Effect.LocationUpdatedEffect -> State.LocationState(effect.location)
                    is Effect.SpecificLocationSelectedEffect -> State.LocationState(effect.location)
                    Effect.RandomLocationSelectedEffect -> state.copy(
                        location = state.location.copy(
                            mode = LocationMode.RANDOM_LOCATION
                        )
                    )
                    Effect.RealLocationSelectedEffect -> state.copy(
                        location = state.location.copy(
                            mode = LocationMode.REAL_LOCATION
                        )
                    )
                    is Effect.ErrorEffect, Effect.SpecificLocationSavedEffect -> state
                    is Effect.LocationUpdatedEffect -> state.copy(
                        location = state.location.copy(
                            latitude = effect.latitude,
                            longitude = effect.longitude
                        )
                    )
                    is Effect.SpecificLocationSelectedEffect -> state.copy(
                        location = state.location.copy(
                            mode = LocationMode.CUSTOM_LOCATION
                        )
                    )
                }
            },
            actor = { _, action ->
                when (action) {
                    is Action.ObserveLocationAction -> DummyDataSource.location.map {
                        Effect.LocationUpdatedEffect(it)
                    }
                    is Action.AddSpecificLocationAction -> {
                    is Action.UpdateLocationAction -> flowOf(
                        Effect.LocationUpdatedEffect(
                            action.latLng.latitude,
                            action.latLng.longitude
                        )
                    )
                    is Action.SetFakeLocationAction -> {
                        val location = Location(
                            LocationMode.CUSTOM_LOCATION,
                            action.latitude,
                            action.longitude
                        )
                        // TODO: Call fake location api with specific coordinates here.
                        val success = DummyDataSource.setLocationMode(
                            LocationMode.CUSTOM_LOCATION,
                            location
@@ -112,8 +154,13 @@ class FakeLocationFeature(
                            )
                        }
                    }
                    Action.UseRandomLocationAction -> {
                        val success = DummyDataSource.setLocationMode(LocationMode.RANDOM_LOCATION)
                    is Action.UseRandomLocationAction -> {
                        val randomCity = CityDataSource.getRandomCity(action.cities)
                        // TODO: Call fake location api with random location here.
                        val success = DummyDataSource.setLocationMode(
                            LocationMode.RANDOM_LOCATION,
                            randomCity.toRandomLocation()
                        )
                        if (success) {
                            flowOf(
                                Effect.RandomLocationSelectedEffect
@@ -125,6 +172,7 @@ class FakeLocationFeature(
                        }
                    }
                    Action.UseRealLocationAction -> {
                        // TODO: Call turn off fake location api here.
                        val success = DummyDataSource.setLocationMode(LocationMode.REAL_LOCATION)
                        if (success) {
                            flowOf(
@@ -137,8 +185,7 @@ class FakeLocationFeature(
                        }
                    }
                    Action.UseSpecificLocationAction -> {
                        val location = DummyDataSource.location.value
                        flowOf(Effect.SpecificLocationSelectedEffect(location.copy(mode = LocationMode.CUSTOM_LOCATION)))
                        flowOf(Effect.SpecificLocationSelectedEffect)
                    }
                }
            },
+163 −113

File changed.

Preview size limit exceeded, changes collapsed.

+33 −42
Original line number Diff line number Diff line
@@ -3,30 +3,30 @@
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:mapbox="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/white"
    android:layout_height="match_parent"
    android:layout_width="match_parent"
    >

    <Toolbar
        android:background="@color/white"
        android:id="@+id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="?android:attr/actionBarSize"
        android:layout_gravity="top|center"
        android:background="@color/white"
        android:layout_height="?android:attr/actionBarSize"
        android:layout_width="match_parent"
        tools:layout_height="56dp"
        />

    <androidx.core.widget.NestedScrollView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_marginTop="?android:attr/actionBarSize"
        android:layout_marginBottom="32dp"
        android:layout_marginTop="?android:attr/actionBarSize"
        android:layout_width="match_parent"
        >

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_width="match_parent"
            android:orientation="vertical"
            android:paddingLeft="32dp"
            android:paddingRight="32dp"
@@ -35,9 +35,9 @@

            <TextView
                android:id="@+id/fake_location_info"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_gravity="center_horizontal"
                android:layout_height="wrap_content"
                android:layout_width="match_parent"
                android:paddingTop="16dp"
                android:text="@string/fake_location_info"
                android:textColor="@color/black"
@@ -45,23 +45,23 @@
                />

            <TextView
                android:id="@+id/learn_more_fake_location"
                android:layout_width="wrap_content"
                android:layout_height="48dp"
                android:fontFamily="sans-serif-medium"
                android:gravity="center_vertical"
                android:id="@+id/learn_more_fake_location"
                android:layout_height="48dp"
                android:layout_width="wrap_content"
                android:text="@string/learn_more"
                android:textColor="#007fff"
                android:textSize="14sp"
                />

            <TextView
                android:fontFamily="sans-serif-medium"
                android:id="@+id/my_location_header"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:fontFamily="sans-serif-medium"
                android:paddingTop="16dp"
                android:layout_width="wrap_content"
                android:paddingBottom="8dp"
                android:paddingTop="16dp"
                android:text="@string/my_location_title"
                android:textColor="@color/black"
                android:textSize="14sp"
@@ -69,31 +69,31 @@

            <RadioGroup
                android:id="@+id/location_choices"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_width="match_parent"
                android:orientation="vertical"
                >

                <foundation.e.privacycentralapp.common.RightRadioButton
                    android:id="@+id/radio_use_real_location"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_width="match_parent"
                    android:text="@string/use_real_location"
                    android:textSize="16sp"
                    />

                <foundation.e.privacycentralapp.common.RightRadioButton
                    android:id="@+id/radio_use_random_location"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_width="match_parent"
                    android:text="@string/use_random_location"
                    android:textSize="16sp"
                    />

                <foundation.e.privacycentralapp.common.RightRadioButton
                    android:id="@+id/radio_use_specific_location"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_width="match_parent"
                    android:text="@string/use_specific_location"
                    android:textSize="16sp"
                    />
@@ -102,53 +102,44 @@

            <foundation.e.privacycentralapp.features.location.FakeLocationMapView
                android:id="@+id/mapView"
                android:layout_width="match_parent"
                android:layout_height="240dp"
                mapbox:mapbox_cameraZoom="15"
                android:layout_marginTop="32dp"
                android:layout_marginBottom="32dp"
                android:layout_marginTop="32dp"
                android:layout_width="match_parent"
                mapbox:mapbox_cameraZoom="8"
                />

            <com.google.android.material.textfield.TextInputLayout
                android:id="@+id/edittext_longitude"
                style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:hint="@string/longitude"
                android:id="@+id/edittext_longitude"
                android:layout_height="wrap_content"
                android:layout_width="match_parent"
                >

                <com.google.android.material.textfield.TextInputEditText
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:inputType="numberDecimal"
                    android:layout_height="wrap_content"
                    android:layout_width="match_parent"
                    />
            </com.google.android.material.textfield.TextInputLayout>

            <com.google.android.material.textfield.TextInputLayout
                android:id="@+id/edittext_latitude"
                style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
                android:layout_width="match_parent"
                android:hint="@string/latitude"
                android:id="@+id/edittext_latitude"
                android:layout_height="wrap_content"
                android:layout_marginTop="16dp"
                android:hint="@string/latitude"
                android:layout_width="match_parent"
                >

                <com.google.android.material.textfield.TextInputEditText
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:inputType="numberDecimal"
                    android:layout_height="wrap_content"
                    android:layout_width="match_parent"
                    />
            </com.google.android.material.textfield.TextInputLayout>

            <Button
                android:id="@+id/button_add_location"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="center_horizontal"
                android:layout_marginTop="32dp"
                android:text="@string/add_location"
                app:backgroundTint="#007fff"
                />
        </LinearLayout>
    </androidx.core.widget.NestedScrollView>
</FrameLayout>
 No newline at end of file
Loading