├── .gitignore
├── .idea
├── .gitignore
├── .name
├── codeStyles
│ └── Project.xml
├── compiler.xml
├── deploymentTargetDropDown.xml
├── encodings.xml
├── gradle.xml
├── jarRepositories.xml
├── jpa-buddy.xml
├── misc.xml
└── vcs.xml
├── LICENSE
├── README.md
├── Screenshot.png
├── app
├── .gitignore
├── build.gradle
├── libs
│ └── solarpositioning.jar
├── proguard-rules.pro
├── release
│ └── app-release.aab
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── ic_launcher-web.png
│ ├── java
│ └── com
│ │ └── genewarrior
│ │ └── daynightmap
│ │ ├── MainActivity.java
│ │ ├── Status.java
│ │ ├── SunNavigationView.java
│ │ ├── SunSeekBar.java
│ │ ├── Widget
│ │ └── DayNightWidget.java
│ │ └── ui
│ │ ├── daynight
│ │ ├── DayNightFragment.java
│ │ └── DayNightHelper.java
│ │ └── help
│ │ └── HelpFragment.java
│ ├── res
│ ├── drawable-nodpi
│ │ ├── daynight_widget_preview.png
│ │ └── ic_day_of_year_button.xml
│ ├── drawable
│ │ ├── astrodawn.xml
│ │ ├── civildawn.xml
│ │ ├── ic_clock.xml
│ │ ├── ic_launcher_foreground.xml
│ │ ├── ic_menu_share.xml
│ │ ├── ic_play_arrow.xml
│ │ ├── ic_reset.xml
│ │ ├── ic_stop.xml
│ │ ├── ic_time_of_day_button.xml
│ │ ├── icon_sun.xml
│ │ ├── map_of_the_world.png
│ │ ├── nauticaldawn.xml
│ │ ├── roundedcorner.xml
│ │ ├── roundedcorner2.xml
│ │ ├── roundedcorner2_pressed.xml
│ │ ├── roundedcorner2_unpressed.xml
│ │ ├── roundedcorner_pressed.xml
│ │ ├── roundedcorner_unpressed.xml
│ │ └── side_nav_bar.xml
│ ├── font
│ │ ├── lato.xml
│ │ ├── lato_black.ttf
│ │ ├── lato_blackitalic.ttf
│ │ ├── lato_bold.ttf
│ │ ├── lato_bolditalic.ttf
│ │ ├── lato_hairline.ttf
│ │ ├── lato_hairlineitalic.ttf
│ │ ├── lato_italic.ttf
│ │ ├── lato_light.ttf
│ │ ├── lato_lightitalic.ttf
│ │ └── lato_regular.ttf
│ ├── layout-land
│ │ └── fragment_daynight.xml
│ ├── layout
│ │ ├── activity_main.xml
│ │ ├── app_bar_main.xml
│ │ ├── content_main.xml
│ │ ├── fragment_daynight.xml
│ │ ├── fragment_help.xml
│ │ ├── nav_header_main.xml
│ │ ├── view_sunnavigationview.xml
│ │ └── widget_day_night.xml
│ ├── menu
│ │ └── activity_main_drawer.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
│ ├── navigation
│ │ └── mobile_navigation.xml
│ ├── values-night
│ │ ├── colors.xml
│ │ └── styles.xml
│ ├── values
│ │ ├── colors.xml
│ │ ├── dimens.xml
│ │ ├── ic_launcher_background.xml
│ │ ├── ids.xml
│ │ ├── strings.xml
│ │ └── styles.xml
│ └── xml
│ │ └── day_night_widget_info.xml
│ └── rs
│ └── daynightscript.rs
├── build.gradle
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── screenshot2.png
├── screenshot3.png
└── settings.gradle
/.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 |
--------------------------------------------------------------------------------
/.idea/.gitignore:
--------------------------------------------------------------------------------
1 | # Default ignored files
2 | /shelf/
3 | /workspace.xml
4 | # Editor-based HTTP Client requests
5 | /httpRequests/
6 | # Datasource local storage ignored files
7 | /dataSources/
8 | /dataSources.local.xml
9 |
--------------------------------------------------------------------------------
/.idea/.name:
--------------------------------------------------------------------------------
1 | Day & Night Map
--------------------------------------------------------------------------------
/.idea/codeStyles/Project.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
11 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 | xmlns:android
32 |
33 | ^$
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 | xmlns:.*
43 |
44 | ^$
45 |
46 |
47 | BY_NAME
48 |
49 |
50 |
51 |
52 |
53 |
54 | .*:id
55 |
56 | http://schemas.android.com/apk/res/android
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 | .*:name
66 |
67 | http://schemas.android.com/apk/res/android
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 | name
77 |
78 | ^$
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 | style
88 |
89 | ^$
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 | .*
99 |
100 | ^$
101 |
102 |
103 | BY_NAME
104 |
105 |
106 |
107 |
108 |
109 |
110 | .*
111 |
112 | http://schemas.android.com/apk/res/android
113 |
114 |
115 | ANDROID_ATTRIBUTE_ORDER
116 |
117 |
118 |
119 |
120 |
121 |
122 | .*
123 |
124 | .*
125 |
126 |
127 | BY_NAME
128 |
129 |
130 |
131 |
132 |
133 |
134 |
--------------------------------------------------------------------------------
/.idea/compiler.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/deploymentTargetDropDown.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/.idea/encodings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/gradle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
18 |
19 |
--------------------------------------------------------------------------------
/.idea/jarRepositories.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/.idea/jpa-buddy.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2023 Rainer Follador
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | 
2 |
3 | # Day & Night Map Android App
4 |
5 | The World map shows what areas of the Earth are in daylight, which are at night and in twilight.
6 | Use the slider to interactively set the time and date and visualize the changing of the seasons and the length of the day.
7 | The widget shows live data on your homescreen and is designed to be very battery friendly.
8 |
9 | This is an open source port of [*Day & Night Map and Widget* available on Google Play](https://play.google.com/store/apps/details?id=com.genewarrior.daynightmap).
10 |
11 | *Day & Night Map and Widget* is integrated in [SunLocator](http://sunlocator.com), an app
12 | to predict the sun's position in multiple ways (Augmented Reality, Map, 3D Terrain simulation).
13 | [Available on Google Play](https://play.google.com/store/apps/details?id=com.genewarrior.sunlocator.pro).
14 |
15 | ## Key Elements
16 |
17 | ### Renderscript
18 |
19 | The Renderscript file [daynightscript.rs](app/src/main/rs/daynightscript.rs)
20 | handles the rendering of the map's shadows on a pixel by pixel basis, depicting regions with night,
21 | civil dawn/dusk, nautical dawn/dusk and astronomical dawn/dusk. Mercator projection of the map makes it
22 | straightforward to calculate which pixel is which longitude/latitude.
23 |
24 | Calculation is based on [Grena, 2012 - Five new algorithms for the computation of sun position from 2010 to 2110](https://www.sciencedirect.com/science/article/abs/pii/S0038092X12000400)
25 | algorithms with modifications.
26 |
27 | [Renderscript](https://developer.android.com/guide/topics/renderscript/compute)
28 | allows running computational intensive tasks in parallel using GPUs and multi-core CPUs.
29 | This lets the app calculate the sun elevation at every pixel of the map (800x400 px) very fast while
30 | allowing interactively changing the time/date.
31 |
32 | **Note:** RenderScript is deprecated starting in Android 12. [See here.](https://developer.android.com/guide/topics/renderscript/migrate)
33 | I still have not got around to migrate it to Vulkan, as suggested in the linked article.
34 |
35 | ### Android Layouts
36 |
37 | The app itself is quite straightforward. [PhotoView](https://github.com/Baseflow/PhotoView) is
38 | used to allow a tiny bit of panning/zooming the map.
39 | The widget is implemented in [DayNightWidget.java](app/src/main/java/com/genewarrior/daynightmap/Widget/DayNightWidget.java).
40 |
41 | 
42 | 
43 |
44 |
45 |
--------------------------------------------------------------------------------
/Screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/r-follador/DayNightMap/d2e73cc879603837d5fb04fde6a9fd1cda005792/Screenshot.png
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 |
5 | signingConfigs {
6 | config {
7 | keyAlias 'android'
8 | }
9 | }
10 |
11 | compileSdkVersion 32
12 | defaultConfig {
13 | applicationId "com.genewarrior.daynightmap"
14 | minSdkVersion 24
15 | targetSdkVersion 32
16 | versionCode 1
17 | versionName "1"
18 | vectorDrawables.useSupportLibrary = true
19 | renderscriptTargetApi 19
20 | renderscriptSupportModeEnabled true
21 | }
22 | buildTypes {
23 | release {
24 | minifyEnabled true
25 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
26 | signingConfig signingConfigs.config
27 | }
28 | }
29 | compileOptions {
30 | sourceCompatibility = 1.8
31 | targetCompatibility = 1.8
32 | }
33 | }
34 |
35 | dependencies {
36 | implementation fileTree(dir: 'libs', include: ['*.jar'])
37 | implementation("com.google.guava:guava:30.1.1-android")
38 | implementation 'androidx.appcompat:appcompat:1.5.1'
39 | implementation 'androidx.legacy:legacy-support-v4:1.0.0'
40 | implementation 'com.google.android.material:material:1.7.0'
41 | implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
42 | implementation 'androidx.navigation:navigation-fragment:2.5.3'
43 | implementation 'androidx.navigation:navigation-ui:2.5.3'
44 | implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
45 | implementation 'com.github.Baseflow:PhotoView:2.3.0'
46 | implementation files('libs/solarpositioning.jar')
47 | }
48 |
--------------------------------------------------------------------------------
/app/libs/solarpositioning.jar:
--------------------------------------------------------------------------------
1 | /home/rainer/Software_Dev/AndroidStudioProjects/SunLocator/solarpositioning/build/libs/solarpositioning.jar
--------------------------------------------------------------------------------
/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
22 |
23 | -keep class * extends java.util.ListResourceBundle {
24 | protected Object[][] getContents();
25 | }
26 |
27 | -keep public class com.google.android.gms.common.internal.safeparcel.SafeParcelable {
28 | public static final *** NULL;
29 | }
30 |
31 | -keepnames @com.google.android.gms.common.annotation.KeepName class *
32 | -keepclassmembernames class * {
33 | @com.google.android.gms.common.annotation.KeepName *;
34 | }
35 |
36 | -keepnames class * implements android.os.Parcelable {
37 | public static final ** CREATOR;
38 | }
39 |
40 | -keep class com.android.vending.billing.**
41 |
42 | -keep class androidx.renderscript.** { *; }
43 |
--------------------------------------------------------------------------------
/app/release/app-release.aab:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/r-follador/DayNightMap/d2e73cc879603837d5fb04fde6a9fd1cda005792/app/release/app-release.aab
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
12 |
13 |
16 |
17 |
18 |
19 |
20 |
21 |
24 |
25 |
26 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/app/src/main/ic_launcher-web.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/r-follador/DayNightMap/d2e73cc879603837d5fb04fde6a9fd1cda005792/app/src/main/ic_launcher-web.png
--------------------------------------------------------------------------------
/app/src/main/java/com/genewarrior/daynightmap/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.genewarrior.daynightmap;
2 |
3 | import android.content.Intent;
4 | import android.os.Bundle;
5 |
6 | import androidx.core.view.GravityCompat;
7 | import androidx.navigation.NavController;
8 | import androidx.navigation.Navigation;
9 | import androidx.navigation.ui.AppBarConfiguration;
10 | import androidx.navigation.ui.NavigationUI;
11 | import com.google.android.material.navigation.NavigationView;
12 |
13 | import androidx.drawerlayout.widget.DrawerLayout;
14 |
15 | import androidx.appcompat.app.AppCompatActivity;
16 | import androidx.appcompat.widget.Toolbar;
17 |
18 | public class MainActivity extends AppCompatActivity {
19 |
20 | private AppBarConfiguration mAppBarConfiguration;
21 | @Override
22 | protected void onCreate(Bundle savedInstanceState) {
23 | super.onCreate(savedInstanceState);
24 | setContentView(R.layout.activity_main);
25 | Toolbar toolbar = findViewById(R.id.toolbar);
26 | setSupportActionBar(toolbar);
27 | DrawerLayout drawer = findViewById(R.id.drawer_layout);
28 | NavigationView navigationView = findViewById(R.id.nav_view);
29 | // Passing each menu ID as a set of Ids because each
30 | // menu should be considered as top level destinations.
31 | mAppBarConfiguration = new AppBarConfiguration.Builder(
32 | R.id.nav_home, R.id.nav_help)
33 | .setDrawerLayout(drawer)
34 | .build();
35 | NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment);
36 | NavigationUI.setupActionBarWithNavController(this, navController, mAppBarConfiguration);
37 | NavigationUI.setupWithNavController(navigationView, navController);
38 | navigationView.setNavigationItemSelectedListener(menuItem -> {
39 | if (menuItem.getItemId()==R.id.nav_share)
40 | shareAppLink();
41 | NavigationUI.onNavDestinationSelected(menuItem,navController);//This is for maintaining the behavior of the Navigation view
42 | drawer.closeDrawer(GravityCompat.START);
43 | return true;
44 | });
45 | }
46 |
47 | @Override
48 | public boolean onSupportNavigateUp() {
49 | NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment);
50 | return NavigationUI.navigateUp(navController, mAppBarConfiguration)
51 | || super.onSupportNavigateUp();
52 | }
53 |
54 | private void shareAppLink() {
55 | try {
56 | Intent shareIntent = new Intent(Intent.ACTION_SEND);
57 | shareIntent.setType("text/plain");
58 | shareIntent.putExtra(Intent.EXTRA_SUBJECT, "Day and Night Map");
59 | //TODO: add correct playstore link
60 | String shareMessage= "I want to recommend the Day and Night App:\n"
61 | + "https://play.google.com/store/apps/details?id=com.genewarrior.daynightmap\n";
62 | shareIntent.putExtra(Intent.EXTRA_TEXT, shareMessage);
63 | startActivity(Intent.createChooser(shareIntent, "Choose"));
64 | } catch(Exception e) {
65 | //e.toString();
66 | }
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/app/src/main/java/com/genewarrior/daynightmap/Status.java:
--------------------------------------------------------------------------------
1 | package com.genewarrior.daynightmap;
2 |
3 | import java.util.GregorianCalendar;
4 |
5 | public class Status {
6 |
7 | public enum ButtonChoice {
8 | MinuteOfDay, DayOfYear
9 | };
10 |
11 | public GregorianCalendar getDate() {
12 | return date;
13 | }
14 |
15 | public void setDate(GregorianCalendar date) {
16 | this.date = date;
17 | }
18 |
19 | public Status(double latitude, double longitude, double altitude, GregorianCalendar date, ButtonChoice buttonChoice) {
20 | this.latitude = latitude;
21 | this.longitude = longitude;
22 | this.altitude = altitude;
23 | this.date = date;
24 | this.buttonChoice = buttonChoice;
25 | }
26 |
27 | double latitude = 0;
28 | double longitude = 0;
29 | double altitude = 0;
30 |
31 | public ButtonChoice getButtonChoice() {
32 | return buttonChoice;
33 | }
34 |
35 | public void setButtonChoice(ButtonChoice buttonChoice) {
36 | this.buttonChoice = buttonChoice;
37 | }
38 |
39 | ButtonChoice buttonChoice = null;
40 | GregorianCalendar date = null;
41 | }
42 |
--------------------------------------------------------------------------------
/app/src/main/java/com/genewarrior/daynightmap/SunNavigationView.java:
--------------------------------------------------------------------------------
1 | package com.genewarrior.daynightmap;
2 |
3 | import android.annotation.SuppressLint;
4 | import android.app.Activity;
5 | import android.app.DatePickerDialog;
6 | import android.app.Dialog;
7 | import android.app.DialogFragment;
8 | import android.app.TimePickerDialog;
9 | import android.content.Context;
10 | import android.os.Bundle;
11 | import android.os.Handler;
12 | import android.text.format.DateFormat;
13 | import android.util.AttributeSet;
14 | import android.view.View;
15 | import android.widget.DatePicker;
16 | import android.widget.ImageButton;
17 | import android.widget.SeekBar;
18 | import android.widget.TimePicker;
19 |
20 | import androidx.constraintlayout.widget.ConstraintLayout;
21 |
22 | import java.text.SimpleDateFormat;
23 | import java.util.Calendar;
24 | import java.util.GregorianCalendar;
25 |
26 | public class SunNavigationView extends ConstraintLayout {
27 | ImageButton buttonChoice;
28 | ImageButton resetTime;
29 | ImageButton buttonPlay;
30 | ImageButton buttonSet;
31 |
32 | SunSeekBar sunSeekBar;
33 | Status status;
34 | boolean limitLiteVersion;
35 |
36 |
37 | public SunNavigationView(Context context) {
38 | super(context);
39 | init();
40 | }
41 |
42 | public SunNavigationView(Context context, AttributeSet attrs) {
43 | super(context, attrs);
44 | init();
45 | }
46 |
47 | public SunNavigationView(Context context, AttributeSet attrs, int defStyle) {
48 | super(context, attrs, defStyle);
49 | init();
50 | }
51 |
52 | private void init() {
53 | inflate(getContext(), R.layout.view_sunnavigationview, this);
54 | buttonChoice = findViewById(R.id.buttonChoice);
55 | sunSeekBar = findViewById(R.id.sunSeekBar);
56 | resetTime = findViewById(R.id.buttonReset);
57 | buttonSet = findViewById(R.id.buttonSet);
58 | buttonPlay = findViewById(R.id.buttonPlay);
59 |
60 | buttonChoice.setImageResource(R.drawable.ic_time_of_day_button);
61 |
62 | buttonChoice.setOnClickListener(new OnClickListener() {
63 | public void onClick(View v) {
64 | if (status.getButtonChoice() == Status.ButtonChoice.DayOfYear)
65 | setSelection(Status.ButtonChoice.MinuteOfDay);
66 | else
67 | setSelection(Status.ButtonChoice.DayOfYear);
68 | }
69 | });
70 |
71 |
72 | resetTime.setOnClickListener(new OnClickListener() {
73 | public void onClick(View v) {
74 | stopSunUpdater();
75 | SimpleDateFormat fmt = new SimpleDateFormat("dd-MMM-yyyy HH:mm:ss S Z");
76 | //System.out.println("Set time to " + fmt.format(originalTime.getTime()));
77 | status.getDate().setTime((new GregorianCalendar()).getTime());
78 | //status.setDate((GregorianCalendar)originalTime.clone());
79 | sunSeekBar.update();
80 | callback.onSunNavigationChange();
81 | //System.out.println("Time is now " + fmt.format(status.getDate().getTime()));
82 | }
83 | });
84 |
85 | buttonSet.setOnClickListener(view -> {
86 | if (status.getButtonChoice() == Status.ButtonChoice.DayOfYear) {
87 | DialogFragment newFragment = new DatePickerFragment(this);
88 | newFragment.show(((Activity)getContext()).getFragmentManager(), "datePicker");
89 | } else { //TimeofDay is selected
90 | DialogFragment newFragment = new TimePickerFragment(this);
91 | newFragment.show(((Activity)getContext()).getFragmentManager(), "timePicker");
92 | }
93 | });
94 |
95 |
96 | sunSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
97 |
98 | @Override
99 | public void onStopTrackingTouch(SeekBar seekBar) {
100 | // TODO Auto-generated method stub
101 | }
102 |
103 | @Override
104 | public void onStartTrackingTouch(SeekBar seekBar) {
105 | // TODO Auto-generated method stub
106 | }
107 |
108 | @Override
109 | public void onProgressChanged(SeekBar seekBar2, int progress,boolean fromUser) {
110 | if (fromUser)
111 | stopSunUpdater();
112 | status.setDate(sunSeekBar.getDate());
113 |
114 | long t_diff = Math.abs(status.getDate().getTimeInMillis() - System.currentTimeMillis());
115 | if (t_diff < 60000) //less than one minute difference
116 | resetTime.setVisibility(INVISIBLE);
117 | else
118 | resetTime.setVisibility(VISIBLE);
119 | callback.onSunNavigationChange();
120 | }
121 | });
122 |
123 | buttonPlay.setOnClickListener(new OnClickListener() {
124 | public void onClick(View v) {
125 | if (sunupdaterIsRunning) {
126 | stopSunUpdater();
127 | } else {
128 | sunUpdater.run();
129 | buttonPlay.setImageResource(R.drawable.ic_stop);
130 | }
131 | }
132 | });
133 | }
134 |
135 | Handler handler = new Handler();
136 |
137 | boolean sunupdaterIsRunning = false;
138 |
139 | public Runnable sunUpdater = new Runnable() {
140 | @Override
141 | public void run() {
142 | sunupdaterIsRunning = true;
143 | if (status.buttonChoice == Status.ButtonChoice.DayOfYear) {
144 | status.getDate().add(GregorianCalendar.DAY_OF_YEAR, 1);
145 | }
146 | else {
147 | int dayOfYear = status.getDate().get(GregorianCalendar.DAY_OF_YEAR);
148 | status.getDate().add(GregorianCalendar.MINUTE, 2);
149 | }
150 | sunSeekBar.update();
151 | callback.onSunNavigationChange();
152 | handler.postDelayed(sunUpdater,40);
153 | }
154 | };
155 |
156 | private void stopSunUpdater() {
157 | handler.removeCallbacks(sunUpdater);
158 | sunupdaterIsRunning = false;
159 | buttonPlay.setImageResource(R.drawable.ic_play_arrow);
160 | }
161 |
162 | public interface OnSunNavigationChangeListener {
163 | // TODO: Update argument type and name
164 | void onSunNavigationChange();
165 | }
166 |
167 | OnSunNavigationChangeListener callback;
168 |
169 | public void setOnFragmentInteractionListener(OnSunNavigationChangeListener callback, Status status, boolean limitLiteVersion) {
170 | this.limitLiteVersion = limitLiteVersion;
171 | this.callback = callback;
172 | this.status = status;
173 | sunSeekBar.setStatus(status);
174 | sunSeekBar.update();
175 | }
176 |
177 | protected void setSelection(Status.ButtonChoice choice) {
178 | if (choice == Status.ButtonChoice.DayOfYear) {
179 | status.setButtonChoice(choice);
180 | sunSeekBar.update();
181 | buttonChoice.setImageResource(R.drawable.ic_day_of_year_button);
182 | } else if (choice == Status.ButtonChoice.MinuteOfDay) {
183 | status.setButtonChoice(choice);
184 | sunSeekBar.update();
185 | buttonChoice.setImageResource(R.drawable.ic_time_of_day_button);
186 | }
187 | sunSeekBar.update();
188 | }
189 |
190 | @Override
191 | protected void onDetachedFromWindow() {
192 | super.onDetachedFromWindow();
193 | stopSunUpdater();
194 | }
195 |
196 | @SuppressLint("ValidFragment") //Shouldn't use custom constructor, but the alternative is a pain in the ass
197 | public static class TimePickerFragment extends DialogFragment implements TimePickerDialog.OnTimeSetListener {
198 | SunNavigationView sunNavigationView;
199 | public TimePickerFragment(SunNavigationView sunNavigationView) {
200 | super();
201 | this.sunNavigationView = sunNavigationView;
202 | }
203 |
204 | @Override
205 | public Dialog onCreateDialog(Bundle savedInstanceState) {
206 | // Use the current time as the default values for the picker
207 | final Calendar c = Calendar.getInstance();
208 | int hour = c.get(Calendar.HOUR_OF_DAY);
209 | int minute = c.get(Calendar.MINUTE);
210 |
211 | // Create a new instance of TimePickerDialog and return it
212 | return new TimePickerDialog(getActivity(), this, hour, minute,
213 | DateFormat.is24HourFormat(getActivity()));
214 | }
215 |
216 | public void onTimeSet(TimePicker view, int hourOfDay, int minute) {
217 | sunNavigationView.status.getDate().set(Calendar.HOUR_OF_DAY, hourOfDay);
218 | sunNavigationView.status.getDate().set(Calendar.MINUTE, minute);
219 | sunNavigationView.sunSeekBar.update();
220 | sunNavigationView.callback.onSunNavigationChange();
221 | }
222 | }
223 |
224 | @SuppressLint("ValidFragment") //Shouldn't use custom constructor, but the alternative is a pain in the ass
225 | public static class DatePickerFragment extends DialogFragment implements DatePickerDialog.OnDateSetListener {
226 |
227 | SunNavigationView sunNavigationView;
228 | public DatePickerFragment(SunNavigationView sunNavigationView) {
229 | super();
230 | this.sunNavigationView = sunNavigationView;
231 | }
232 |
233 | @Override
234 | public Dialog onCreateDialog(Bundle savedInstanceState) {
235 | // Use the current date as the default date in the picker
236 | final Calendar c = Calendar.getInstance();
237 | int year = c.get(Calendar.YEAR);
238 | int month = c.get(Calendar.MONTH);
239 | int day = c.get(Calendar.DAY_OF_MONTH);
240 |
241 | // Create a new instance of DatePickerDialog and return it
242 | return new DatePickerDialog(getActivity(), this, year, month, day);
243 | }
244 |
245 | public void onDateSet(DatePicker view, int year, int month, int day) {
246 | sunNavigationView.status.getDate().set(Calendar.YEAR, year);
247 | sunNavigationView.status.getDate().set(Calendar.MONTH, month);
248 | sunNavigationView.status.getDate().set(Calendar.DAY_OF_MONTH, day);
249 | sunNavigationView.sunSeekBar.update();
250 | sunNavigationView.callback.onSunNavigationChange();
251 | }
252 | }
253 | }
254 |
--------------------------------------------------------------------------------
/app/src/main/java/com/genewarrior/daynightmap/SunSeekBar.java:
--------------------------------------------------------------------------------
1 | package com.genewarrior.daynightmap;
2 |
3 | import android.content.Context;
4 | import android.graphics.Canvas;
5 | import android.graphics.Paint;
6 | import android.graphics.Typeface;
7 | import android.util.AttributeSet;
8 | import android.util.TypedValue;
9 | import android.widget.SeekBar;
10 |
11 | import androidx.core.content.ContextCompat;
12 | import androidx.core.content.res.ResourcesCompat;
13 |
14 | import java.text.SimpleDateFormat;
15 | import java.util.Calendar;
16 | import java.util.GregorianCalendar;
17 |
18 | public class SunSeekBar extends SeekBar {
19 | static final int maximumPos = 10000;
20 |
21 | Status status;
22 |
23 | public SunSeekBar(Context context) {
24 | super(context);
25 | init();
26 | }
27 |
28 | public SunSeekBar(Context context, AttributeSet attrs) {
29 | super(context, attrs);
30 | init();
31 | }
32 |
33 | public SunSeekBar(Context context, AttributeSet attrs, int defStyleAttr) {
34 | super(context, attrs, defStyleAttr);
35 | init();
36 | }
37 |
38 | public void init() {
39 | setMax(maximumPos);
40 | Typeface font = ResourcesCompat.getFont(getContext(), R.font.lato);
41 | blackPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
42 | blackPaint.setTypeface(font);
43 | blackPaint.setColor(ContextCompat.getColor(getContext(), R.color.colorSunseekbarFont));
44 | blackPaint.setStyle(Paint.Style.FILL);
45 | fontsize = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,12, getResources().getDisplayMetrics());
46 | blackPaint.setTextSize(fontsize);
47 | drawDate = new GregorianCalendar();
48 | drawDate.set(GregorianCalendar.DAY_OF_YEAR, 1);
49 | drawDate.set(GregorianCalendar.HOUR, 0);
50 | drawDate.set(GregorianCalendar.MINUTE, 0);
51 | }
52 |
53 | Paint blackPaint;
54 | GregorianCalendar drawDate;
55 | int fontsize;
56 |
57 | public void setStatus(Status status)
58 | {
59 | this.status = status;
60 | }
61 |
62 |
63 | public void update() {
64 | this.setProgress(date2position(status.date, status.getButtonChoice()));
65 | }
66 |
67 | public void setDate(GregorianCalendar date) {
68 |
69 | }
70 |
71 | public GregorianCalendar getDate() {
72 | return position2date(this.getProgress(), status.buttonChoice, status.date);
73 | }
74 |
75 |
76 |
77 | private static int date2position(GregorianCalendar date, Status.ButtonChoice buttonChoice) {
78 | if (buttonChoice == Status.ButtonChoice.MinuteOfDay) {
79 | int minuteOfDay = date.get(Calendar.MINUTE) + (date.get(Calendar.HOUR_OF_DAY)*60);
80 | return Math.round((float)maximumPos*((float)minuteOfDay/(float)((23*60)+59)));
81 | } else if (buttonChoice == Status.ButtonChoice.DayOfYear) {
82 | return Math.round((float)maximumPos*((float)(date.get(Calendar.DAY_OF_YEAR)-1)/364.0f));
83 | }
84 | return -1; //error
85 | }
86 |
87 | private static GregorianCalendar position2date(int position, Status.ButtonChoice buttonChoice, GregorianCalendar date) {
88 |
89 | GregorianCalendar dateOut = (GregorianCalendar)(date.clone());
90 |
91 | if (buttonChoice == Status.ButtonChoice.MinuteOfDay) {
92 | int minuteOfDay = Math.round((((float)position/(float)maximumPos)*(float)((23*60)+59)));
93 | int hourOfDay = minuteOfDay/60;
94 | int minuteOfHour = minuteOfDay%60;
95 |
96 |
97 |
98 | dateOut.set(Calendar.HOUR_OF_DAY, hourOfDay);
99 | dateOut.set(Calendar.MINUTE, minuteOfHour);
100 | } else if (buttonChoice == Status.ButtonChoice.DayOfYear) {
101 | dateOut.set(Calendar.DAY_OF_YEAR, 1+Math.round(364.0f*(float)position/(float)maximumPos));
102 | }
103 | return dateOut;
104 | }
105 |
106 |
107 |
108 | //see https://stackoverflow.com/questions/15011144/how-to-make-custom-seek-bar-in-android
109 | @Override
110 | protected synchronized void onDraw(Canvas canvas) {
111 |
112 | super.onDraw(canvas);
113 |
114 | // size of seek bar.
115 | float width = getWidth();
116 | float height = getHeight();
117 | float mPaddingLeft = getPaddingLeft();
118 | float mPaddingRight = getPaddingRight();
119 | float mPaddingTop = getPaddingTop();
120 | float mPaddingBottom = getPaddingBottom();
121 | float yMiddle = mPaddingTop + ((height-mPaddingTop-mPaddingBottom)/2);
122 |
123 | SimpleDateFormat sdf = new SimpleDateFormat("MMM");
124 |
125 | float barWidth = width - mPaddingLeft-mPaddingRight;
126 |
127 | if (status.getButtonChoice()==Status.ButtonChoice.DayOfYear) {
128 | for (int month = 0; month < 12; month++) {
129 | drawDate.set(GregorianCalendar.MONTH, month);
130 | int pos = date2position(drawDate, Status.ButtonChoice.DayOfYear);
131 | float x = (barWidth * ((float) pos / (float) maximumPos)) + mPaddingRight;
132 | canvas.drawCircle(x, yMiddle, 5, blackPaint);
133 | float textY = (month % 2 == 0 ? yMiddle - 6 : yMiddle + fontsize + 2);
134 | canvas.drawText(sdf.format(drawDate.getTime()), x + 2, textY, blackPaint);
135 | }
136 | } else {
137 | for (int hour = 0; hour < 25; hour++) {
138 |
139 | float x = (barWidth * ((float)hour/24f)) + mPaddingRight;
140 | canvas.drawCircle(x, yMiddle, 5, blackPaint);
141 | float textY = (hour % 2 == 0 ? yMiddle - 12 : yMiddle + fontsize + 6);
142 | if (hour%3!=0)
143 | continue;
144 | canvas.drawCircle(x, yMiddle, 8, blackPaint);
145 | if (hour==24)
146 | continue;
147 | String txt = Integer.toString(hour)+(hour<12?"am":"pm");
148 | canvas.drawText(txt, x - 15, textY, blackPaint);
149 | }
150 | }
151 |
152 | }
153 |
154 | }
155 |
--------------------------------------------------------------------------------
/app/src/main/java/com/genewarrior/daynightmap/Widget/DayNightWidget.java:
--------------------------------------------------------------------------------
1 | package com.genewarrior.daynightmap.Widget;
2 |
3 | import android.app.AlarmManager;
4 | import android.app.PendingIntent;
5 | import android.appwidget.AppWidgetManager;
6 | import android.appwidget.AppWidgetProvider;
7 | import android.content.ComponentName;
8 | import android.content.Context;
9 | import android.content.Intent;
10 | import android.graphics.Bitmap;
11 | import android.os.SystemClock;
12 | import android.widget.RemoteViews;
13 |
14 |
15 | import com.genewarrior.daynightmap.MainActivity;
16 | import com.genewarrior.daynightmap.R;
17 | import com.genewarrior.daynightmap.ui.daynight.DayNightHelper;
18 |
19 | import java.util.GregorianCalendar;
20 |
21 |
22 | /**
23 | * Implementation of App Widget functionality.
24 | */
25 | public class DayNightWidget extends AppWidgetProvider {
26 |
27 | @Override
28 | public void onReceive(Context context, Intent intent) {
29 | super.onReceive(context, intent);
30 | //(context.getPackageName()+".DAY_NIGHT_WIDGET_UPDATE_INTENT")
31 | if ((context.getPackageName()+".DAY_NIGHT_WIDGET_UPDATE_INTENT").equals(intent.getAction())) {
32 | // Get the widget manager and ids for this widget provider, then call the shared
33 | // clock update method.
34 | ComponentName thisAppWidget = new ComponentName(context.getPackageName(), getClass().getName());
35 | AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
36 | int[] ids = appWidgetManager.getAppWidgetIds(thisAppWidget);
37 |
38 | DayNightHelper dayNightHelper = new DayNightHelper(context);
39 | Bitmap outputBmp = dayNightHelper.getDayNightBmp(new GregorianCalendar());
40 |
41 |
42 | for (int appWidgetID: ids) {
43 | updateAppWidget(context, appWidgetManager, appWidgetID, outputBmp);
44 | }
45 | }
46 | }
47 |
48 | private PendingIntent createDayNightTickIntent(Context context) {
49 | Intent intent = new Intent(context, DayNightWidget.class);
50 |
51 | intent.setAction(context.getPackageName()+".DAY_NIGHT_WIDGET_UPDATE_INTENT");
52 | PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);
53 |
54 | return pendingIntent;
55 | }
56 |
57 |
58 | static void updateAppWidget(Context context, AppWidgetManager appWidgetManager,
59 | int appWidgetId, Bitmap bitmap) {
60 | // Construct the RemoteViews object
61 | try {
62 | RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.widget_day_night);
63 | views.setImageViewBitmap(R.id.daynightimageWidget, bitmap);
64 |
65 | Intent mainactivityIntent = new Intent(context, MainActivity.class);
66 | PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, mainactivityIntent, PendingIntent.FLAG_IMMUTABLE);
67 | views.setOnClickPendingIntent(R.id.daynightimageWidget, pendingIntent);
68 |
69 | // Instruct the widget manager to update the widget
70 | appWidgetManager.updateAppWidget(appWidgetId, views);
71 | } catch (Exception e) {
72 | e.printStackTrace();
73 | //Bla
74 | }
75 | }
76 |
77 | @Override
78 | public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
79 | DayNightHelper dayNightHelper = null;
80 |
81 | try {
82 | dayNightHelper = new DayNightHelper(context);
83 | } catch (Exception e) {
84 | e.printStackTrace();
85 | } catch (OutOfMemoryError e) {
86 | System.gc();
87 | try {
88 | dayNightHelper = new DayNightHelper(context);
89 | } catch (OutOfMemoryError e2) {
90 | e2.printStackTrace();
91 | }
92 | }
93 |
94 | if (dayNightHelper == null)
95 | return;
96 |
97 | Bitmap outputBmp = dayNightHelper.getDayNightBmp(new GregorianCalendar());
98 |
99 | for (int appWidgetId : appWidgetIds) {
100 | updateAppWidget(context, appWidgetManager, appWidgetId, outputBmp);
101 | }
102 |
103 | dayNightHelper.destroy();
104 | super.onUpdate(context, appWidgetManager, appWidgetIds);
105 | }
106 |
107 |
108 |
109 | @Override
110 | public void onEnabled(Context context) {
111 | // Enter relevant functionality for when the first widget is created
112 | super.onEnabled(context);
113 | AlarmManager alarmManager = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
114 |
115 | alarmManager.setRepeating(AlarmManager.ELAPSED_REALTIME, SystemClock.elapsedRealtime()+1000, 5*60*1000, createDayNightTickIntent(context));
116 | }
117 |
118 | @Override
119 | public void onDisabled(Context context) {
120 | // Enter relevant functionality for when the last widget is disabled
121 | super.onDisabled(context);
122 | AlarmManager alarmManager = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
123 | alarmManager.cancel(createDayNightTickIntent(context));
124 |
125 | }
126 | }
127 |
128 |
--------------------------------------------------------------------------------
/app/src/main/java/com/genewarrior/daynightmap/ui/daynight/DayNightFragment.java:
--------------------------------------------------------------------------------
1 | package com.genewarrior.daynightmap.ui.daynight;
2 |
3 | import android.graphics.Bitmap;
4 | import android.graphics.Matrix;
5 | import android.os.AsyncTask;
6 | import android.os.Bundle;
7 | import android.view.LayoutInflater;
8 | import android.view.View;
9 | import android.view.ViewGroup;
10 | import android.widget.TextView;
11 |
12 | import androidx.annotation.NonNull;
13 | import androidx.fragment.app.Fragment;
14 |
15 | import com.genewarrior.daynightmap.R;
16 | import com.genewarrior.daynightmap.Status;
17 | import com.genewarrior.daynightmap.SunNavigationView;
18 | import com.github.chrisbanes.photoview.PhotoView;
19 |
20 | import java.text.SimpleDateFormat;
21 | import java.util.GregorianCalendar;
22 | import java.util.TimeZone;
23 |
24 | public class DayNightFragment extends Fragment implements SunNavigationView.OnSunNavigationChangeListener {
25 |
26 | TextView timeView;
27 | boolean isRunning = false;
28 | GregorianCalendar queue = null;
29 | Status status = null;
30 | DayNightHelper dayNightHelper;
31 | PhotoView dayNightImage;
32 | SimpleDateFormat fmt = new SimpleDateFormat("dd-MMM-yyyy HH:mm");
33 | SunNavigationView sunNavigationView;
34 | DayLightImageTask dayLightImageTask;
35 |
36 | public View onCreateView(@NonNull LayoutInflater inflater,
37 | ViewGroup container, Bundle savedInstanceState) {
38 | View root = inflater.inflate(R.layout.fragment_daynight, container, false);
39 | dayNightHelper = new DayNightHelper(getContext());
40 |
41 | status = new Status(0, 0, 0, new GregorianCalendar(), Status.ButtonChoice.MinuteOfDay);
42 | fmt.setTimeZone(status.getDate().getTimeZone());
43 | timeView = (TextView) root.findViewById(R.id.timeView);
44 | dayNightImage = (PhotoView) root.findViewById(R.id.daynightimage);
45 | sunNavigationView = root.findViewById(R.id.sunnavigationview);
46 | sunNavigationView.setOnFragmentInteractionListener(this, status, false);
47 |
48 | drawNewDate();
49 |
50 | return root;
51 | }
52 |
53 | protected String getStringFromDate() {
54 | String tz = status.getDate().getTimeZone().getDisplayName(status.getDate().getTimeZone().inDaylightTime(status.getDate().getTime()), TimeZone.SHORT);
55 | return fmt.format(status.getDate().getTime()) + "\n" +tz;
56 | }
57 |
58 | protected void setTimeView(String str) {
59 | timeView.setText(str);
60 | }
61 |
62 | protected void drawNewDate() {
63 | setTimeView(getStringFromDate());
64 | if (isRunning) {
65 | queue = status.getDate();
66 | return;
67 | }
68 |
69 | dayLightImageTask = new DayLightImageTask();
70 | dayLightImageTask.execute(status.getDate());
71 |
72 | }
73 |
74 |
75 |
76 | @Override
77 | public void onSunNavigationChange() {
78 | drawNewDate();
79 | }
80 |
81 | protected class DayLightImageTask extends AsyncTask {
82 |
83 | Bitmap outputBmp;
84 | @Override
85 | protected Integer doInBackground(GregorianCalendar... dates) {
86 | GregorianCalendar date = dates[0];
87 | outputBmp = dayNightHelper.getDayNightBmp(date);
88 | return null;
89 | }
90 |
91 | protected void onProgressUpdate(Integer... progress) {
92 | //do something
93 | }
94 |
95 | protected void onPreExecute() {
96 | isRunning = true;
97 | }
98 |
99 | protected void onPostExecute(Integer result) {
100 | Matrix previousImageMatrix = new Matrix();
101 | dayNightImage.getSuppMatrix(previousImageMatrix);
102 | dayNightImage.setImageBitmap(outputBmp);
103 | dayNightImage.setDisplayMatrix(previousImageMatrix);
104 | isRunning = false;
105 |
106 | if (queue != null) {
107 | new DayLightImageTask().execute((GregorianCalendar)queue.clone());
108 | queue = null;
109 | }
110 | }
111 | }
112 |
113 | @Override
114 | public void onDestroyView() {
115 | dayLightImageTask.cancel(true);
116 | dayNightHelper.destroy();
117 | super.onDestroyView();
118 | }
119 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/genewarrior/daynightmap/ui/daynight/DayNightHelper.java:
--------------------------------------------------------------------------------
1 | package com.genewarrior.daynightmap.ui.daynight;
2 |
3 | import android.content.Context;
4 | import android.graphics.Bitmap;
5 | import android.graphics.BitmapFactory;
6 | import android.graphics.Canvas;
7 | import android.graphics.Matrix;
8 | import android.graphics.drawable.Drawable;
9 |
10 | import androidx.core.content.res.ResourcesCompat;
11 | import androidx.renderscript.Allocation;
12 | import androidx.renderscript.RenderScript;
13 |
14 | import com.genewarrior.daynightmap.R;
15 | import com.genewarrior.sunlocator.app.ScriptC_daynightscript;
16 | import com.sunlocator.solarpositioning.AzimuthZenithAngle;
17 | import com.sunlocator.solarpositioning.DeltaT;
18 |
19 | import java.util.GregorianCalendar;
20 |
21 | import static com.sunlocator.solarpositioning.Grena3.calcT;
22 | import static java.lang.Math.PI;
23 | import static java.lang.Math.asin;
24 | import static java.lang.Math.atan2;
25 | import static java.lang.Math.cos;
26 | import static java.lang.Math.sin;
27 | import static java.lang.Math.sqrt;
28 | import static java.lang.Math.toDegrees;
29 | import static java.lang.Math.toRadians;
30 |
31 | public class DayNightHelper {
32 |
33 | RenderScript rs;
34 | ScriptC_daynightscript daynightscript;
35 |
36 | Allocation mapBmpInput;
37 |
38 | Bitmap background;
39 | Drawable sunIcon;
40 | int sunIconSize;
41 | int width;
42 | int height;
43 | public DayNightHelper(Context context) {
44 | background = BitmapFactory.decodeResource(context.getResources(), R.drawable.map_of_the_world);
45 | sunIcon = ResourcesCompat.getDrawable(context.getResources(), R.drawable.icon_sun, null);
46 |
47 | width = background.getWidth();
48 | height = background.getHeight();
49 | sunIconSize = height/5;
50 | rs = RenderScript.create(context, RenderScript.ContextType.NORMAL);
51 | daynightscript = new ScriptC_daynightscript(rs);
52 |
53 | mapBmpInput = Allocation.createFromBitmap(rs, background);
54 | }
55 |
56 | public Bitmap getDayNightBmp(GregorianCalendar date) {
57 |
58 | if (isDestroyed) {
59 | return null;
60 | }
61 |
62 | SolarElevationPreCalc preCalc = calculateSolarElevation_Step1(date);
63 |
64 | Bitmap.Config conf = Bitmap.Config.ARGB_8888;
65 | Bitmap bmpOutput = Bitmap.createBitmap(background.getWidth(), background.getHeight(), conf);
66 |
67 |
68 | Allocation outputBmpAlloc = Allocation.createFromBitmap(rs, bmpOutput);
69 |
70 | daynightscript.set_alpha((float)preCalc.alpha); //right ascension
71 | daynightscript.set_delta((float)preCalc.delta); //declination
72 | daynightscript.set_h_pre((float)preCalc.H_pre);
73 | daynightscript.set_height(height);
74 | daynightscript.set_width(width);
75 |
76 | daynightscript.forEach_root(mapBmpInput, outputBmpAlloc);
77 | rs.finish();
78 | outputBmpAlloc.copyTo(bmpOutput);
79 |
80 | Bitmap overlay = background.copy(background.getConfig(), true);
81 | Canvas canvas = new Canvas(overlay);
82 | canvas.drawBitmap(bmpOutput, new Matrix(), null);
83 |
84 |
85 | double pseudoH = preCalc.H_pre-preCalc.alpha; //the hour angle for 0 longitude
86 | pseudoH = ((pseudoH + PI) % (2 * PI)) - PI;
87 | if (pseudoH < -PI) {
88 | pseudoH += 2 * PI;
89 | }
90 |
91 | int longitudePixel = (width/2)-(int)((pseudoH/(Math.PI))*(double)width/2);
92 | int latitudePixel = (height/2)-(int)((preCalc.delta/(Math.PI/2d))*(double)height/2);
93 | sunIcon.setBounds(longitudePixel-(sunIconSize/2), latitudePixel-(sunIconSize/2), longitudePixel+(sunIconSize/2), latitudePixel+(sunIconSize/2));
94 | sunIcon.draw(canvas);
95 |
96 | if (longitudePixel-(sunIconSize/2)<0) {
97 | sunIcon.setBounds(width+longitudePixel-(sunIconSize/2), latitudePixel-(sunIconSize/2), width+longitudePixel+(sunIconSize/2), latitudePixel+(sunIconSize/2));
98 | sunIcon.draw(canvas);
99 | } else if (longitudePixel+(sunIconSize/2)>width) {
100 | int bla = ((width-longitudePixel)*-1)-(sunIconSize/2);
101 | sunIcon.setBounds(bla, latitudePixel-(sunIconSize/2), bla+(sunIconSize), latitudePixel+(sunIconSize/2));
102 |
103 | sunIcon.draw(canvas);
104 | }
105 | outputBmpAlloc.destroy();
106 |
107 | return overlay;
108 | }
109 |
110 | boolean isDestroyed = false;
111 | public void destroy() {
112 | isDestroyed = true;
113 | mapBmpInput.destroy();
114 | daynightscript.destroy();
115 | rs.destroy();
116 | }
117 |
118 |
119 | /**
120 | * Modified from Grena3; no refraction correction
121 | * Step 1: non lat/lon dependent calculations
122 | *
123 | * @param date Observer's local date and time.
124 | * @return Topocentric solar position (azimuth measured eastward from north)
125 | * @see AzimuthZenithAngle
126 | */
127 | public static SolarElevationPreCalc calculateSolarElevation_Step1(final GregorianCalendar date) {
128 | final double deltaT = DeltaT.estimate(date);
129 | final double t = calcT(date);
130 | final double tE = t + 1.1574e-5 * deltaT;
131 | final double omegaAtE = 0.0172019715 * tE;
132 |
133 | final double lambda = -1.388803 + 1.720279216e-2 * tE + 3.3366e-2 * sin(omegaAtE - 0.06172)
134 | + 3.53e-4 * sin(2.0 * omegaAtE - 0.1163);
135 |
136 | final double epsilon = 4.089567e-1 - 6.19e-9 * tE;
137 |
138 | final double sLambda = sin(lambda);
139 | final double cLambda = cos(lambda);
140 | final double sEpsilon = sin(epsilon);
141 | final double cEpsilon = sqrt(1 - sEpsilon * sEpsilon);
142 |
143 | double alpha = atan2(sLambda * cEpsilon, cLambda);
144 | if (alpha < 0) {
145 | alpha += 2 * PI;
146 | }
147 |
148 | final double delta = asin(sLambda * sEpsilon);
149 |
150 | double H_pre = 1.7528311 + 6.300388099 * t;
151 |
152 |
153 | return new SolarElevationPreCalc(alpha, delta, H_pre);
154 | }
155 |
156 | private static class SolarElevationPreCalc {
157 | double alpha, delta, H_pre;
158 | public SolarElevationPreCalc(double alpha, double delta, double H_pre) {
159 | this.alpha = alpha;
160 | this.delta = delta;
161 | this.H_pre = H_pre;
162 | }
163 | }
164 | }
165 |
--------------------------------------------------------------------------------
/app/src/main/java/com/genewarrior/daynightmap/ui/help/HelpFragment.java:
--------------------------------------------------------------------------------
1 | package com.genewarrior.daynightmap.ui.help;
2 |
3 | import android.os.Bundle;
4 | import android.view.LayoutInflater;
5 | import android.view.View;
6 | import android.view.ViewGroup;
7 | import android.widget.TextView;
8 |
9 | import androidx.annotation.Nullable;
10 | import androidx.annotation.NonNull;
11 | import androidx.fragment.app.Fragment;
12 | import androidx.lifecycle.Observer;
13 | import androidx.lifecycle.ViewModelProviders;
14 |
15 | import com.genewarrior.daynightmap.R;
16 |
17 | public class HelpFragment extends Fragment {
18 |
19 |
20 | public View onCreateView(@NonNull LayoutInflater inflater,
21 | ViewGroup container, Bundle savedInstanceState) {
22 | View root = inflater.inflate(R.layout.fragment_help, container, false);
23 |
24 | return root;
25 | }
26 | }
--------------------------------------------------------------------------------
/app/src/main/res/drawable-nodpi/daynight_widget_preview.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/r-follador/DayNightMap/d2e73cc879603837d5fb04fde6a9fd1cda005792/app/src/main/res/drawable-nodpi/daynight_widget_preview.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-nodpi/ic_day_of_year_button.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
12 |
15 |
18 |
19 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/astrodawn.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/civildawn.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_clock.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
6 |
8 |
9 |
10 |
13 |
14 |
15 |
16 |
19 |
20 |
23 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_menu_share.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_play_arrow.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_reset.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_stop.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_time_of_day_button.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
12 |
15 |
16 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/icon_sun.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
10 |
14 |
16 |
22 |
24 |
30 |
32 |
38 |
40 |
46 |
48 |
54 |
56 |
62 |
64 |
70 |
72 |
78 |
80 |
86 |
88 |
94 |
96 |
102 |
104 |
110 |
112 |
118 |
120 |
124 |
127 |
131 |
134 |
140 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/map_of_the_world.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/r-follador/DayNightMap/d2e73cc879603837d5fb04fde6a9fd1cda005792/app/src/main/res/drawable/map_of_the_world.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/nauticaldawn.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/roundedcorner.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
8 |
9 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/roundedcorner2.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
8 |
9 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/roundedcorner2_pressed.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/roundedcorner2_unpressed.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/roundedcorner_pressed.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/roundedcorner_unpressed.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/side_nav_bar.xml:
--------------------------------------------------------------------------------
1 |
3 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/font/lato.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
11 |
15 |
--------------------------------------------------------------------------------
/app/src/main/res/font/lato_black.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/r-follador/DayNightMap/d2e73cc879603837d5fb04fde6a9fd1cda005792/app/src/main/res/font/lato_black.ttf
--------------------------------------------------------------------------------
/app/src/main/res/font/lato_blackitalic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/r-follador/DayNightMap/d2e73cc879603837d5fb04fde6a9fd1cda005792/app/src/main/res/font/lato_blackitalic.ttf
--------------------------------------------------------------------------------
/app/src/main/res/font/lato_bold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/r-follador/DayNightMap/d2e73cc879603837d5fb04fde6a9fd1cda005792/app/src/main/res/font/lato_bold.ttf
--------------------------------------------------------------------------------
/app/src/main/res/font/lato_bolditalic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/r-follador/DayNightMap/d2e73cc879603837d5fb04fde6a9fd1cda005792/app/src/main/res/font/lato_bolditalic.ttf
--------------------------------------------------------------------------------
/app/src/main/res/font/lato_hairline.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/r-follador/DayNightMap/d2e73cc879603837d5fb04fde6a9fd1cda005792/app/src/main/res/font/lato_hairline.ttf
--------------------------------------------------------------------------------
/app/src/main/res/font/lato_hairlineitalic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/r-follador/DayNightMap/d2e73cc879603837d5fb04fde6a9fd1cda005792/app/src/main/res/font/lato_hairlineitalic.ttf
--------------------------------------------------------------------------------
/app/src/main/res/font/lato_italic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/r-follador/DayNightMap/d2e73cc879603837d5fb04fde6a9fd1cda005792/app/src/main/res/font/lato_italic.ttf
--------------------------------------------------------------------------------
/app/src/main/res/font/lato_light.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/r-follador/DayNightMap/d2e73cc879603837d5fb04fde6a9fd1cda005792/app/src/main/res/font/lato_light.ttf
--------------------------------------------------------------------------------
/app/src/main/res/font/lato_lightitalic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/r-follador/DayNightMap/d2e73cc879603837d5fb04fde6a9fd1cda005792/app/src/main/res/font/lato_lightitalic.ttf
--------------------------------------------------------------------------------
/app/src/main/res/font/lato_regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/r-follador/DayNightMap/d2e73cc879603837d5fb04fde6a9fd1cda005792/app/src/main/res/font/lato_regular.ttf
--------------------------------------------------------------------------------
/app/src/main/res/layout-land/fragment_daynight.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
19 |
20 |
32 |
33 |
40 |
41 |
51 |
52 |
59 |
60 |
70 |
71 |
78 |
79 |
89 |
90 |
96 |
97 |
98 |
99 |
100 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
15 |
16 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/app_bar_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
13 |
14 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/content_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
20 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_daynight.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
19 |
20 |
32 |
33 |
39 |
40 |
48 |
49 |
56 |
57 |
66 |
67 |
74 |
75 |
85 |
86 |
92 |
93 |
94 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_help.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
11 |
12 |
26 |
27 |
28 |
39 |
40 |
49 |
50 |
60 |
61 |
69 |
70 |
79 |
80 |
89 |
90 |
98 |
99 |
107 |
108 |
116 |
117 |
127 |
128 |
138 |
139 |
149 |
150 |
159 |
160 |
161 |
162 |
163 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/nav_header_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
14 |
15 |
22 |
23 |
30 |
31 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/view_sunnavigationview.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
20 |
21 |
34 |
35 |
36 |
37 |
51 |
52 |
66 |
67 |
81 |
82 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/widget_day_night.xml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
14 |
15 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/activity_main_drawer.xml:
--------------------------------------------------------------------------------
1 |
2 |
25 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/r-follador/DayNightMap/d2e73cc879603837d5fb04fde6a9fd1cda005792/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/r-follador/DayNightMap/d2e73cc879603837d5fb04fde6a9fd1cda005792/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/r-follador/DayNightMap/d2e73cc879603837d5fb04fde6a9fd1cda005792/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/r-follador/DayNightMap/d2e73cc879603837d5fb04fde6a9fd1cda005792/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/r-follador/DayNightMap/d2e73cc879603837d5fb04fde6a9fd1cda005792/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/r-follador/DayNightMap/d2e73cc879603837d5fb04fde6a9fd1cda005792/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/r-follador/DayNightMap/d2e73cc879603837d5fb04fde6a9fd1cda005792/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/r-follador/DayNightMap/d2e73cc879603837d5fb04fde6a9fd1cda005792/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/r-follador/DayNightMap/d2e73cc879603837d5fb04fde6a9fd1cda005792/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/r-follador/DayNightMap/d2e73cc879603837d5fb04fde6a9fd1cda005792/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/navigation/mobile_navigation.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
13 |
18 |
--------------------------------------------------------------------------------
/app/src/main/res/values-night/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #303F9F
4 | #ffffff
5 | #000000
6 | #000000
7 |
8 |
--------------------------------------------------------------------------------
/app/src/main/res/values-night/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
14 |
15 |
16 |
19 |
20 |
25 |
26 |
30 |
31 |
36 |
37 |
40 |
41 |
42 |
43 |
44 |
45 |
50 |
51 |
62 |
63 |
68 |
69 |
74 |
75 |
79 |
80 |
84 |
85 |
88 |
89 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #3f92b5
4 | #303F9F
5 | #ff7840
6 | #000000
7 | #FFFFFF
8 | #FFFFFF
9 | #FFFFFF
10 | @android:color/black
11 | #c7f9f9f9
12 | #616161
13 | #FFFFFF
14 | @android:color/black
15 | @android:color/white
16 | #66000000
17 | #000000
18 | #EEE
19 | #eef2f4
20 |
21 |
--------------------------------------------------------------------------------
/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 16dp
4 | 16dp
5 | 8dp
6 | 176dp
7 | 16dp
8 | 0dp
9 |
--------------------------------------------------------------------------------
/app/src/main/res/values/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #FFFFFF
4 |
--------------------------------------------------------------------------------
/app/src/main/res/values/ids.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Day & Night Map
4 | Open navigation drawer
5 | Close navigation drawer
6 | Day & Night Map
7 | Made by SunLocator.com
8 | Navigation header
9 | Settings
10 | Day & Night Map
11 | Help
12 | Tools
13 | Share App
14 | Send
15 |
16 | Compass Calibration
17 | -Move away from any magnetic interference (be aware of any magnets in phone cases and holsters)\n-Rotate your device several times around each of its three axes\n-Confirm using a real compass
18 | Decimal Lat/Long
19 | Latitude
20 | Longitude
21 | North
22 | South
23 | West
24 | East
25 | Degrees Minutes Seconds
26 | Longitude is out of range. Max +/- 180°
27 | Latitude is out of range. Max +/- 88°
28 | OK
29 | Cancel
30 | Saved Locations
31 | New Position
32 | Save Location?
33 | Location saved
34 | Last used location
35 | No saved list found
36 | Your list is empty\nShowing example locations
37 | Error saving position
38 | Position and Time
39 | Location
40 | Save
41 | List
42 | GPS
43 | Map
44 | Search
45 | Coordinates
46 | Date/Time
47 | Current time
48 | Set time
49 | Set date
50 | Time zone
51 | Select Time Zone
52 | Device Default
53 | Auto Detect
54 | Set the desired date and time to continue
55 | Set the desired location to continue
56 | Set the location and the date/time to continue
57 | Querying server…
58 | Error querying Server :(
59 | No Time zone chosen
60 | Date and time is not set
61 | No Location chosen
62 | Sun
63 | Camera View
64 | Map View
65 | Morning
66 | Sunrise
67 | Astronomical Dawn
68 | Nautical Dawn
69 | Civil Dawn
70 | Noon
71 | Sun transit
72 | Day duration
73 | Evening
74 | Sunset
75 | Civil Dusk
76 | Nautical Dusk
77 | Astronomical Dusk
78 | Photography
79 | Blue Hour
80 | Golden Hour
81 | Equinox
82 | Spring
83 | Autumn
84 | Solstice
85 | Winter
86 | Summer
87 | Sun position at
88 | Azimuth
89 | Elevation
90 | Shadow ratio
91 | Sun Graph
92 | Day
93 | Year
94 | Day of Year
95 | Time of Day
96 | Moon
97 | Moon rise
98 | Moon set
99 | Moon position at
100 | Moon Phase
101 | Waning
102 | Waxing
103 | Day/Night
104 | Blue Ocean
105 | Transparent Ocean
106 | All times in
107 | Current sun position
108 | Current Moon position
109 | Night
110 | Sun Dial Height
111 | Sun Dial Shadow
112 | Set Sun Dial Height
113 | Map Layer
114 | Compass Direction
115 | Lock Position
116 | Metric
117 | Imperial
118 | Metric/Imperial Unit
119 | Meter
120 | Feet
121 | Set
122 | Delete
123 | Yes
124 | No
125 | Calculating…
126 | Sunrise
127 | Sunset
128 | Time
129 | None
130 | Not visible
131 | Can\'t open Maps.
132 | Can\'t get GPS location. Check if GPS is turned on.
133 | Can\'t open Map View. Make sure Google Maps is installed.
134 | Can\'t open Camera View.
135 | -Remember to regularly calibrate your device.\n-Be aware of your surroundings\n-For children: Parental supervision is important
136 | Sun Locator cannot access your compass. Does your device have a compass? Is it enabled?
137 | unknown
138 | not set
139 | Show Help
140 | Map
141 | Problems?
142 | Having Problems? Read the Help file or send an email to contact@sunlocator.com
143 | Sun Locator Facebook Page
144 | Rate App
145 | Help
146 | Upgrade to Pro
147 | Get the Sun and Moon data for any day of the year
148 | -Plan ahead and know where to be for the perfect photo opportunity\n-Will your plants get enough Sun in the garden or balcony?\n-How does the path of the Sun change throughout the year?\n-Will neighbouring buildings block the Sun in Winter or Summer?\n\n
149 | Predict the Shadow length
150 | Customize the height of the sun dial to calculate and visualize shadow length of physical objects.
151 | Plot the Sunset and Sunrise over the course of a year.
152 | Upgrade!
153 | Later
154 | Help improve Day & Night
155 | Do you like Day & Night?\nPlease rate the app on the Play Store, and help making it more popular.
156 | Rate Day & Night
157 | Don\'t like Day & Night?\nHelp improving the app by sending an email to the developer\nAny feedback is welcome!
158 | Write an email
159 | Remind me later
160 | No, thanks
161 | Sun Locator predicts Sun and Moon positions during the course of a day and a year.
162 | Getting started
163 | First the app must know your current position and the date and time for which you want to predict the solar and lunar location.
164 | Set the position:
165 | By clicking on \"GPS\", you can use your device\'s GPS to get your current position. For this you need to activate your GPS.
166 | By clicking on \"Map\", you can select the position in Google Maps. For this you need to have an internet connection to download the map.
167 | Set the time and date:
168 | You can either use the current time by clicking on \"Use current time\" or set the date and time to a different value by clicking on \"Choose time\" and \"Choose date\", This allows you to predict the sun and moon position on a time and date of your choice.
169 | The Main view shows the important data about the current solar and lunar position, such as sun set and sun rise, twilight, moon phase etc.
170 | The Camera View shows the AR (augmented reality) feature of Sun Locator. The Sun and Moon position is overlaid on your device\'s camera and helps you to directly track the sun and moon path and check for any obstructions.
171 | The Map view shows the Sun and Moon path overlaid on Google Maps and the shadow is displayed on a 3D sundial.
172 | Sunrise, Sunset, Moon rise, Moon set:
173 | The time of day when the sun or moon crosses the Earth\'s horizon.
174 | Sun transit:
175 | Sometimes referred to as solar noon, is the time of the day when the sun passes over the observer\'s meridian line, this is roughly when the sun is at its highest.
176 | Twilight times:
177 | Twilight is the remaining illumination when the sun is below the horizon. The sunlight scatters in the atmosphere and illuminates the Earth. There are three definitions of twilight:
178 | Civil twilight: Approximately the limit at which solar illumination is sufficient, under clear weather conditions, for terrestrial objects to be clearly distinguished by eye. There is enough light from the sun during this period that artificial sources of light are not needed to carry on most outdoor activities.
179 | Nautical twilight: The horizon is clearly visible, but artificial lighting is necessary to see terrestrial objects.
180 | Astronomical twilight: Outside of the astronomical twilight, the sky (away from light pollution, moonlight, auroras, and other sources of light in the sky) is dark enough for nearly all astronomical observations.
181 | Shadow ratio:
182 | The length of the shadow cast by an object of the height of 1 foot or meter.
183 | E.g. at a shadow ratio of 1:0.45 an object of 5 meter height will cast a shadow of 5 × 0.45 = 2.25 meter
184 | Photography: Blue and golden hour:
185 | The Blue hour is the period of twilight when the sun is below the horizon and the indirect sunlight takes on a predominantly blue hue and cold color temperature.
186 | The Golden hour is the short period of time just before sunset or after sunrise when the light is redder, having a warm color temperature. Lighting is diffuse and with little contrast, so no strong shadows exist.
187 | Azimuth:
188 | The horizontal angle clockwise from North. I.e. North is zero degrees (0°), East 90°, South 180° and West 270°. The Magnetic declination is automatically taken into account using the specified location.
189 | Elevation:
190 | Sometimes referred to as altitude, is the angle between the devices horizon and the sun. The horizon is at 0° and the zenith at 90°
191 | Moon phase:
192 | The percentage of the lit surface of the moon. 0% corresponds to a new moon, 100% to a full moon. The moon is either waxing (the lit surface is increasing) or waning (decreasing).
193 | Time zone:
194 | The Time zone can be changed in the Main View.
195 | In the AR (augmented reality) feature of Sun Locator, the Sun and Moon position is overlaid on your device\'s camera and helps you to directly track the sun and moon path and check for any obstructions. The slider lets you fast forward in time throughout the day and year.
196 | [A] Date/Time: Use the bottom slider to change the date and time.
197 | [B] Switch Sun/Moon: Switch from displaying the Sun position and path to displaying the Moon.
198 | [C] Slider range: Using the slider will either set the time of day or day in year.
199 | [D] Slider: set the date and time by going back and forth.
200 | [E] Sun/Moon path throughout the day.
201 | [F] Current position of the Sun/Moon
202 | Accuracy
203 | The Camera view relies heavily on your device\'s internal compass. This sensor becomes inaccurate when not calibrated regularly. It\'s best to calibrate your device before each use of the app. You find instruction for doing so on the apps main menu.
204 | When using the Camera View, make sure to move away from any magnetic interference and remove any magnets (e.g. in phone cases).
205 | The solar and lunar path is overlaid on top of Google Maps and the shadow is displayed on a 3D sundial.
206 | [A] Switch Sun/Moon: Switch from displaying the Sun position and path to displaying the Moon.
207 | [B] Data: Chosen date/time, Sun/Moon position, Shadow ratio/length
208 | [C] Show/Hide Advanced options
209 | [D] Map layer: choose between different map types (normal, satellite, terrain) to be displayed
210 | [E] Lock position: keep position locked (no scrolling)
211 | [F] Compass direction: rotate map according to your device\'s compass
212 | [G] Set Sun dial height: customize the height of the sun dial
213 | [H] Slider range: Using the slider will either set the time of day or day in year
214 | [I] Slider: set the date and time by going back and forth.
215 | [J] Shadow cast by the 3D sundial
216 | [K] Sun/moon path throughout the day
217 | [L] Current sun/moon position
218 | Use pinch to zoom in/out, drag to change the position and two finger drag to tilt the view (just as in Google Maps).
219 | Main View
220 | Camera View
221 | Map View
222 | This is a BETA feature, please report any problems to contact@sunlocator.com
223 | Storage is full, can\'t download file
224 | Querying server for map...
225 | Downloading Map...
226 | Querying Server for Topographical Model...
227 | Downloading Topographical Model...
228 | Time out Error: Are you connected to the Internet? Please try again.
229 | Location is not (yet) supported
230 | Unknown Error
231 | No Internet connection
232 | Error: No WebGL detected on your device
233 | 3D Terrain Simulator
234 | -Simulation of lighting conditions in a 3D landscape during the course of a day and year.\n - Shadows of mountains, hills and valleys are calculated
235 | 3D Terrain Simulation
236 | Can\'t open 3D Terrain.
237 | EXAMPLE
238 | Add widget
239 | Failed to contact Google Play, please try again later.
240 | Google Play purchase was not successful
241 | Google Play purchase is still pending. Check back later
242 | You have already disabled ads.\nThank you for your support!
243 | No one likes ads, but it\'s what pays our coffee to keep the app running. Feed our coffein addiction, buy us a coffee and we remove the ads from the app.
244 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
13 |
14 |
18 |
19 |
23 |
24 |
29 |
30 |
31 |
32 |
35 |
36 |
37 |
38 |
39 |
40 |
45 |
46 |
57 |
58 |
63 |
64 |
69 |
70 |
74 |
75 |
79 |
80 |
83 |
84 |
85 |
86 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/day_night_widget_info.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/rs/daynightscript.rs:
--------------------------------------------------------------------------------
1 | #pragma version(1)
2 | #pragma rs_fp_relaxed
3 | #pragma rs java_package_name(com.genewarrior.sunlocator.app)
4 |
5 | #include "rs_debug.rsh"
6 |
7 | float width;
8 | float height;
9 |
10 | float alpha;
11 | float delta;
12 | float h_pre;
13 |
14 | float static elev(float latitude, float longitude) {
15 | float H = h_pre + radians(longitude) - alpha;
16 | H = fmod((H + M_PI),(2 * M_PI)) - M_PI;
17 | if (H < 0 - M_PI) {
18 | H += 2 * M_PI;
19 | }
20 | float sPhi = sin(radians(latitude));
21 | float cPhi = sqrt((1 - sPhi * sPhi));
22 | float sDelta = sin(delta);
23 | float cDelta = sqrt(1 - sDelta * sDelta);
24 | float cH = cos(H);
25 |
26 | float sEpsilon0 = sPhi * sDelta + cPhi * cDelta * cH;
27 | float eP = asin(sEpsilon0) - 4.26e-5 * sqrt(1.0f - sEpsilon0 * sEpsilon0);
28 |
29 |
30 | float z = M_PI / 2 - eP;
31 |
32 | return 90.0f - degrees(z);
33 | }
34 |
35 | uchar4 __attribute__((kernel)) root(uchar4 in, uint32_t x, uint32_t y) {
36 | uchar4 nightColor = rsPackColorTo8888(0.1f, 0.1f, 0.1f, 0.85f);
37 | uchar4 astroColor = rsPackColorTo8888(0.15f, 0.15f, 0.2f, 0.8f);
38 | uchar4 nautColor = rsPackColorTo8888(0.12f, 0.2f, 0.40f, 0.7f);
39 | uchar4 civilColor = rsPackColorTo8888(0.20f, 0.35f, 0.53f, 0.6f);
40 | uchar4 dayColor = rsPackColorTo8888(1.0f, 1.0f, 1.0f, 0.0f); //full transparency
41 |
42 |
43 | //conversion from pixel position to lat/lon on plate carée protection
44 | float longitude = ((360.0f/width)*(float)x)-180.0f;
45 | float latitude = 90.0f-((180.0f/height)*(float)y);
46 |
47 | float z = elev(latitude, longitude);
48 |
49 | if (z < -18.0f) {
50 | return nightColor;
51 | }
52 | if (z < -12.0f) { //astronomical twilight
53 | return astroColor;
54 | }
55 | if (z < -6.0f) { //nautical twilight
56 | return nautColor;
57 | }
58 | if (z < -0.8333f) { //civil twilight
59 | return civilColor;
60 | }
61 | return dayColor; //anything above -0.833 is day
62 |
63 | }
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 | repositories {
5 | google()
6 | jcenter()
7 | maven { url "https://jitpack.io" }
8 | }
9 | dependencies {
10 | classpath 'com.android.tools.build:gradle:7.3.1'
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 | jcenter()
21 | maven { url "https://jitpack.io" }
22 | }
23 | }
24 |
25 | task clean(type: Delete) {
26 | delete rootProject.buildDir
27 | }
28 |
--------------------------------------------------------------------------------
/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=true
20 |
21 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/r-follador/DayNightMap/d2e73cc879603837d5fb04fde6a9fd1cda005792/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Wed Sep 09 21:17:41 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.4-all.zip
7 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/screenshot2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/r-follador/DayNightMap/d2e73cc879603837d5fb04fde6a9fd1cda005792/screenshot2.png
--------------------------------------------------------------------------------
/screenshot3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/r-follador/DayNightMap/d2e73cc879603837d5fb04fde6a9fd1cda005792/screenshot3.png
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 | rootProject.name='Day & Night Map'
3 |
--------------------------------------------------------------------------------