Compare commits

...

32 Commits

Author SHA1 Message Date
Daniele Verducci (Slimpenguin)
3361ec8965 Excluded IDE files 2024-02-28 08:53:15 +01:00
Daniele Verducci (Slimpenguin)
c5e05e4b8a Implemented filter by category 2024-02-28 08:50:20 +01:00
Daniele Verducci (Slimpenguin)
25f7b05fd0 WIP implementing filtering by category 2024-02-27 08:59:37 +01:00
Daniele Verducci (Slimpenguin)
443e954c66 Fixed logout issue 2024-02-27 08:18:28 +01:00
Daniele Verducci (Slimpenguin)
28258d8c15 Working search in both map and list view 2024-02-24 18:03:11 +01:00
Daniele Verducci (Slimpenguin)
d74462a66c Refactored filter to support category filtering 2024-02-24 17:37:57 +01:00
Daniele Verducci (Slimpenguin)
572095a7c3 Moved toolbar management in common fragment 2024-02-24 16:45:52 +01:00
Daniele Verducci (Slimpenguin)
32b005599a User badge 2024-02-24 07:19:55 +01:00
Daniele Verducci (Slimpenguin)
49e291881a Changed share text 2024-02-23 08:57:49 +01:00
Daniele Verducci (Slimpenguin)
5949099d91 Fixed geopoint deletion and update 2024-02-23 08:52:32 +01:00
Daniele Verducci (Slimpenguin)
13287f5b05 Implemented geofav creation on long press 2024-02-23 08:31:23 +01:00
Daniele Verducci (Slimpenguin)
acf5090489 Fixes in dark mode 2024-02-23 08:23:49 +01:00
Daniele Verducci (Slimpenguin)
7b26938efb Center to user position 2024-02-23 08:23:23 +01:00
Daniele Verducci (Slimpenguin)
0e8f9e2dfa Fixed map not redrawn after elements added 2024-02-23 07:18:10 +01:00
Daniele Verducci (Slimpenguin)
513bc368b2 Fixed navigation in map 2024-02-22 08:29:31 +01:00
Daniele Verducci (Slimpenguin)
a752a85a3f Fixed dialog buttons color 2024-02-22 08:23:19 +01:00
Daniele Verducci (Slimpenguin)
053f7401b8 Styled category label in infowindow 2024-02-22 08:13:57 +01:00
Daniele Verducci (Slimpenguin)
b6ce246a74 Handcrafted infowindow pointer 2024-02-22 07:34:16 +01:00
Daniele Verducci (Slimpenguin)
ae9274d646 Map style, graphics refinements 2024-02-22 07:22:32 +01:00
Daniele Verducci (Slimpenguin)
739399f54b Working geofavorites 2024-02-20 14:02:51 +01:00
fd4a9c1f5d WIP Geofavorite infowindow 2024-02-19 21:42:31 +01:00
d762ffe40a Working map view with markers opening default, ugly, infowindow 2024-02-19 20:52:21 +01:00
ebbd4c823b Fixed build 2024-02-19 19:41:13 +01:00
Daniele Verducci (Slimpenguin)
e1747b73f3 WIP adding geofavorite map fragment 2024-02-19 18:31:39 +01:00
Daniele Verducci (Slimpenguin)
e1b1adf9ad Moved toolbar to fragment to allow hide-on-scroll 2024-02-19 08:53:24 +01:00
Daniele Verducci (Slimpenguin)
a396406877 Resolved warnings on main activity layout 2024-02-19 08:26:55 +01:00
Daniele Verducci (Slimpenguin)
ca2b7a7064 Fixed some resources references 2024-02-19 08:17:57 +01:00
Daniele Verducci (Slimpenguin)
fa65c33ec6 Separated list logic from application logic, support for multiple list fragments 2024-02-17 09:07:59 +01:00
Daniele Verducci (Slimpenguin)
a1d6f1dabe Moved shared preferences in their own class 2024-02-17 06:58:35 +01:00
Daniele Verducci (Slimpenguin)
367d6d0a74 Header styled like the one in Nextcloud Files app 2024-02-16 08:26:17 +01:00
Daniele Verducci (Slimpenguin)
b15236580b Updated libraries 2024-02-16 08:15:27 +01:00
Daniele Verducci (Slimpenguin)
334b540721 Updated gradle and build target 2024-02-16 06:58:10 +01:00
60 changed files with 1656 additions and 614 deletions

5
.gitignore vendored
View File

@ -96,3 +96,8 @@ lint/generated/
lint/outputs/ lint/outputs/
lint/tmp/ lint/tmp/
# lint/reports/ # lint/reports/
app/release/output-metadata.json
.idea/deploymentTargetDropDown.xml
.idea/misc.xml

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project version="4"> <project version="4">
<component name="CompilerConfiguration"> <component name="CompilerConfiguration">
<bytecodeTargetLevel target="11" /> <bytecodeTargetLevel target="17" />
</component> </component>
</project> </project>

View File

@ -1,17 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="deploymentTargetDropDown">
<targetSelectedWithDropDown>
<Target>
<type value="QUICK_BOOT_TARGET" />
<deviceKey>
<Key>
<type value="VIRTUAL_DEVICE_PATH" />
<value value="$USER_HOME$/.android/avd/Pixel_5_API_29.avd" />
</Key>
</deviceKey>
</Target>
</targetSelectedWithDropDown>
<timeTargetWasSelectedWithDropDown value="2023-02-15T07:23:10.782369Z" />
</component>
</project>

10
.idea/migrations.xml Normal file
View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectMigrations">
<option name="MigrateToGradleLocalJavaHome">
<set>
<option value="$PROJECT_DIR$" />
</set>
</option>
</component>
</project>

View File

@ -1,30 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="DesignSurface">
<option name="filePathToZoomLevelMap">
<map>
<entry key="../../../../layout/custom_preview.xml" value="0.5661458333333333" />
<entry key="app/src/main/res/drawable/category_listitem_background.xml" value="0.35104166666666664" />
<entry key="app/src/main/res/drawable/coordinates_label_background.xml" value="0.3614583333333333" />
<entry key="app/src/main/res/drawable/floating_semitransparent_button_background.xml" value="0.512962962962963" />
<entry key="app/src/main/res/drawable/ic_list_pin.xml" value="0.3614583333333333" />
<entry key="app/src/main/res/drawable/ic_map_pin.xml" value="0.6425925925925926" />
<entry key="app/src/main/res/drawable/ic_more.xml" value="0.6166666666666667" />
<entry key="app/src/main/res/drawable/ic_nav.xml" value="0.6083333333333333" />
<entry key="app/src/main/res/drawable/ic_share.xml" value="0.8828125" />
<entry key="app/src/main/res/drawable/round_button_background.xml" value="0.3614583333333333" />
<entry key="app/src/main/res/layout/activity_geofavorite_detail.xml" value="0.4" />
<entry key="app/src/main/res/layout/activity_list_view.xml" value="0.4" />
<entry key="app/src/main/res/layout/activity_login.xml" value="0.2630208333333333" />
<entry key="app/src/main/res/layout/activity_main.xml" value="0.5307291666666667" />
<entry key="app/src/main/res/layout/activity_map_picker.xml" value="0.33016304347826086" />
<entry key="app/src/main/res/layout/item_geofav.xml" value="0.5307291666666667" />
<entry key="app/src/main/res/layout/item_navigation.xml" value="0.8" />
<entry key="app/src/main/res/layout/sorting_order_fragment.xml" value="0.4740740740740741" />
<entry key="app/src/main/res/menu/list_context_menu.xml" value="0.41944444444444445" />
</map>
</option>
</component>
<component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="ProjectRootManager" version="2" languageLevel="JDK_11" default="true" project-jdk-name="11" project-jdk-type="JavaSDK" />
</project>

View File

@ -18,12 +18,12 @@
apply plugin: 'com.android.application' apply plugin: 'com.android.application'
android { android {
compileSdkVersion 31 compileSdkVersion 34
defaultConfig { defaultConfig {
applicationId "it.danieleverducci.nextcloudmaps" applicationId "it.danieleverducci.nextcloudmaps"
minSdkVersion 23 minSdkVersion 23
targetSdkVersion 31 targetSdkVersion 34
versionCode 8 versionCode 8
versionName "0.3.6" versionName "0.3.6"
@ -37,6 +37,9 @@ android {
} }
} }
compileOptions { compileOptions {
// Flag to enable support for the new language APIs
coreLibraryDesugaringEnabled true
// Sets Java compatibility to Java 8
sourceCompatibility JavaVersion.VERSION_1_8 sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8
} }
@ -44,6 +47,7 @@ android {
buildFeatures { buildFeatures {
dataBinding true dataBinding true
} }
namespace 'it.danieleverducci.nextcloudmaps'
} }
repositories { repositories {
@ -54,28 +58,40 @@ repositories {
dependencies { dependencies {
implementation fileTree(dir: "libs", include: ["*.jar"]) implementation fileTree(dir: "libs", include: ["*.jar"])
implementation 'com.android.support:design:31.0.0' // Desugaring lib: see https://developer.android.com/studio/write/java8-support
implementation 'androidx.appcompat:appcompat:1.3.1' coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:2.0.3")
implementation 'androidx.recyclerview:recyclerview:1.2.1'
implementation "androidx.cardview:cardview:1.0.0"
implementation 'androidx.constraintlayout:constraintlayout:2.1.0'
implementation "androidx.preference:preference:1.1.1"
testImplementation 'junit:junit:4.13.2' implementation 'com.android.support:design:34.0.0'
androidTestImplementation 'androidx.test.ext:junit:1.1.3' implementation 'androidx.appcompat:appcompat:1.6.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0' implementation 'androidx.recyclerview:recyclerview:1.3.2'
implementation "androidx.cardview:cardview:1.0.0"
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
implementation "androidx.preference:preference:1.2.1"
implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0'
// Retrofif2 // Retrofif2
implementation 'com.squareup.retrofit2:retrofit:2.9.0' implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.squareup.retrofit2:converter-gson:2.6.1' implementation 'com.squareup.retrofit2:converter-gson:2.6.1'
// Nextcloud SSO // Nextcloud SSO
implementation "com.github.nextcloud:Android-SingleSignOn:0.6.1" implementation "com.github.nextcloud:Android-SingleSignOn:1.0.0"
// OSMDroid // OSMDroid
implementation 'org.osmdroid:osmdroid-android:6.1.10' implementation 'org.osmdroid:osmdroid-android:6.1.18'
//Threeten-Backport (ports Java 8 Date API on Java 6+) //Threeten-Backport (ports Java 8 Date API on Java 6+)
implementation 'org.threeten:threetenbp:1.5.1' implementation 'org.threeten:threetenbp:1.5.1'
// https://mvnrepository.com/artifact/commons-io/commons-io
implementation 'commons-io:commons-io:2.11.0'
// Picasso (image loader)
implementation 'com.squareup.picasso:picasso:2.8'
configurations.all {
resolutionStrategy {
force 'commons-io:commons-io:2.11.0'
}
}
} }

View File

@ -17,8 +17,7 @@
--> -->
<manifest <manifest
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android">
package="it.danieleverducci.nextcloudmaps">
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />

View File

@ -0,0 +1,47 @@
package it.danieleverducci.nextcloudmaps.activity.detail;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.graphics.drawable.DrawableCompat;
import java.util.ArrayList;
import java.util.HashSet;
import it.danieleverducci.nextcloudmaps.R;
import it.danieleverducci.nextcloudmaps.model.Geofavorite;
public class CategoriesAdapter extends ArrayAdapter<String> {
public CategoriesAdapter(@NonNull Context context) {
super(context, R.layout.category_listitem, R.id.category_name, new ArrayList<>());
}
@NonNull
@Override
public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
View v = super.getView(position, convertView, parent);
TextView categoryName = v.findViewById(R.id.category_name);
Drawable backgroundDrawable = categoryName.getBackground();
DrawableCompat.setTint(
backgroundDrawable,
Geofavorite.categoryColorFromName(categoryName.getText().toString()) == 0
? v.getContext().getColor(R.color.defaultBrand)
: Geofavorite.categoryColorFromName(categoryName.getText().toString())
);
return v;
}
public void setCategoriesList(HashSet<String> categories) {
clear();
addAll(categories);
notifyDataSetChanged();
}
}

View File

@ -1,24 +0,0 @@
package it.danieleverducci.nextcloudmaps.activity.detail;
import android.content.Context;
import android.widget.ArrayAdapter;
import androidx.annotation.NonNull;
import java.util.HashSet;
public class CategoriesSpinnerAdapter extends ArrayAdapter<String> {
public CategoriesSpinnerAdapter(@NonNull Context context) {
super(context, android.R.layout.simple_dropdown_item_1line);
}
// TODO: implement colors
public void setCategoriesList(HashSet<String> categories) {
clear();
addAll(categories);
notifyDataSetChanged();
}
}

View File

@ -21,11 +21,9 @@ import android.Manifest;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.graphics.Color;
import android.location.Location; import android.location.Location;
import android.location.LocationListener; import android.location.LocationListener;
import android.location.LocationManager; import android.location.LocationManager;
import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.util.Log; import android.util.Log;
import android.view.LayoutInflater; import android.view.LayoutInflater;
@ -34,7 +32,6 @@ import android.widget.Toast;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.content.res.AppCompatResources; import androidx.appcompat.content.res.AppCompatResources;
import androidx.core.app.ActivityCompat; import androidx.core.app.ActivityCompat;
import androidx.lifecycle.Observer; import androidx.lifecycle.Observer;
@ -43,7 +40,6 @@ import androidx.preference.PreferenceManager;
import org.osmdroid.api.IMapController; import org.osmdroid.api.IMapController;
import org.osmdroid.config.Configuration; import org.osmdroid.config.Configuration;
import org.osmdroid.config.IConfigurationProvider;
import org.osmdroid.util.GeoPoint; import org.osmdroid.util.GeoPoint;
import org.osmdroid.views.CustomZoomButtonsController; import org.osmdroid.views.CustomZoomButtonsController;
import org.osmdroid.views.overlay.Marker; import org.osmdroid.views.overlay.Marker;
@ -52,10 +48,8 @@ import org.threeten.bp.format.FormatStyle;
import java.util.HashSet; import java.util.HashSet;
import it.danieleverducci.nextcloudmaps.BuildConfig;
import it.danieleverducci.nextcloudmaps.R; import it.danieleverducci.nextcloudmaps.R;
import it.danieleverducci.nextcloudmaps.activity.NextcloudMapsStyledActivity; import it.danieleverducci.nextcloudmaps.activity.NextcloudMapsStyledActivity;
import it.danieleverducci.nextcloudmaps.activity.mappicker.MapPickerActivity;
import it.danieleverducci.nextcloudmaps.databinding.ActivityGeofavoriteDetailBinding; import it.danieleverducci.nextcloudmaps.databinding.ActivityGeofavoriteDetailBinding;
import it.danieleverducci.nextcloudmaps.model.Geofavorite; import it.danieleverducci.nextcloudmaps.model.Geofavorite;
import it.danieleverducci.nextcloudmaps.utils.GeoUriParser; import it.danieleverducci.nextcloudmaps.utils.GeoUriParser;
@ -313,7 +307,7 @@ public class GeofavoriteDetailActivity extends NextcloudMapsStyledActivity imple
this.binding.actionIconNav.setOnClickListener(this); this.binding.actionIconNav.setOnClickListener(this);
// Set categories adapter // Set categories adapter
CategoriesSpinnerAdapter categoriesAdapter = new CategoriesSpinnerAdapter(binding.root.getContext()); CategoriesAdapter categoriesAdapter = new CategoriesAdapter(binding.root.getContext());
this.binding.categoryAt.setAdapter(categoriesAdapter); this.binding.categoryAt.setAdapter(categoriesAdapter);
this.binding.categoryAt.setText(Geofavorite.DEFAULT_CATEGORY); this.binding.categoryAt.setText(Geofavorite.DEFAULT_CATEGORY);
@ -378,7 +372,7 @@ public class GeofavoriteDetailActivity extends NextcloudMapsStyledActivity imple
} }
public void setCategories(HashSet<String> categories) { public void setCategories(HashSet<String> categories) {
((CategoriesSpinnerAdapter)binding.categoryAt.getAdapter()).setCategoriesList(categories); ((CategoriesAdapter)binding.categoryAt.getAdapter()).setCategoriesList(categories);
} }
public void hideAccuracy() { public void hideAccuracy() {

View File

@ -20,6 +20,8 @@ package it.danieleverducci.nextcloudmaps.activity.login;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.os.Bundle; import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.view.View; import android.view.View;
import android.widget.Button; import android.widget.Button;
import android.widget.ProgressBar; import android.widget.ProgressBar;
@ -45,6 +47,7 @@ import it.danieleverducci.nextcloudmaps.api.API;
import it.danieleverducci.nextcloudmaps.api.ApiProvider; import it.danieleverducci.nextcloudmaps.api.ApiProvider;
public class LoginActivity extends NextcloudMapsStyledActivity { public class LoginActivity extends NextcloudMapsStyledActivity {
private static final String TAG = "LoginActivity";
protected ProgressBar progress; protected ProgressBar progress;
protected Button button; protected Button button;
@ -63,18 +66,25 @@ public class LoginActivity extends NextcloudMapsStyledActivity {
openAccountChooser(); openAccountChooser();
}); });
try { Handler h = new Handler();
ssoAccount = SingleAccountHelper.getCurrentSingleSignOnAccount(getApplicationContext()); h.post(() -> {
SingleAccountHelper.setCurrentAccount(getApplicationContext(), ssoAccount.name); try {
accountAccessDone(); ssoAccount = SingleAccountHelper.getCurrentSingleSignOnAccount(getApplicationContext());
} catch (NextcloudFilesAppAccountNotFoundException | NoCurrentAccountSelectedException e) { SingleAccountHelper.applyCurrentAccount(getApplicationContext(), ssoAccount.name);
} accountAccessDone();
} catch (NextcloudFilesAppAccountNotFoundException | NoCurrentAccountSelectedException e) {
Log.e(TAG, "Autologin: " + e.toString());
}
});
} }
private void openAccountChooser() { private void openAccountChooser() {
try { try {
AccountImporter.pickNewAccount(this); AccountImporter.pickNewAccount(this);
} catch (NextcloudFilesAppNotInstalledException | AndroidGetAccountsPermissionNotGranted e) { } catch (NextcloudFilesAppNotInstalledException | AndroidGetAccountsPermissionNotGranted e) {
UiExceptionManager.showDialogForException(this, e); UiExceptionManager.showDialogForException(this, e);
Log.e(TAG, "openAccountChooser: " + e.toString());
progress.setVisibility(View.GONE);
} }
} }
@ -98,7 +108,7 @@ public class LoginActivity extends NextcloudMapsStyledActivity {
@Override @Override
public void accountAccessGranted(SingleSignOnAccount account) { public void accountAccessGranted(SingleSignOnAccount account) {
Context l_context = getApplicationContext(); Context l_context = getApplicationContext();
SingleAccountHelper.setCurrentAccount(l_context, account.name); SingleAccountHelper.applyCurrentAccount(l_context, account.name);
accountAccessDone(); accountAccessDone();
} }

View File

@ -28,8 +28,6 @@ import android.view.LayoutInflater;
import android.view.MenuItem; import android.view.MenuItem;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.Filter;
import android.widget.Filterable;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.PopupMenu; import android.widget.PopupMenu;
import android.widget.TextView; import android.widget.TextView;
@ -42,14 +40,13 @@ import org.threeten.bp.format.DateTimeFormatter;
import org.threeten.bp.format.FormatStyle; import org.threeten.bp.format.FormatStyle;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import it.danieleverducci.nextcloudmaps.R; import it.danieleverducci.nextcloudmaps.R;
import it.danieleverducci.nextcloudmaps.model.Geofavorite; import it.danieleverducci.nextcloudmaps.model.Geofavorite;
public class GeofavoriteAdapter extends RecyclerView.Adapter<GeofavoriteAdapter.GeofavoriteViewHolder> implements Filterable { public class GeofavoriteAdapter extends RecyclerView.Adapter<GeofavoriteAdapter.GeofavoriteViewHolder> {
public static final String TAG = "GeofavoriteAdapter"; public static final String TAG = "GeofavoriteAdapter";
@ -58,12 +55,11 @@ public class GeofavoriteAdapter extends RecyclerView.Adapter<GeofavoriteAdapter.
public static final int SORT_BY_CATEGORY = 2; public static final int SORT_BY_CATEGORY = 2;
public static final int SORT_BY_DISTANCE = 3; public static final int SORT_BY_DISTANCE = 3;
private Context context; private final Context context;
private ItemClickListener itemClickListener; private final ItemClickListener itemClickListener;
private DateTimeFormatter dateFormatter = DateTimeFormatter.ofLocalizedDate(FormatStyle.SHORT); private final DateTimeFormatter dateFormatter = DateTimeFormatter.ofLocalizedDate(FormatStyle.SHORT);
private List<Geofavorite> geofavoriteList = new ArrayList<>(); private List<Geofavorite> items = new ArrayList<>();
private List<Geofavorite> geofavoriteListFiltered = new ArrayList<>();
private int sortRule = SORT_BY_CREATED; private int sortRule = SORT_BY_CREATED;
// Contains the position of the element containing the overflow menu clicked // Contains the position of the element containing the overflow menu clicked
@ -75,15 +71,15 @@ public class GeofavoriteAdapter extends RecyclerView.Adapter<GeofavoriteAdapter.
} }
public void setGeofavoriteList(@NonNull List<Geofavorite> geofavoriteList) { public void setGeofavoriteList(@NonNull List<Geofavorite> geofavoriteList) {
this.geofavoriteList = geofavoriteList; this.items.clear();
this.geofavoriteListFiltered = new ArrayList<>(geofavoriteList); this.items.addAll(geofavoriteList);
performSort(); performSort();
notifyDataSetChanged(); notifyDataSetChanged();
} }
public Geofavorite get(int position) { public Geofavorite get(int position) {
return geofavoriteListFiltered.get(position); return items.get(position);
} }
public int getSortRule() { public int getSortRule() {
@ -106,7 +102,7 @@ public class GeofavoriteAdapter extends RecyclerView.Adapter<GeofavoriteAdapter.
@Override @Override
public void onBindViewHolder(@NonNull GeofavoriteViewHolder holder, int position) { public void onBindViewHolder(@NonNull GeofavoriteViewHolder holder, int position) {
Geofavorite geofavorite = geofavoriteListFiltered.get(position); Geofavorite geofavorite = items.get(position);
holder.tv_category.setText(geofavorite.categoryLetter()); holder.tv_category.setText(geofavorite.categoryLetter());
holder.setCategoryColor( holder.setCategoryColor(
@ -118,48 +114,9 @@ public class GeofavoriteAdapter extends RecyclerView.Adapter<GeofavoriteAdapter.
@Override @Override
public int getItemCount() { public int getItemCount() {
return geofavoriteListFiltered.size(); return items.size();
} }
@Override
public Filter getFilter() {
return filter;
}
Filter filter = new Filter() {
@Override
// Run on Background thread.
protected FilterResults performFiltering(CharSequence charSequence) {
FilterResults filterResults = new FilterResults();
List <Geofavorite> filteredGeofavorites = new ArrayList<>();
if (charSequence.toString().isEmpty()) {
filteredGeofavorites.addAll(geofavoriteList);
} else {
for (Geofavorite geofavorite : geofavoriteList) {
String query = charSequence.toString().toLowerCase();
if (geofavorite.getName() != null && geofavorite.getName().toLowerCase().contains(query)) {
filteredGeofavorites.add(geofavorite);
} else if (geofavorite.getComment() != null && geofavorite.getComment().toLowerCase().contains(query)) {
filteredGeofavorites.add(geofavorite);
}
}
}
filterResults.values = filteredGeofavorites;
return filterResults;
}
//Run on ui thread
@Override
protected void publishResults(CharSequence charSequence, FilterResults filterResults) {
geofavoriteListFiltered.clear();
geofavoriteListFiltered.addAll((Collection<? extends Geofavorite>) filterResults.values);
performSort();
notifyDataSetChanged();
}
};
class GeofavoriteViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener { class GeofavoriteViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
TextView tv_category, tv_title, tv_content, tv_date; TextView tv_category, tv_title, tv_content, tv_date;
ImageView bt_context_menu; ImageView bt_context_menu;
@ -211,13 +168,13 @@ public class GeofavoriteAdapter extends RecyclerView.Adapter<GeofavoriteAdapter.
private void performSort() { private void performSort() {
if (sortRule == SORT_BY_TITLE) { if (sortRule == SORT_BY_TITLE) {
Collections.sort(geofavoriteListFiltered, Geofavorite.ByTitleAZ); Collections.sort(items, Geofavorite.ByTitleAZ);
} else if (sortRule == SORT_BY_CREATED) { } else if (sortRule == SORT_BY_CREATED) {
Collections.sort(geofavoriteListFiltered, Geofavorite.ByLastCreated); Collections.sort(items, Geofavorite.ByLastCreated);
} else if (sortRule == SORT_BY_CATEGORY) { } else if (sortRule == SORT_BY_CATEGORY) {
Collections.sort(geofavoriteListFiltered, Geofavorite.ByCategory); Collections.sort(items, Geofavorite.ByCategory);
} else if (sortRule == SORT_BY_DISTANCE) { } else if (sortRule == SORT_BY_DISTANCE) {
Collections.sort(geofavoriteListFiltered, Geofavorite.ByDistance); Collections.sort(items, Geofavorite.ByDistance);
} }
} }

View File

@ -3,15 +3,15 @@ package it.danieleverducci.nextcloudmaps.activity.main;
import android.content.Context; import android.content.Context;
import androidx.lifecycle.LiveData; import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel; import androidx.lifecycle.ViewModel;
import java.util.HashSet;
import java.util.List; import java.util.List;
import it.danieleverducci.nextcloudmaps.model.Geofavorite; import it.danieleverducci.nextcloudmaps.model.Geofavorite;
import it.danieleverducci.nextcloudmaps.repository.GeofavoriteRepository; import it.danieleverducci.nextcloudmaps.repository.GeofavoriteRepository;
public class MainActivityViewModel extends ViewModel { public class GeofavoritesFragmentViewModel extends ViewModel {
private GeofavoriteRepository mRepo; private GeofavoriteRepository mRepo;
public void init(Context applicationContext) { public void init(Context applicationContext) {
@ -27,6 +27,10 @@ public class MainActivityViewModel extends ViewModel {
mRepo.updateGeofavorites(); mRepo.updateGeofavorites();
} }
public LiveData<HashSet<String>> getCategories(){
return mRepo.getCategories();
}
public void deleteGeofavorite(Geofavorite geofav) { public void deleteGeofavorite(Geofavorite geofav) {
mRepo.deleteGeofavorite(geofav); mRepo.deleteGeofavorite(geofav);
} }

View File

@ -17,38 +17,25 @@
package it.danieleverducci.nextcloudmaps.activity.main; package it.danieleverducci.nextcloudmaps.activity.main;
import android.content.DialogInterface; import android.Manifest;
import android.content.Intent; import android.content.Intent;
import android.content.SharedPreferences; import android.content.pm.PackageManager;
import android.os.Bundle; import android.os.Bundle;
import android.text.TextUtils;
import android.util.Log;
import android.view.View; import android.view.View;
import android.widget.Toast;
import androidx.annotation.Nullable; import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog; import androidx.core.app.ActivityCompat;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.AppCompatImageButton;
import androidx.appcompat.widget.AppCompatImageView;
import androidx.appcompat.widget.SearchView;
import androidx.appcompat.widget.Toolbar;
import androidx.core.view.GravityCompat; import androidx.core.view.GravityCompat;
import androidx.drawerlayout.widget.DrawerLayout; import androidx.drawerlayout.widget.DrawerLayout;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager; import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentTransaction; import androidx.fragment.app.FragmentTransaction;
import androidx.lifecycle.ViewModelProvider;
import androidx.preference.PreferenceManager;
import androidx.recyclerview.widget.RecyclerView; import androidx.recyclerview.widget.RecyclerView;
import androidx.recyclerview.widget.StaggeredGridLayoutManager;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
import com.google.android.material.card.MaterialCardView;
import com.google.android.material.floatingactionbutton.FloatingActionButton; import com.google.android.material.floatingactionbutton.FloatingActionButton;
import com.nextcloud.android.sso.helper.SingleAccountHelper; import com.nextcloud.android.sso.helper.SingleAccountHelper;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List;
import it.danieleverducci.nextcloudmaps.R; import it.danieleverducci.nextcloudmaps.R;
import it.danieleverducci.nextcloudmaps.activity.NextcloudMapsStyledActivity; import it.danieleverducci.nextcloudmaps.activity.NextcloudMapsStyledActivity;
@ -56,124 +43,87 @@ import it.danieleverducci.nextcloudmaps.activity.about.AboutActivity;
import it.danieleverducci.nextcloudmaps.activity.detail.GeofavoriteDetailActivity; import it.danieleverducci.nextcloudmaps.activity.detail.GeofavoriteDetailActivity;
import it.danieleverducci.nextcloudmaps.activity.login.LoginActivity; import it.danieleverducci.nextcloudmaps.activity.login.LoginActivity;
import it.danieleverducci.nextcloudmaps.activity.main.NavigationAdapter.NavigationItem; import it.danieleverducci.nextcloudmaps.activity.main.NavigationAdapter.NavigationItem;
import it.danieleverducci.nextcloudmaps.activity.main.SortingOrderDialogFragment.OnSortingOrderListener;
import it.danieleverducci.nextcloudmaps.activity.mappicker.MapPickerActivity; import it.danieleverducci.nextcloudmaps.activity.mappicker.MapPickerActivity;
import it.danieleverducci.nextcloudmaps.api.ApiProvider; import it.danieleverducci.nextcloudmaps.api.ApiProvider;
import it.danieleverducci.nextcloudmaps.model.Geofavorite; import it.danieleverducci.nextcloudmaps.fragments.GeofavoriteListFragment;
import it.danieleverducci.nextcloudmaps.utils.GeoUriParser; import it.danieleverducci.nextcloudmaps.fragments.GeofavoriteMapFragment;
import it.danieleverducci.nextcloudmaps.utils.IntentGenerator; import it.danieleverducci.nextcloudmaps.repository.GeofavoriteRepository;
import it.danieleverducci.nextcloudmaps.utils.SettingsManager;
import static android.view.View.GONE; public class MainActivity extends NextcloudMapsStyledActivity {
import static android.view.View.VISIBLE;
import static it.danieleverducci.nextcloudmaps.activity.main.GeofavoriteAdapter.*;
import static it.danieleverducci.nextcloudmaps.activity.main.GeofavoriteAdapter.SORT_BY_CREATED;
import static it.danieleverducci.nextcloudmaps.activity.main.GeofavoriteAdapter.SORT_BY_TITLE;
import androidx.lifecycle.Observer;
public class MainActivity extends NextcloudMapsStyledActivity implements OnSortingOrderListener {
private static final String TAG = "MainActivity"; private static final String TAG = "MainActivity";
private static final int PERMISSION_REQUEST_CODE = 3890;
private static final String NAVIGATION_KEY_ADD_GEOFAVORITE_FROM_GPS = "add_from_gps"; private static final String NAVIGATION_KEY_ADD_GEOFAVORITE_FROM_GPS = "add_from_gps";
private static final String NAVIGATION_KEY_ADD_GEOFAVORITE_FROM_MAP = "add_from_map"; private static final String NAVIGATION_KEY_ADD_GEOFAVORITE_FROM_MAP = "add_from_map";
private static final String NAVIGATION_KEY_SHOW_ABOUT = "about"; private static final String NAVIGATION_KEY_SHOW_ABOUT = "about";
private static final String NAVIGATION_KEY_SWITCH_ACCOUNT = "switch_account"; private static final String NAVIGATION_KEY_SWITCH_ACCOUNT = "switch_account";
private SharedPreferences preferences; private ArrayList<OnGpsPermissionGrantedListener> onGpsPermissionGrantedListener = new ArrayList<>();
private DrawerLayout drawerLayout; private DrawerLayout drawerLayout;
private Toolbar toolbar;
private MaterialCardView homeToolbar;
private SearchView searchView;
private SwipeRefreshLayout swipeRefresh;
private RecyclerView recyclerView;
private StaggeredGridLayoutManager layoutManager;
private FloatingActionButton fab;
private GeofavoriteAdapter geofavoriteAdapter;
private ItemClickListener rvItemClickListener;
private MainActivityViewModel mMainActivityViewModel;
private boolean isFabOpen = false; private boolean isFabOpen = false;
NavigationAdapter navigationCommonAdapter; NavigationAdapter navigationCommonAdapter;
public void openDrawer() {
drawerLayout.openDrawer(GravityCompat.START);
}
public void showMap() {
replaceFragment(new GeofavoriteMapFragment());
SettingsManager.setGeofavoriteListShownAsMap(this, true);
}
public void showList() {
replaceFragment(new GeofavoriteListFragment());
SettingsManager.setGeofavoriteListShownAsMap(this, false);
}
public void addOnGpsPermissionGrantedListener(OnGpsPermissionGrantedListener l) {
onGpsPermissionGrantedListener.add(l);
}
public void removeOnGpsPermissionGrantedListener(OnGpsPermissionGrantedListener l) {
onGpsPermissionGrantedListener.remove(l);
}
public void requestGpsPermissions() {
ActivityCompat.requestPermissions(
this,
new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
PERMISSION_REQUEST_CODE
);
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == PERMISSION_REQUEST_CODE && permissions[0].equals(Manifest.permission.ACCESS_FINE_LOCATION)) {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
for (OnGpsPermissionGrantedListener l : onGpsPermissionGrantedListener) {
l.onGpsPermissionGranted();
}
}
}
}
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); setContentView(R.layout.activity_main);
preferences = PreferenceManager.getDefaultSharedPreferences(getApplicationContext()); boolean showMap = SettingsManager.isGeofavoriteListShownAsMap(this);
if (showMap)
showMap();
else
showList();
int sortRule = preferences.getInt(getString(R.string.setting_sort_by), SORT_BY_CREATED); FloatingActionButton fab = findViewById(R.id.open_fab);
boolean gridViewEnabled = preferences.getBoolean(getString(R.string.setting_grid_view_enabled), false);
recyclerView = findViewById(R.id.recycler_view);
layoutManager = new StaggeredGridLayoutManager(gridViewEnabled ? 2 : 1, StaggeredGridLayoutManager.VERTICAL);
recyclerView.setLayoutManager(layoutManager);
rvItemClickListener = new ItemClickListener() {
@Override
public void onItemClick(Geofavorite item) {
showGeofavoriteDetailActivity(item);
}
@Override
public void onItemShareClick(Geofavorite item) {
startActivity(Intent.createChooser(IntentGenerator.newShareIntent(MainActivity.this, item), getString(R.string.share_via)));
}
@Override
public void onItemNavClick(Geofavorite item) {
startActivity(IntentGenerator.newGeoUriIntent(MainActivity.this, item));
}
@Override
public void onItemDeleteClick(Geofavorite item) {
showGeofavoriteDeteleDialog(item);
}
};
geofavoriteAdapter = new GeofavoriteAdapter(this, rvItemClickListener);
recyclerView.setAdapter(geofavoriteAdapter);
geofavoriteAdapter.setSortRule(sortRule);
mMainActivityViewModel = new ViewModelProvider(this).get(MainActivityViewModel.class);
mMainActivityViewModel.init(getApplicationContext());
mMainActivityViewModel.getIsUpdating().observe(this, new Observer<Boolean>() {
@Override
public void onChanged(@Nullable Boolean aBoolean) {
if(aBoolean){
swipeRefresh.setRefreshing(true);
}
else{
swipeRefresh.setRefreshing(false);
}
}
});
mMainActivityViewModel.getOnFinished().observe(this, new Observer<Boolean>() {
@Override
public void onChanged(@Nullable Boolean success) {
if(success == null || !success){
Toast.makeText(MainActivity.this, R.string.list_geofavorite_connection_error, Toast.LENGTH_LONG).show();
}
}
});
mMainActivityViewModel.getGeofavorites().observe(this, new Observer<List<Geofavorite>>() {
@Override
public void onChanged(List<Geofavorite> geofavorites) {
geofavoriteAdapter.setGeofavoriteList(geofavorites);
}
});
mMainActivityViewModel.updateGeofavorites();
swipeRefresh = findViewById(R.id.swipe_refresh);
swipeRefresh.setOnRefreshListener(() ->
mMainActivityViewModel.updateGeofavorites());
fab = findViewById(R.id.open_fab);
fab.setOnClickListener(view -> openFab(!this.isFabOpen)); fab.setOnClickListener(view -> openFab(!this.isFabOpen));
fab = findViewById(R.id.add_from_gps); fab = findViewById(R.id.add_from_gps);
@ -182,51 +132,9 @@ public class MainActivity extends NextcloudMapsStyledActivity implements OnSorti
fab = findViewById(R.id.add_from_map); fab = findViewById(R.id.add_from_map);
fab.setOnClickListener(view -> addGeofavoriteFromMap()); fab.setOnClickListener(view -> addGeofavoriteFromMap());
toolbar = findViewById(R.id.toolbar);
homeToolbar = findViewById(R.id.home_toolbar);
searchView = findViewById(R.id.search_view);
searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
@Override
public boolean onQueryTextSubmit(String query) {
return false;
}
@Override
public boolean onQueryTextChange(String query) {
geofavoriteAdapter.getFilter().filter(query);
return false;
}
});
searchView.setOnCloseListener(() -> {
if (toolbar.getVisibility() == VISIBLE && TextUtils.isEmpty(searchView.getQuery())) {
updateToolbars(true);
return true;
}
return false;
});
setSupportActionBar(toolbar);
setupNavigationMenu(); setupNavigationMenu();
homeToolbar.setOnClickListener(view -> updateToolbars(false));
AppCompatImageView sortButton = findViewById(R.id.sort_mode);
sortButton.setOnClickListener(view -> openSortingOrderDialogFragment(getSupportFragmentManager(), geofavoriteAdapter.getSortRule()));
drawerLayout = findViewById(R.id.drawerLayout); drawerLayout = findViewById(R.id.drawerLayout);
AppCompatImageButton menuButton = findViewById(R.id.menu_button);
menuButton.setOnClickListener(view -> drawerLayout.openDrawer(GravityCompat.START));
AppCompatImageView viewButton = findViewById(R.id.view_mode);
viewButton.setOnClickListener(view -> {
boolean gridEnabled = layoutManager.getSpanCount() == 1;
onGridIconChosen(gridEnabled);
});
updateSortingIcon(sortRule);
updateGridIcon(gridViewEnabled);
} }
@Override @Override
@ -235,6 +143,13 @@ public class MainActivity extends NextcloudMapsStyledActivity implements OnSorti
super.onPause(); super.onPause();
} }
private void replaceFragment(Fragment fragment) {
FragmentManager manager = getSupportFragmentManager();
FragmentTransaction transaction = manager.beginTransaction();
transaction.replace(R.id.fragment_container, fragment);
transaction.commit();
}
private void setupNavigationMenu() { private void setupNavigationMenu() {
ArrayList<NavigationItem> navItems = new ArrayList<>(); ArrayList<NavigationItem> navItems = new ArrayList<>();
@ -265,22 +180,6 @@ public class MainActivity extends NextcloudMapsStyledActivity implements OnSorti
navigationMenuCommon.setAdapter(navigationCommonAdapter); navigationMenuCommon.setAdapter(navigationCommonAdapter);
} }
private void updateToolbars(boolean disableSearch) {
homeToolbar.setVisibility(disableSearch ? VISIBLE : GONE);
toolbar.setVisibility(disableSearch ? GONE : VISIBLE);
if (disableSearch) {
searchView.setQuery(null, true);
}
searchView.setIconified(disableSearch);
}
private void openSortingOrderDialogFragment(FragmentManager supportFragmentManager, int sortOrder) {
FragmentTransaction fragmentTransaction = supportFragmentManager.beginTransaction();
fragmentTransaction.addToBackStack(null);
SortingOrderDialogFragment.newInstance(sortOrder).show(fragmentTransaction, SortingOrderDialogFragment.SORTING_ORDER_FRAGMENT);
}
private void addGeofavoriteFromGps() { private void addGeofavoriteFromGps() {
startActivity( startActivity(
new Intent(this, GeofavoriteDetailActivity.class) new Intent(this, GeofavoriteDetailActivity.class)
@ -297,77 +196,15 @@ public class MainActivity extends NextcloudMapsStyledActivity implements OnSorti
startActivity(new Intent(this, AboutActivity.class)); startActivity(new Intent(this, AboutActivity.class));
} }
private void switch_account() { public void switch_account() {
ApiProvider.logout(); ApiProvider.logout();
SingleAccountHelper.setCurrentAccount(this, null); GeofavoriteRepository.resetInstance();
SingleAccountHelper.applyCurrentAccount(this, null);
Intent intent = new Intent(MainActivity.this, LoginActivity.class); Intent intent = new Intent(MainActivity.this, LoginActivity.class);
startActivity(intent); startActivity(intent);
finish(); finish();
} }
@Override
public void onSortingOrderChosen(int sortSelection) {
geofavoriteAdapter.setSortRule(sortSelection);
updateSortingIcon(sortSelection);
preferences.edit().putInt(getString(R.string.setting_sort_by), sortSelection).apply();
}
public void updateSortingIcon(int sortSelection) {
AppCompatImageView sortButton = findViewById(R.id.sort_mode);
switch (sortSelection) {
case SORT_BY_TITLE:
sortButton.setImageResource(R.drawable.ic_alphabetical_asc);
break;
case SORT_BY_CREATED:
sortButton.setImageResource(R.drawable.ic_modification_asc);
break;
case SORT_BY_CATEGORY:
sortButton.setImageResource(R.drawable.ic_category_asc);
break;
case SORT_BY_DISTANCE:
sortButton.setImageResource(R.drawable.ic_distance_asc);
break;
}
}
public void onGridIconChosen(boolean gridEnabled) {
layoutManager.setSpanCount(gridEnabled ? 2 : 1);
updateGridIcon(gridEnabled);
preferences.edit().putBoolean(getString(R.string.setting_grid_view_enabled), gridEnabled).apply();
}
public void updateGridIcon(boolean gridEnabled) {
AppCompatImageView viewButton = findViewById(R.id.view_mode);
viewButton.setImageResource(gridEnabled ? R.drawable.ic_view_list : R.drawable.ic_view_module);
}
private void showGeofavoriteDeteleDialog(Geofavorite item) {
AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
builder.setMessage(getString(R.string.dialog_delete_message).replace("{name}", item.getName() != null ? item.getName() : ""))
.setTitle(R.string.dialog_delete_title)
.setPositiveButton(R.string.dialog_delete_delete, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
mMainActivityViewModel.deleteGeofavorite(item);
dialog.dismiss();
}
})
.setNegativeButton(R.string.dialog_delete_cancel, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
dialog.dismiss();
}
});
AlertDialog ad = builder.create();
ad.show();
}
private void showGeofavoriteDetailActivity(Geofavorite item) {
Intent i = new Intent(this, GeofavoriteDetailActivity.class);
i.putExtra(GeofavoriteDetailActivity.ARG_GEOFAVORITE, item.getId());
startActivity(i);
}
private void openFab(boolean open) { private void openFab(boolean open) {
View fab = findViewById(R.id.open_fab); View fab = findViewById(R.id.open_fab);
View addFromGpsFab = findViewById(R.id.add_from_gps); View addFromGpsFab = findViewById(R.id.add_from_gps);
@ -387,4 +224,8 @@ public class MainActivity extends NextcloudMapsStyledActivity implements OnSorti
} }
public interface OnGpsPermissionGrantedListener {
public void onGpsPermissionGranted();
}
} }

View File

@ -48,6 +48,7 @@ public class SortingOrderDialogFragment extends DialogFragment {
public static final String SORTING_ORDER_FRAGMENT = "SORTING_ORDER_FRAGMENT"; public static final String SORTING_ORDER_FRAGMENT = "SORTING_ORDER_FRAGMENT";
private static final String KEY_SORT_ORDER = "SORT_ORDER"; private static final String KEY_SORT_ORDER = "SORT_ORDER";
private OnSortingOrderListener onSortingOrderListener;
private View mView; private View mView;
private View[] mTaggedViews; private View[] mTaggedViews;
private Button mCancel; private Button mCancel;
@ -90,6 +91,10 @@ public class SortingOrderDialogFragment extends DialogFragment {
return mView; return mView;
} }
public void setOnSortingOrderListener(OnSortingOrderListener listener) {
this.onSortingOrderListener = listener;
}
/** /**
* find all relevant UI elements and set their values. * find all relevant UI elements and set their values.
* TODO: this is REALLY ugly. * TODO: this is REALLY ugly.
@ -171,8 +176,8 @@ public class SortingOrderDialogFragment extends DialogFragment {
@Override @Override
public void onClick(View v) { public void onClick(View v) {
dismissAllowingStateLoss(); dismissAllowingStateLoss();
((SortingOrderDialogFragment.OnSortingOrderListener) getActivity()) if (onSortingOrderListener != null)
.onSortingOrderChosen((int) v.getTag()); onSortingOrderListener.onSortingOrderChosen((int) v.getTag());
} }
} }

View File

@ -0,0 +1,153 @@
package it.danieleverducci.nextcloudmaps.fragments;
import static it.danieleverducci.nextcloudmaps.activity.main.GeofavoriteAdapter.SORT_BY_CATEGORY;
import static it.danieleverducci.nextcloudmaps.activity.main.GeofavoriteAdapter.SORT_BY_CREATED;
import static it.danieleverducci.nextcloudmaps.activity.main.GeofavoriteAdapter.SORT_BY_DISTANCE;
import static it.danieleverducci.nextcloudmaps.activity.main.GeofavoriteAdapter.SORT_BY_TITLE;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.widget.AppCompatImageView;
import androidx.fragment.app.FragmentTransaction;
import androidx.lifecycle.Observer;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
import java.util.ArrayList;
import java.util.List;
import it.danieleverducci.nextcloudmaps.R;
import it.danieleverducci.nextcloudmaps.activity.main.GeofavoriteAdapter;
import it.danieleverducci.nextcloudmaps.activity.main.MainActivity;
import it.danieleverducci.nextcloudmaps.activity.main.SortingOrderDialogFragment;
import it.danieleverducci.nextcloudmaps.model.Geofavorite;
import it.danieleverducci.nextcloudmaps.utils.GeofavoritesFilter;
import it.danieleverducci.nextcloudmaps.utils.SettingsManager;
public class GeofavoriteListFragment extends GeofavoritesFragment implements SortingOrderDialogFragment.OnSortingOrderListener {
private SwipeRefreshLayout swipeRefresh;
private GeofavoriteAdapter geofavoriteAdapter;
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_geofavorite_list, container, false);
// Setup list
int sortRule = SettingsManager.getGeofavoriteListSortBy(requireContext());
RecyclerView recyclerView = v.findViewById(R.id.recycler_view);
LinearLayoutManager layoutManager = new LinearLayoutManager(requireContext());
recyclerView.setLayoutManager(layoutManager);
GeofavoriteAdapter.ItemClickListener rvItemClickListener = new GeofavoriteAdapter.ItemClickListener() {
@Override
public void onItemClick(Geofavorite item) {
openGeofavorite(item);
}
@Override
public void onItemShareClick(Geofavorite item) {
shareGeofavorite(item);
}
@Override
public void onItemNavClick(Geofavorite item) {
navigateToGeofavorite(item);
}
@Override
public void onItemDeleteClick(Geofavorite item) {
deleteGeofavorite(item);
}
};
geofavoriteAdapter = new GeofavoriteAdapter(requireContext(), rvItemClickListener);
recyclerView.setAdapter(geofavoriteAdapter);
geofavoriteAdapter.setSortRule(sortRule);
// Register for data source events
mGeofavoritesFragmentViewModel.getIsUpdating().observe(getViewLifecycleOwner(), new Observer<Boolean>() {
@Override
public void onChanged(@Nullable Boolean changed) {
if(Boolean.TRUE.equals(changed)){
swipeRefresh.setRefreshing(true);
}
else{
swipeRefresh.setRefreshing(false);
}
}
});
// Setup view listeners
swipeRefresh = v.findViewById(R.id.swipe_refresh);
swipeRefresh.setOnRefreshListener(() ->
mGeofavoritesFragmentViewModel.updateGeofavorites());
AppCompatImageView sortButton = v.findViewById(R.id.sort_mode);
sortButton.setOnClickListener(view -> openSortingOrderDialogFragment(geofavoriteAdapter.getSortRule()));
View showMapButton = v.findViewById(R.id.view_mode_map);
showMapButton.setOnClickListener(View -> ((MainActivity)requireActivity()).showMap());
return v;
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
// Set icons
int sortRule = SettingsManager.getGeofavoriteListSortBy(requireContext());
updateSortingIcon(sortRule);
}
@Override
public void onDatasetChange(List<Geofavorite> items) {
// Called when the items are loaded or a filtering happens
geofavoriteAdapter.setGeofavoriteList(items);
}
@Override
public void onSortingOrderChosen(int sortSelection) {
geofavoriteAdapter.setSortRule(sortSelection);
updateSortingIcon(sortSelection);
SettingsManager.setGeofavoriteListSortBy(requireContext(), sortSelection);
}
private void openSortingOrderDialogFragment(int sortOrder) {
FragmentTransaction fragmentTransaction = requireActivity().getSupportFragmentManager().beginTransaction();
fragmentTransaction.addToBackStack(null);
SortingOrderDialogFragment sodf = SortingOrderDialogFragment.newInstance(sortOrder);
sodf.setOnSortingOrderListener(this);
sodf.show(fragmentTransaction, SortingOrderDialogFragment.SORTING_ORDER_FRAGMENT);
}
private void updateSortingIcon(int sortSelection) {
AppCompatImageView sortButton = requireView().findViewById(R.id.sort_mode);
switch (sortSelection) {
case SORT_BY_TITLE:
sortButton.setImageResource(R.drawable.ic_alphabetical_asc);
break;
case SORT_BY_CREATED:
sortButton.setImageResource(R.drawable.ic_modification_asc);
break;
case SORT_BY_CATEGORY:
sortButton.setImageResource(R.drawable.ic_category_asc);
break;
case SORT_BY_DISTANCE:
sortButton.setImageResource(R.drawable.ic_distance_asc);
break;
}
}
}

View File

@ -0,0 +1,232 @@
package it.danieleverducci.nextcloudmaps.fragments;
import android.Manifest;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.content.res.AppCompatResources;
import androidx.core.app.ActivityCompat;
import androidx.core.graphics.drawable.DrawableCompat;
import androidx.lifecycle.Observer;
import org.osmdroid.api.IMapController;
import org.osmdroid.events.MapEventsReceiver;
import org.osmdroid.util.GeoPoint;
import org.osmdroid.views.CustomZoomButtonsController;
import org.osmdroid.views.MapView;
import org.osmdroid.views.overlay.MapEventsOverlay;
import org.osmdroid.views.overlay.Marker;
import org.osmdroid.views.overlay.Overlay;
import org.osmdroid.views.overlay.infowindow.InfoWindow;
import org.osmdroid.views.overlay.mylocation.GpsMyLocationProvider;
import org.osmdroid.views.overlay.mylocation.MyLocationNewOverlay;
import java.util.List;
import java.util.Set;
import it.danieleverducci.nextcloudmaps.R;
import it.danieleverducci.nextcloudmaps.activity.detail.GeofavoriteDetailActivity;
import it.danieleverducci.nextcloudmaps.activity.main.MainActivity;
import it.danieleverducci.nextcloudmaps.activity.mappicker.MapPickerActivity;
import it.danieleverducci.nextcloudmaps.model.Geofavorite;
import it.danieleverducci.nextcloudmaps.utils.GeoUriParser;
import it.danieleverducci.nextcloudmaps.utils.MapUtils;
import it.danieleverducci.nextcloudmaps.utils.SettingsManager;
import it.danieleverducci.nextcloudmaps.views.GeofavMarkerInfoWindow;
public class GeofavoriteMapFragment extends GeofavoritesFragment implements MainActivity.OnGpsPermissionGrantedListener {
private MapView map;
private MyLocationNewOverlay mLocationOverlay;
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
MapUtils.configOsmdroid(requireContext());
}
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_geofavorite_map, container, false);
// Register listeners
v.findViewById(R.id.center_position).setOnClickListener((cpv) -> moveToUserPosition());
// Setup map
map = v.findViewById(R.id.map);
map.getZoomController().setVisibility(CustomZoomButtonsController.Visibility.NEVER);
map.setMultiTouchControls(true);
MapUtils.setTheme(map);
MapEventsOverlay meo = new MapEventsOverlay(new MapEventsReceiver() {
@Override
public boolean singleTapConfirmedHelper(GeoPoint p) {
InfoWindow.closeAllInfoWindowsOn(map);
return false;
}
@Override
public boolean longPressHelper(GeoPoint p) {
// Create new geofavorite (go to geofav creation activity)
Uri geoUri = GeoUriParser.createGeoUri(p.getLatitude(), p.getLongitude(), null);
Intent i = new Intent(requireActivity(), GeofavoriteDetailActivity.class);
i.setData(geoUri);
startActivity(i);
return true;
}
});
map.getOverlays().add(0, meo);
showUserPosition();
// Setup view listeners
View showListButton = v.findViewById(R.id.view_mode_list);
showListButton.setOnClickListener(View -> ((MainActivity)requireActivity()).showList());
View loadingWall = v.findViewById(R.id.loading_wall);
// Register for data source events
mGeofavoritesFragmentViewModel.getIsUpdating().observe(getViewLifecycleOwner(), new Observer<Boolean>() {
@Override
public void onChanged(@Nullable Boolean changed) {
if(Boolean.TRUE.equals(changed)){
loadingWall.setVisibility(View.VISIBLE);
}
else{
loadingWall.setVisibility(View.GONE);
}
}
});
return v;
}
@Override
public void onStart() {
super.onStart();
((MainActivity)requireActivity()).addOnGpsPermissionGrantedListener(this);
}
@Override
public void onDatasetChange(List<Geofavorite> items) {
clearAllMarkers();
for(Geofavorite gf : items)
addMarker(gf);
map.invalidate();
}
@Override
public void onStop() {
super.onStop();
((MainActivity)requireActivity()).removeOnGpsPermissionGrantedListener(this);
SettingsManager.setLastMapPosition(
requireContext(),
map.getMapCenter().getLatitude(),
map.getMapCenter().getLongitude(),
map.getZoomLevelDouble()
);
}
@Override
public void onGpsPermissionGranted() {
showUserPosition();
}
private void showUserPosition() {
// Center map on last position
double[] pos = SettingsManager.getLastMapPosition(requireContext());
IMapController mapController = map.getController();
mapController.setCenter(new GeoPoint(pos[0], pos[1]));
mapController.setZoom(pos[2]);
// Check if user granted location permission
if (ActivityCompat.checkSelfPermission(requireContext(), Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED &&
ActivityCompat.checkSelfPermission(requireContext(), Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED
) {
// User didn't grant permission. Ask it.
((MainActivity)requireActivity()).requestGpsPermissions();
return;
}
// Display user position on screen
mLocationOverlay = new MyLocationNewOverlay(new GpsMyLocationProvider(requireContext()), map);
// On first gps fix, show "center to my position" icon
mLocationOverlay.runOnFirstFix(() -> {
if(getActivity() != null) {
getActivity().runOnUiThread(() -> {
getView().findViewById(R.id.center_position).setVisibility(View.VISIBLE);
});
}
});
mLocationOverlay.enableMyLocation();
map.getOverlays().add(mLocationOverlay);
}
void moveToUserPosition() {
if (mLocationOverlay != null)
map.getController().animateTo(mLocationOverlay.getMyLocation());
}
private void addMarker(Geofavorite geofavorite){
GeoPoint pos = new GeoPoint(geofavorite.getLat(), geofavorite.getLng());
// Set icon and color
Drawable icon = DrawableCompat.wrap(AppCompatResources.getDrawable(requireContext(), R.drawable.ic_map_pin));
DrawableCompat.setTint(icon, geofavorite.categoryColor() == 0 ? requireContext().getColor(R.color.defaultBrand) : geofavorite.categoryColor());
// Set infowindow (popup opened on marker click) and its listeners
GeofavMarkerInfoWindow iw = new GeofavMarkerInfoWindow(map, geofavorite);
iw.setOnGeofavMarkerInfoWindowClickListener(new GeofavMarkerInfoWindow.OnGeofavMarkerInfoWindowClickListener() {
@Override
public void onGeofavMarkerInfoWindowEditClick() {
openGeofavorite(geofavorite);
}
@Override
public void onGeofavMarkerInfoWindowShareClick() {
shareGeofavorite(geofavorite);
}
@Override
public void onGeofavMarkerInfoWindowNavClick() {
navigateToGeofavorite(geofavorite);
}
@Override
public void onGeofavMarkerInfoWindowDeleteClick() {
deleteGeofavorite(geofavorite);
}
});
// Set marker
Marker m = new Marker(map);
m.setPosition(pos);
m.setAnchor(Marker.ANCHOR_CENTER, Marker.ANCHOR_BOTTOM);
m.setIcon(icon);
m.setTitle(geofavorite.getName());
m.setSnippet(geofavorite.getComment());
m.setSubDescription(geofavorite.getCategory());
m.setInfoWindow(iw);
map.getOverlays().add(m);
}
private void clearAllMarkers() {
// Close any open infowindow before removing related marker
InfoWindow.closeAllInfoWindowsOn(map);
// Remove all markers, leaving the other overlays (user position and tap listener ones)
for(Overlay o : map.getOverlays()) {
if (o instanceof Marker) {
map.getOverlays().remove(o);
}
}
}
}

View File

@ -0,0 +1,270 @@
package it.danieleverducci.nextcloudmaps.fragments;
import static android.view.View.GONE;
import static android.view.View.VISIBLE;
import android.content.DialogInterface;
import android.content.Intent;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.Handler;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import android.widget.ImageButton;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.widget.AppCompatImageButton;
import androidx.appcompat.widget.AppCompatImageView;
import androidx.appcompat.widget.SearchView;
import androidx.core.graphics.drawable.DrawableCompat;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProvider;
import com.nextcloud.android.sso.helper.SingleAccountHelper;
import com.nextcloud.android.sso.model.SingleSignOnAccount;
import com.squareup.picasso.Picasso;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import it.danieleverducci.nextcloudmaps.R;
import it.danieleverducci.nextcloudmaps.activity.detail.CategoriesAdapter;
import it.danieleverducci.nextcloudmaps.activity.detail.GeofavoriteDetailActivity;
import it.danieleverducci.nextcloudmaps.activity.main.GeofavoritesFragmentViewModel;
import it.danieleverducci.nextcloudmaps.activity.main.MainActivity;
import it.danieleverducci.nextcloudmaps.model.Geofavorite;
import it.danieleverducci.nextcloudmaps.utils.GeofavoritesFilter;
import it.danieleverducci.nextcloudmaps.utils.IntentGenerator;
/**
* Separates the specific list/map implementation details providing a standard interface
* to communicate with the activity
*/
public abstract class GeofavoritesFragment extends Fragment {
private final String TAG = "GeofavoritesFragment";
protected GeofavoritesFragmentViewModel mGeofavoritesFragmentViewModel;
private View toolbar;
private View homeToolbar;
private SearchView searchView;
private ImageButton filterButton;
private List<Geofavorite> geofavorites = new ArrayList<>();
private HashSet<String> categories = new HashSet<>();
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Load data
mGeofavoritesFragmentViewModel = new ViewModelProvider(this).get(GeofavoritesFragmentViewModel.class);
mGeofavoritesFragmentViewModel.init(requireContext());
mGeofavoritesFragmentViewModel.getOnFinished().observe(this, new Observer<Boolean>() {
@Override
public void onChanged(@Nullable Boolean success) {
if(success == null || !success){
Toast.makeText(requireContext(), R.string.list_geofavorite_connection_error, Toast.LENGTH_LONG).show();
}
}
});
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
// Set views
AppCompatImageButton menuButton = view.findViewById(R.id.menu_button);
menuButton.setOnClickListener(v -> ((MainActivity)requireActivity()).openDrawer());
View userBadgeContainer = view.findViewById(R.id.user_badge_container);
userBadgeContainer.setOnClickListener(v -> showSwitchAccountDialog());
// Setup toolbar/searchbar
toolbar = view.findViewById(R.id.toolbar);
homeToolbar = view.findViewById(R.id.home_toolbar);
filterButton = view.findViewById(R.id.search_filter);
filterButton.setOnClickListener(v -> showCategoryFilterDialog());
searchView = view.findViewById(R.id.search_view);
searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
@Override
public boolean onQueryTextSubmit(String query) {
return false;
}
@Override
public boolean onQueryTextChange(String query) {
onDatasetChange(
(new GeofavoritesFilter(geofavorites)).byText(query)
);
return false;
}
});
mGeofavoritesFragmentViewModel.getGeofavorites().observe(getViewLifecycleOwner(), new Observer<List<Geofavorite>>() {
@Override
public void onChanged(List<Geofavorite> geofavorites) {
GeofavoritesFragment.this.geofavorites = geofavorites;
onDatasetChange(geofavorites);
}
});
mGeofavoritesFragmentViewModel.getCategories().observe(getViewLifecycleOwner(), new Observer<HashSet<String>>() {
@Override
public void onChanged(HashSet<String> categories) {
GeofavoritesFragment.this.categories = categories;
}
});
searchView.setOnCloseListener(() -> {
if (toolbar.getVisibility() == VISIBLE && TextUtils.isEmpty(searchView.getQuery())) {
updateToolbars(true);
return true;
}
return false;
});
homeToolbar.setOnClickListener(v -> updateToolbars(false));
// Set user badge (async)
Handler h = new Handler();
h.post(() -> {
try {
SingleSignOnAccount ssoAccount = SingleAccountHelper.getCurrentSingleSignOnAccount(requireContext());
String userBadgePath = ssoAccount.url + "/index.php/avatar/" + ssoAccount.userId + "/64";
if (getActivity() != null)
getActivity().runOnUiThread(
() -> Picasso.get().load(userBadgePath).into((AppCompatImageView)userBadgeContainer.findViewById(R.id.user_badge))
);
} catch (Exception e) {
Log.e(TAG, "Unable to load user image: " + e.toString());
}
});
}
@Override
public void onStart() {
super.onStart();
// Reset filter and update data
filterButton.setImageResource(R.drawable.ic_filter_off);
mGeofavoritesFragmentViewModel.updateGeofavorites();
}
abstract public void onDatasetChange(List<Geofavorite> items);
protected void openGeofavorite(Geofavorite item) {
showGeofavoriteDetailActivity(item);
}
protected void shareGeofavorite(Geofavorite item) {
startActivity(Intent.createChooser(IntentGenerator.newShareIntent(requireActivity(), item), getString(R.string.share_via)));
}
protected void navigateToGeofavorite(Geofavorite item) {
startActivity(IntentGenerator.newGeoUriIntent(requireActivity(), item));
}
protected void deleteGeofavorite(Geofavorite item) {
showGeofavoriteDeteleDialog(item);
}
private void showGeofavoriteDetailActivity(Geofavorite item) {
Intent i = new Intent(requireContext(), GeofavoriteDetailActivity.class);
i.putExtra(GeofavoriteDetailActivity.ARG_GEOFAVORITE, item.getId());
startActivity(i);
}
private void showGeofavoriteDeteleDialog(Geofavorite item) {
AlertDialog.Builder builder = new AlertDialog.Builder(requireContext());
builder.setMessage(getString(R.string.dialog_delete_message).replace("{name}", item.getName() != null ? item.getName() : ""))
.setTitle(R.string.dialog_delete_title)
.setPositiveButton(R.string.dialog_delete_delete, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
mGeofavoritesFragmentViewModel.deleteGeofavorite(item);
dialog.dismiss();
}
})
.setNegativeButton(R.string.dialog_delete_cancel, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
dialog.dismiss();
}
});
AlertDialog ad = builder.create();
ad.show();
}
private void showSwitchAccountDialog() {
AlertDialog.Builder builder = new AlertDialog.Builder(requireContext());
builder.setMessage(R.string.dialog_logout_message)
.setTitle(R.string.dialog_logout_title)
.setPositiveButton(android.R.string.yes, (dialog, id) -> {
if (getActivity() != null)
((MainActivity) getActivity()).switch_account();
dialog.dismiss();
})
.setNegativeButton(android.R.string.no, (dialog, id) -> dialog.dismiss());
AlertDialog ad = builder.create();
ad.show();
}
private void showCategoryFilterDialog() {
if (categories.isEmpty()) {
Toast.makeText(requireContext(), R.string.filtering_unavailable, Toast.LENGTH_SHORT).show();
return;
}
AlertDialog.Builder builder = new AlertDialog.Builder(requireContext());
builder.setTitle(R.string.filtering_dialog_title);
CategoriesAdapter ca = new CategoriesAdapter(requireContext());
ca.setCategoriesList(categories);
builder.setAdapter(ca, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
// Set filter button enabled icon and color
String categoryName = ca.getItem(which);
filterButton.setImageResource(R.drawable.ic_filter);
Drawable d = filterButton.getDrawable();
DrawableCompat.setTint(
d,
Geofavorite.categoryColorFromName(categoryName) == 0
? requireContext().getColor(R.color.defaultBrand)
: Geofavorite.categoryColorFromName(categoryName)
);
filterByCategory(categoryName);
}
});
builder.setPositiveButton(R.string.filtering_dialog_cancel, (dialog, id) -> {
dialog.dismiss();
filterButton.setImageResource(R.drawable.ic_filter_off);
filterByCategory(null);
});
AlertDialog dialog = builder.create();
dialog.show();
}
private void updateToolbars(boolean disableSearch) {
homeToolbar.setVisibility(disableSearch ? VISIBLE : GONE);
toolbar.setVisibility(disableSearch ? GONE : VISIBLE);
if (disableSearch) {
searchView.setQuery(null, true);
}
searchView.setIconified(disableSearch);
}
private void filterByCategory(String category) {
onDatasetChange(
(new GeofavoritesFilter(geofavorites)).byCategory(category)
);
}
}

View File

@ -22,6 +22,7 @@ package it.danieleverducci.nextcloudmaps.model;
import android.graphics.Color; import android.graphics.Color;
import android.net.Uri; import android.net.Uri;
import android.widget.Filter;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
@ -34,7 +35,9 @@ import org.threeten.bp.LocalDate;
import org.threeten.bp.ZoneId; import org.threeten.bp.ZoneId;
import java.io.Serializable; import java.io.Serializable;
import java.util.ArrayList;
import java.util.Comparator; import java.util.Comparator;
import java.util.List;
import it.danieleverducci.nextcloudmaps.utils.GeoUriParser; import it.danieleverducci.nextcloudmaps.utils.GeoUriParser;
@ -201,17 +204,7 @@ public class Geofavorite implements Serializable {
* @return the generated color or null for the default category * @return the generated color or null for the default category
*/ */
public int categoryColor() { public int categoryColor() {
// If category is default, return null: will be used Nextcloud's accent return categoryColorFromName(this.category);
if (this.category == null || this.category.equals(DEFAULT_CATEGORY) || this.category.length() == 0)
return 0;
float letter1Index = this.category.toLowerCase().charAt(0);
float letter2Index = this.category.toLowerCase().charAt(1);
float letterCoef = ((letter1Index * letter2Index) % 100) / 100;
float h = letterCoef * 360;
float s = 75 + letterCoef * 10;
float l = 50 + letterCoef * 10;
return Color.HSVToColor( new float[]{ Math.round(h), Math.round(s), Math.round(l) });
} }
public String categoryLetter() { public String categoryLetter() {
@ -226,4 +219,27 @@ public class Geofavorite implements Serializable {
return "[" + getName() + " (" + getLat() + "," + getLng() + ")]"; return "[" + getName() + " (" + getLat() + "," + getLng() + ")]";
} }
/**
* Based on Nextcloud Maps's getLetterColor util.
* Assigns a color to a category based on its two first letters.
*
* @see "https://github.com/nextcloud/maps/blob/master/src/utils.js"
* @return the generated color or null for the default category
*/
public static int categoryColorFromName(String category) {
// If category is default, return null: will be used Nextcloud's accent
if (category == null || category.equals(DEFAULT_CATEGORY) || category.length() == 0)
return 0;
float letter1Index = category.toLowerCase().charAt(0);
float letter2Index = category.toLowerCase().charAt(1);
float letterCoef = ((letter1Index * letter2Index) % 100) / 100;
float h = letterCoef * 360;
float s = 75 + letterCoef * 10;
float l = 50 + letterCoef * 10;
return Color.HSVToColor( new float[]{ Math.round(h), Math.round(s), Math.round(l) });
}
} }

View File

@ -42,6 +42,10 @@ public class GeofavoriteRepository {
return instance; return instance;
} }
public static void resetInstance() {
instance = null;
}
public MutableLiveData<List<Geofavorite>> getGeofavorites(){ public MutableLiveData<List<Geofavorite>> getGeofavorites(){
if (mGeofavorites == null) { if (mGeofavorites == null) {
mGeofavorites = new MutableLiveData<>(); mGeofavorites = new MutableLiveData<>();

View File

@ -0,0 +1,47 @@
package it.danieleverducci.nextcloudmaps.utils;
import java.util.ArrayList;
import java.util.List;
import it.danieleverducci.nextcloudmaps.model.Geofavorite;
public class GeofavoritesFilter {
List<Geofavorite> items;
public GeofavoritesFilter(List<Geofavorite> items) {
this.items = items;
}
public List<Geofavorite> byText(String text) {
List<Geofavorite> filteredGeofavorites = new ArrayList<>();
if (text.isEmpty()) {
return items;
} else {
for (Geofavorite geofavorite : items) {
String query = text.toLowerCase();
if (geofavorite.getName() != null && geofavorite.getName().toLowerCase().contains(query)) {
filteredGeofavorites.add(geofavorite);
} else if (geofavorite.getComment() != null && geofavorite.getComment().toLowerCase().contains(query)) {
filteredGeofavorites.add(geofavorite);
}
}
}
return filteredGeofavorites;
}
public List<Geofavorite> byCategory(String category) {
List<Geofavorite> filteredGeofavorites = new ArrayList<>();
if (category == null) {
return items;
} else {
for (Geofavorite geofavorite : items) {
if (geofavorite.getCategory().equals(category)) {
filteredGeofavorites.add(geofavorite);
}
}
}
return filteredGeofavorites;
}
}

View File

@ -14,6 +14,7 @@ public class IntentGenerator {
i.setAction(Intent.ACTION_SEND); i.setAction(Intent.ACTION_SEND);
i.setType("text/plain"); i.setType("text/plain");
String shareMessage = context.getString(R.string.share_message) String shareMessage = context.getString(R.string.share_message)
.replace("{title}", item.getName() == null ? context.getString(R.string.share_message_default_title) : item.getName())
.replace("{lat}", ""+item.getLat()) .replace("{lat}", ""+item.getLat())
.replace("{lng}", ""+item.getLng()); .replace("{lng}", ""+item.getLng());
i.putExtra(Intent.EXTRA_TEXT, shareMessage ); i.putExtra(Intent.EXTRA_TEXT, shareMessage );

View File

@ -0,0 +1,57 @@
package it.danieleverducci.nextcloudmaps.utils;
import android.content.Context;
import android.content.SharedPreferences;
import androidx.preference.PreferenceManager;
import it.danieleverducci.nextcloudmaps.activity.main.GeofavoriteAdapter;
public class SettingsManager {
static private final String SETTING_SORT_BY = "SETTING_SORT_BY";
static private final String SETTING_LAST_SELECTED_LIST_VIEW = "SETTING_LAST_SELECTED_LIST_VIEW";
static private final String SETTING_LAST_MAP_POSITION_LAT = "SETTING_LAST_MAP_POSITION_LAT";
static private final String SETTING_LAST_MAP_POSITION_LNG = "SETTING_LAST_MAP_POSITION_LNG";
static private final String SETTING_LAST_MAP_POSITION_ZOOM = "SETTING_LAST_MAP_POSITION_ZOOM";
public static int getGeofavoriteListSortBy(Context context) {
return PreferenceManager.getDefaultSharedPreferences(context)
.getInt(SETTING_SORT_BY, GeofavoriteAdapter.SORT_BY_CREATED);
}
public static void setGeofavoriteListSortBy(Context context, int value) {
PreferenceManager.getDefaultSharedPreferences(context)
.edit().putInt(SETTING_SORT_BY, value).apply();
}
public static boolean isGeofavoriteListShownAsMap(Context context) {
return PreferenceManager.getDefaultSharedPreferences(context)
.getBoolean(SETTING_LAST_SELECTED_LIST_VIEW, false);
}
public static void setGeofavoriteListShownAsMap(Context context, boolean value) {
PreferenceManager.getDefaultSharedPreferences(context)
.edit().putBoolean(SETTING_LAST_SELECTED_LIST_VIEW, value).apply();
}
/**
* Returns the last saved position
* @param context
* @return double[lat,lng,zoom]
*/
public static double[] getLastMapPosition(Context context) {
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
return new double[] {
(double) sp.getFloat(SETTING_LAST_MAP_POSITION_LAT, 0.0f),
(double) sp.getFloat(SETTING_LAST_MAP_POSITION_LNG, 0.0f),
(double) sp.getFloat(SETTING_LAST_MAP_POSITION_ZOOM, 10.0f),
};
}
public static void setLastMapPosition(Context context, double lat, double lng, double zoom) {
PreferenceManager.getDefaultSharedPreferences(context).edit()
.putFloat(SETTING_LAST_MAP_POSITION_LAT, (float)lat)
.putFloat(SETTING_LAST_MAP_POSITION_LNG, (float)lng)
.putFloat(SETTING_LAST_MAP_POSITION_ZOOM, (float)zoom)
.apply();
}
}

View File

@ -0,0 +1,72 @@
package it.danieleverducci.nextcloudmaps.views;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.view.View;
import androidx.appcompat.content.res.AppCompatResources;
import androidx.core.graphics.drawable.DrawableCompat;
import org.osmdroid.views.MapView;
import org.osmdroid.views.overlay.infowindow.InfoWindow;
import org.osmdroid.views.overlay.infowindow.MarkerInfoWindow;
import it.danieleverducci.nextcloudmaps.R;
import it.danieleverducci.nextcloudmaps.model.Geofavorite;
public class GeofavMarkerInfoWindow extends MarkerInfoWindow implements View.OnClickListener {
private OnGeofavMarkerInfoWindowClickListener onGeofavMarkerInfoWindowClickListener;
public GeofavMarkerInfoWindow(MapView mapView, Geofavorite geofavorite) {
super(R.layout.infowindow_geofav, mapView);
Context context = getView().getContext();
// Set category color
View category = getView().findViewById(R.id.bubble_subdescription);
Drawable backgroundDrawable = category.getBackground();
DrawableCompat.setTint(backgroundDrawable, geofavorite.categoryColor() == 0 ? context.getColor(R.color.defaultBrand) : geofavorite.categoryColor());
// Set listeners
getView().findViewById(R.id.action_icon_share).setOnClickListener(this);
getView().findViewById(R.id.action_icon_nav).setOnClickListener(this);
getView().findViewById(R.id.action_icon_delete).setOnClickListener(this);
getView().findViewById(R.id.action_icon_edit).setOnClickListener(this);
}
public void setOnGeofavMarkerInfoWindowClickListener(OnGeofavMarkerInfoWindowClickListener l) {
this.onGeofavMarkerInfoWindowClickListener = l;
}
@Override
public void onOpen(Object item) {
InfoWindow.closeAllInfoWindowsOn(getMapView());
super.onOpen(item);
}
@Override
public void onClick(View v) {
if (onGeofavMarkerInfoWindowClickListener == null)
return;
if (v.getId() == R.id.action_icon_share)
onGeofavMarkerInfoWindowClickListener.onGeofavMarkerInfoWindowShareClick();
if (v.getId() == R.id.action_icon_nav)
onGeofavMarkerInfoWindowClickListener.onGeofavMarkerInfoWindowNavClick();
if (v.getId() == R.id.action_icon_delete)
onGeofavMarkerInfoWindowClickListener.onGeofavMarkerInfoWindowDeleteClick();
if (v.getId() == R.id.action_icon_edit)
onGeofavMarkerInfoWindowClickListener.onGeofavMarkerInfoWindowEditClick();
}
public interface OnGeofavMarkerInfoWindowClickListener {
public void onGeofavMarkerInfoWindowEditClick();
public void onGeofavMarkerInfoWindowShareClick();
public void onGeofavMarkerInfoWindowNavClick();
public void onGeofavMarkerInfoWindowDeleteClick();
}
}

View File

@ -0,0 +1,13 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="209.21dp"
android:height="45.14dp"
android:viewportWidth="209.21"
android:viewportHeight="45.14">
<path
android:pathData="m204.31,0.14c-0.97,0.02 -2.1,0.07 -3.3,0.15l8.18,-0.01c0,0 -1.81,-0.2 -4.89,-0.14zM201.01,0.29 L0.02,0.46c0,0 32.67,5.29 57.83,17.7 25.15,12.42 45.33,26.81 45.33,26.81 0,0 18.75,-13.75 38.46,-26.28 20.46,-13 49.14,-17.73 59.37,-18.41z"
android:strokeLineJoin="miter"
android:strokeWidth="0.264583"
android:fillColor="#000000"
android:strokeColor="#00000000"
android:strokeLineCap="butt"/>
</vector>

View File

@ -3,7 +3,7 @@
android:height="24dp" android:height="24dp"
android:viewportWidth="24" android:viewportWidth="24"
android:viewportHeight="24" android:viewportHeight="24"
android:tint="?attr/colorControlNormal"> android:tint="?android:attr/colorControlNormal">
<path <path
android:fillColor="@android:color/white" android:fillColor="@android:color/white"
android:pathData="M20.94,11c-0.46,-4.17 -3.77,-7.48 -7.94,-7.94L13,1h-2v2.06c-1.13,0.12 -2.19,0.46 -3.16,0.97l1.5,1.5C10.16,5.19 11.06,5 12,5c3.87,0 7,3.13 7,7 0,0.94 -0.19,1.84 -0.52,2.65l1.5,1.5c0.5,-0.96 0.84,-2.02 0.97,-3.15L23,13v-2h-2.06zM3,4.27l2.04,2.04C3.97,7.62 3.25,9.23 3.06,11L1,11v2h2.06c0.46,4.17 3.77,7.48 7.94,7.94L11,23h2v-2.06c1.77,-0.2 3.38,-0.91 4.69,-1.98L19.73,21 21,19.73 4.27,3 3,4.27zM16.27,17.54C15.09,18.45 13.61,19 12,19c-3.87,0 -7,-3.13 -7,-7 0,-1.61 0.55,-3.09 1.46,-4.27l9.81,9.81z"/> android:pathData="M20.94,11c-0.46,-4.17 -3.77,-7.48 -7.94,-7.94L13,1h-2v2.06c-1.13,0.12 -2.19,0.46 -3.16,0.97l1.5,1.5C10.16,5.19 11.06,5 12,5c3.87,0 7,3.13 7,7 0,0.94 -0.19,1.84 -0.52,2.65l1.5,1.5c0.5,-0.96 0.84,-2.02 0.97,-3.15L23,13v-2h-2.06zM3,4.27l2.04,2.04C3.97,7.62 3.25,9.23 3.06,11L1,11v2h2.06c0.46,4.17 3.77,7.48 7.94,7.94L11,23h2v-2.06c1.77,-0.2 3.38,-0.91 4.69,-1.98L19.73,21 21,19.73 4.27,3 3,4.27zM16.27,17.54C15.09,18.45 13.61,19 12,19c-3.87,0 -7,-3.13 -7,-7 0,-1.61 0.55,-3.09 1.46,-4.27l9.81,9.81z"/>

View File

@ -3,7 +3,7 @@
android:height="24dp" android:height="24dp"
android:viewportWidth="24" android:viewportWidth="24"
android:viewportHeight="24" android:viewportHeight="24"
android:tint="?attr/colorControlNormal"> android:tint="?android:attr/colorControlNormal">
<path <path
android:fillColor="@android:color/white" android:fillColor="@android:color/white"
android:pathData="M12,8c-2.21,0 -4,1.79 -4,4s1.79,4 4,4 4,-1.79 4,-4 -1.79,-4 -4,-4zM20.94,11c-0.46,-4.17 -3.77,-7.48 -7.94,-7.94L13,1h-2v2.06C6.83,3.52 3.52,6.83 3.06,11L1,11v2h2.06c0.46,4.17 3.77,7.48 7.94,7.94L11,23h2v-2.06c4.17,-0.46 7.48,-3.77 7.94,-7.94L23,13v-2h-2.06zM12,19c-3.87,0 -7,-3.13 -7,-7s3.13,-7 7,-7 7,3.13 7,7 -3.13,7 -7,7z"/> android:pathData="M12,8c-2.21,0 -4,1.79 -4,4s1.79,4 4,4 4,-1.79 4,-4 -1.79,-4 -4,-4zM20.94,11c-0.46,-4.17 -3.77,-7.48 -7.94,-7.94L13,1h-2v2.06C6.83,3.52 3.52,6.83 3.06,11L1,11v2h2.06c0.46,4.17 3.77,7.48 7.94,7.94L11,23h2v-2.06c4.17,-0.46 7.48,-3.77 7.94,-7.94L23,13v-2h-2.06zM12,19c-3.87,0 -7,-3.13 -7,-7s3.13,-7 7,-7 7,3.13 7,7 -3.13,7 -7,7z"/>

View File

@ -3,7 +3,7 @@
android:height="24dp" android:height="24dp"
android:viewportWidth="24" android:viewportWidth="24"
android:viewportHeight="24" android:viewportHeight="24"
android:tint="?attr/colorControlNormal"> android:tint="?android:attr/colorControlNormal">
<path <path
android:fillColor="@android:color/white" android:fillColor="@android:color/white"
android:pathData="M12,2l-5.5,9h11z"/> android:pathData="M12,2l-5.5,9h11z"/>

View File

@ -3,7 +3,7 @@
android:height="24dp" android:height="24dp"
android:viewportWidth="24" android:viewportWidth="24"
android:viewportHeight="24" android:viewportHeight="24"
android:tint="?attr/colorControlNormal"> android:tint="?android:attr/colorControlNormal">
<path <path
android:fillColor="@android:color/white" android:fillColor="@android:color/white"
android:pathData="M21,3L3,10.53v0.98l6.84,2.65L12.48,21h0.98L21,3z"/> android:pathData="M21,3L3,10.53v0.98l6.84,2.65L12.48,21h0.98L21,3z"/>

View File

@ -0,0 +1,5 @@
<vector android:height="24dp" android:tint="#FFFFFF"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M4.25,5.61C6.27,8.2 10,13 10,13v6c0,0.55 0.45,1 1,1h2c0.55,0 1,-0.45 1,-1v-6c0,0 3.72,-4.8 5.74,-7.39C20.25,4.95 19.78,4 18.95,4H5.04C4.21,4 3.74,4.95 4.25,5.61z"/>
</vector>

View File

@ -0,0 +1,6 @@
<vector android:height="24dp" android:tint="#FFFFFF"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M19.79,5.61C20.3,4.95 19.83,4 19,4H6.83l7.97,7.97L19.79,5.61z"/>
<path android:fillColor="@android:color/white" android:pathData="M2.81,2.81L1.39,4.22L10,13v6c0,0.55 0.45,1 1,1h2c0.55,0 1,-0.45 1,-1v-2.17l5.78,5.78l1.41,-1.41L2.81,2.81z"/>
</vector>

View File

@ -3,7 +3,7 @@
android:height="24dp" android:height="24dp"
android:viewportWidth="24" android:viewportWidth="24"
android:viewportHeight="24" android:viewportHeight="24"
android:tint="?attr/colorControlNormal"> android:tint="?android:attr/colorControlNormal">
<path <path
android:fillColor="@android:color/white" android:fillColor="@android:color/white"
android:pathData="M13.95,13H9V8.05l5.61,-5.61C13.78,2.16 12.9,2 12,2c-4.2,0 -8,3.22 -8,8.2c0,3.32 2.67,7.25 8,11.8c5.33,-4.55 8,-8.48 8,-11.8c0,-1.01 -0.16,-1.94 -0.45,-2.8L13.95,13z"/> android:pathData="M13.95,13H9V8.05l5.61,-5.61C13.78,2.16 12.9,2 12,2c-4.2,0 -8,3.22 -8,8.2c0,3.32 2.67,7.25 8,11.8c5.33,-4.55 8,-8.48 8,-11.8c0,-1.01 -0.16,-1.94 -0.45,-2.8L13.95,13z"/>

View File

@ -3,7 +3,7 @@
android:height="24dp" android:height="24dp"
android:viewportWidth="24" android:viewportWidth="24"
android:viewportHeight="24" android:viewportHeight="24"
android:tint="?attr/colorControlNormal"> android:tint="?android:attr/colorControlNormal">
<path <path
android:fillColor="@android:color/white" android:fillColor="@android:color/white"
android:pathData="M9,16.17L4.83,12l-1.42,1.41L9,19 21,7l-1.41,-1.41z"/> android:pathData="M9,16.17L4.83,12l-1.42,1.41L9,19 21,7l-1.41,-1.41z"/>

View File

@ -0,0 +1,5 @@
<vector android:height="24dp" android:tint="#FFFFFF"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M20.5,3l-0.16,0.03L15,5.1 9,3 3.36,4.9c-0.21,0.07 -0.36,0.25 -0.36,0.48V20.5c0,0.28 0.22,0.5 0.5,0.5l0.16,-0.03L9,18.9l6,2.1 5.64,-1.9c0.21,-0.07 0.36,-0.25 0.36,-0.48V3.5c0,-0.28 -0.22,-0.5 -0.5,-0.5zM15,19l-6,-2.11V5l6,2.11V19z"/>
</vector>

View File

@ -1,25 +0,0 @@
<!--
~ Nextcloud Maps Geofavorites for Android
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
~ the Free Software Foundation, either version 3 of the License, or
~ (at your option) any later version.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public License
~ along with this program. If not, see <http://www.gnu.org/licenses/>.
-->
<vector
xmlns:android="http://schemas.android.com/apk/res/android"
android:height="24dp"
android:width="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path android:fillColor="#FFFFFF"
android:pathData="M16,5V11H21V5M10,11H15V5H10M16,18H21V12H16M10,18H15V12H10M4,18H9V12H4M4,11H9V5H4V11Z" />
</vector>

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="@color/defaultBackground"/>
<stroke android:width="7dp" android:color="@color/defaultBrand" />
<corners android:radius="20dp"/>
</shape>

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#000" />
<padding android:left="10dp" android:top="3dp" android:right="10dp" android:bottom="3dp" />
<corners android:radius="20dp" />
</shape>

View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape
android:shape="oval">
<solid android:color="@color/translucent"/>
</shape>
</item>
</layer-list>

View File

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape
android:innerRadius="0dp"
android:shape="oval"
android:useLevel="false">
<solid android:color="@android:color/transparent" />
<stroke
android:width="10dp"
android:color="#fff" />
</shape>
</item>
</layer-list>

View File

@ -32,7 +32,7 @@
<androidx.appcompat.widget.Toolbar <androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar" android:id="@+id/toolbar"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize" android:layout_height="?android:attr/actionBarSize"
app:contentInsetStartWithNavigation="0dp" app:contentInsetStartWithNavigation="0dp"
app:navigationIcon="@drawable/ic_back_grey" app:navigationIcon="@drawable/ic_back_grey"
app:titleMarginStart="0dp"/> app:titleMarginStart="0dp"/>

View File

@ -43,7 +43,7 @@
<androidx.appcompat.widget.Toolbar <androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar" android:id="@+id/toolbar"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize" android:layout_height="?android:attr/actionBarSize"
app:contentInsetStart="0dp" app:contentInsetStart="0dp"
app:layout_collapseMode="pin" app:layout_collapseMode="pin"
android:background="@android:color/transparent"> android:background="@android:color/transparent">
@ -51,8 +51,8 @@
<!-- Back button --> <!-- Back button -->
<ImageView <ImageView
android:id="@+id/back_bt" android:id="@+id/back_bt"
android:layout_width="?attr/actionBarSize" android:layout_width="?android:attr/actionBarSize"
android:layout_height="?attr/actionBarSize" android:layout_height="?android:attr/actionBarSize"
android:layout_gravity="start" android:layout_gravity="start"
android:padding="16dp" android:padding="16dp"
android:src="@drawable/ic_back_grey" android:src="@drawable/ic_back_grey"
@ -62,8 +62,8 @@
<!-- Manual position button --> <!-- Manual position button -->
<ImageView <ImageView
android:id="@+id/manual_pos_bt" android:id="@+id/manual_pos_bt"
android:layout_width="?attr/actionBarSize" android:layout_width="?android:attr/actionBarSize"
android:layout_height="?attr/actionBarSize" android:layout_height="?android:attr/actionBarSize"
android:layout_gravity="end" android:layout_gravity="end"
android:padding="16dp" android:padding="16dp"
android:src="@drawable/ic_manual_pos" android:src="@drawable/ic_manual_pos"

View File

@ -15,160 +15,34 @@
~ You should have received a copy of the GNU General Public License ~ You should have received a copy of the GNU General Public License
~ along with this program. If not, see <http://www.gnu.org/licenses/>. ~ along with this program. If not, see <http://www.gnu.org/licenses/>.
--> -->
<FrameLayout
<androidx.coordinatorlayout.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_list_view"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="match_parent">
<com.google.android.material.appbar.AppBarLayout <androidx.fragment.app.FragmentContainerView
android:id="@+id/appBar" android:id="@+id/fragment_container"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:elevation="0dp">
<com.google.android.material.appbar.CollapsingToolbarLayout
android:id="@+id/toolbar_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fitsSystemWindows="true"
app:contentScrim="?attr/colorPrimary"
app:layout_scrollFlags="scroll|enterAlways"
app:toolbarId="@+id/toolbar" >
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="visible"
app:contentInsetStartWithNavigation="0dp"
app:titleMarginStart="0dp"
tools:title="@string/app_name">
<androidx.appcompat.widget.SearchView
android:id="@+id/search_view"
android:layout_width="match_parent"
android:layout_height="wrap_content">
</androidx.appcompat.widget.SearchView>
</androidx.appcompat.widget.Toolbar>
<com.google.android.material.card.MaterialCardView
android:id="@+id/home_toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/spacer_2x"
android:layout_marginTop="@dimen/spacer_1hx"
android:layout_marginEnd="@dimen/spacer_2x"
android:layout_marginBottom="@dimen/spacer_1hx"
app:cardCornerRadius="@dimen/spacer_1x"
app:cardElevation="2dp"
app:strokeWidth="0dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<androidx.appcompat.widget.AppCompatImageButton
android:id="@+id/menu_button"
android:layout_width="?attr/actionBarSize"
android:layout_height="?attr/actionBarSize"
android:background="?attr/selectableItemBackgroundBorderless"
android:layout_gravity="center_vertical|start"
android:paddingStart="@dimen/spacer_1x"
android:paddingTop="@dimen/spacer_2x"
android:paddingEnd="@dimen/spacer_1x"
android:paddingBottom="@dimen/spacer_2x"
android:tint="@color/text_color"
android:src="@drawable/ic_menu_grey"/>
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/search_text"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginStart="@dimen/spacer_1x"
android:layout_marginEnd="@dimen/spacer_1x"
android:layout_weight="1"
android:ellipsize="end"
android:gravity="start"
android:lines="1"
android:textSize="16sp"
android:text="@string/search_in_all"/>
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/sort_mode"
android:layout_width="?attr/actionBarSize"
android:layout_height="?attr/actionBarSize"
android:layout_gravity="center_vertical|end"
android:background="?attr/selectableItemBackgroundBorderless"
android:contentDescription="@string/list_mode"
android:paddingStart="@dimen/spacer_1x"
android:paddingTop="@dimen/spacer_2x"
android:paddingEnd="@dimen/spacer_1x"
android:paddingBottom="@dimen/spacer_2x"
android:tint="@color/text_color"
android:translationX="@dimen/spacer_1x"
android:src="@drawable/ic_alphabetical_asc" />
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/view_mode"
android:layout_width="?attr/actionBarSize"
android:layout_height="?attr/actionBarSize"
android:layout_gravity="center_vertical|end"
android:background="?attr/selectableItemBackgroundBorderless"
android:contentDescription="@string/list_mode"
android:paddingStart="@dimen/spacer_1x"
android:paddingTop="@dimen/spacer_2x"
android:paddingEnd="@dimen/spacer_1x"
android:paddingBottom="@dimen/spacer_2x" android:tint="@color/text_color"
android:translationX="@dimen/spacer_1x"
android:src="@drawable/ic_view_module"
android:visibility="gone"/> <!-- TODO: Replace with Map View icon -->
</LinearLayout>
</com.google.android.material.card.MaterialCardView>
</com.google.android.material.appbar.CollapsingToolbarLayout>
</com.google.android.material.appbar.AppBarLayout>
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
android:id="@+id/swipe_refresh"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:layout_margin="@dimen/spacer_1hx" android:name="it.danieleverducci.nextcloudmaps.fragments.GeofavoriteListFragment"
app:layout_behavior="@string/appbar_scrolling_view_behavior"> tools:layout="@layout/fragment_geofavorite_list" />
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layoutManager="androidx.recyclerview.widget.StaggeredGridLayoutManager"
app:spanCount="1"
tools:itemCount="3"
tools:listitem="@layout/item_geofav">
</androidx.recyclerview.widget.RecyclerView>
</androidx.core.widget.NestedScrollView>
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
<!-- Add from map FAB --> <!-- Add from map FAB -->
<com.google.android.material.floatingactionbutton.FloatingActionButton <com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/add_from_map" android:id="@+id/add_from_map"
android:layout_margin="24dp"
android:layout_gravity="bottom|end"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
app:fabSize="mini" android:layout_gravity="bottom|end"
android:layout_margin="24dp"
android:src="@drawable/ic_add_map" android:src="@drawable/ic_add_map"
app:backgroundTint="@color/defaultBrand"/> app:backgroundTint="@color/defaultBrand"
app:fabSize="mini"
app:tint="@color/white"
tools:ignore="DuplicateClickableBoundsCheck"
android:contentDescription="@string/add_from_map" />
<!-- Add from current position FAB --> <!-- Add from current position FAB -->
<com.google.android.material.floatingactionbutton.FloatingActionButton <com.google.android.material.floatingactionbutton.FloatingActionButton
@ -179,7 +53,9 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
app:fabSize="mini" app:fabSize="mini"
android:src="@drawable/ic_add_gps" android:src="@drawable/ic_add_gps"
app:backgroundTint="@color/defaultBrand"/> app:backgroundTint="@color/defaultBrand"
app:tint="@color/white"
android:contentDescription="@string/add_from_gps"/>
<!-- Main FAB --> <!-- Main FAB -->
<com.google.android.material.floatingactionbutton.FloatingActionButton <com.google.android.material.floatingactionbutton.FloatingActionButton
@ -189,6 +65,8 @@
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:src="@drawable/ic_add" android:src="@drawable/ic_add"
app:backgroundTint="@color/defaultBrand"/> app:backgroundTint="@color/defaultBrand"
app:tint="@color/white"
android:contentDescription="@string/open_fab"/>
</androidx.coordinatorlayout.widget.CoordinatorLayout> </FrameLayout>

View File

@ -42,7 +42,7 @@
android:id="@+id/scrollView" android:id="@+id/scrollView"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:background="?attr/colorPrimary"> android:background="?android:attr/colorPrimary">
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
@ -68,9 +68,11 @@
android:id="@+id/app_name" android:id="@+id/app_name"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginRight="20dp"
android:layout_centerVertical="true" android:layout_centerVertical="true"
android:layout_toEndOf="@id/logo" android:layout_toEndOf="@id/logo"
android:ellipsize="end" android:ellipsize="end"
android:lines="2"
android:fontFamily="sans-serif-light" android:fontFamily="sans-serif-light"
android:gravity="center_vertical" android:gravity="center_vertical"
android:text="@string/app_name" android:text="@string/app_name"

View File

@ -16,27 +16,30 @@
android:layout_height="48dp" android:layout_height="48dp"
android:layout_marginBottom="24dp" android:layout_marginBottom="24dp"
android:layout_gravity="center" android:layout_gravity="center"
android:src="@drawable/ic_map_pin"/> android:src="@drawable/ic_map_pin"
app:tint="@color/defaultBrand"/>
<ImageView <ImageView
android:id="@+id/back_bt" android:id="@+id/back_bt"
android:layout_width="?attr/actionBarSize" android:layout_width="?android:attr/actionBarSize"
android:layout_height="?attr/actionBarSize" android:layout_height="?android:attr/actionBarSize"
android:layout_margin="16dp"
android:layout_gravity="start" android:layout_gravity="start"
android:padding="16dp" android:padding="16dp"
android:src="@drawable/ic_back_grey" android:src="@drawable/ic_back_grey"
app:tint="@color/white" app:tint="@color/text_color"
android:background="@drawable/floating_semitransparent_button_background"/> android:background="@drawable/unselected_floating_semitransparent_button_background"/>
<ImageView <ImageView
android:id="@+id/ok_bt" android:id="@+id/ok_bt"
android:layout_width="?attr/actionBarSize" android:layout_width="?android:attr/actionBarSize"
android:layout_height="?attr/actionBarSize" android:layout_height="?android:attr/actionBarSize"
android:layout_margin="16dp"
android:layout_gravity="end" android:layout_gravity="end"
android:padding="16dp" android:padding="16dp"
android:src="@drawable/ic_ok" android:src="@drawable/ic_ok"
app:tint="@color/white" app:tint="@color/white"
android:background="@drawable/floating_semitransparent_button_background"/> android:background="@drawable/round_button_background"/>
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"

View File

@ -0,0 +1,101 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp">
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="visible"
app:contentInsetStartWithNavigation="0dp"
app:titleMarginStart="0dp"
tools:title="@string/app_name">
<androidx.appcompat.widget.SearchView
android:id="@+id/search_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="30dp"
android:layout_marginEnd="30dp"
android:background="@color/translucent">
</androidx.appcompat.widget.SearchView>
</androidx.appcompat.widget.Toolbar>
<com.google.android.material.card.MaterialCardView
android:id="@+id/home_toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/spacer_2x"
android:layout_marginTop="@dimen/spacer_1hx"
android:layout_marginEnd="@dimen/spacer_2x"
android:layout_marginBottom="@dimen/spacer_1hx"
app:cardCornerRadius="30dp"
app:cardElevation="2dp"
app:strokeWidth="0dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<androidx.appcompat.widget.AppCompatImageButton
android:id="@+id/menu_button"
android:layout_width="?android:attr/actionBarSize"
android:layout_height="?android:attr/actionBarSize"
android:background="?android:attr/selectableItemBackgroundBorderless"
android:layout_gravity="center_vertical|start"
android:paddingStart="@dimen/spacer_1x"
android:paddingTop="@dimen/spacer_2x"
android:paddingEnd="@dimen/spacer_1x"
android:paddingBottom="@dimen/spacer_2x"
android:tint="@color/text_color"
android:src="@drawable/ic_menu_grey"
android:contentDescription="@string/menu"/>
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/search_text"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginStart="@dimen/spacer_1x"
android:layout_marginEnd="@dimen/spacer_1x"
android:layout_weight="1"
android:ellipsize="end"
android:gravity="start"
android:lines="1"
android:textSize="16sp"
android:text="@string/search_in_all"/>
<!-- Filter button -->
<ImageButton
android:id="@+id/search_filter"
android:layout_width="?android:attr/actionBarSize"
android:layout_height="?android:attr/actionBarSize"
android:src="@drawable/ic_filter_off"
app:tint="@color/inactive"
android:background="@color/transparent"/>
<!-- User badge -->
<FrameLayout
android:id="@+id/user_badge_container"
android:layout_width="?android:attr/actionBarSize"
android:layout_height="?android:attr/actionBarSize">
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/user_badge"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="10dp"/>
<View
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/user_badge_mask"/>
</FrameLayout>
</LinearLayout>
</com.google.android.material.card.MaterialCardView>
</FrameLayout>

View File

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingLeft="20dp"
android:paddingRight="20dp"
android:paddingTop="10dp"
android:paddingBottom="10dp">
<TextView
android:id="@+id/category_name"
android:layout_width="match_parent"
android:layout_height="30dp"
android:gravity="center_vertical"
android:lines="1"
android:ellipsize="end"
android:text="Lorem ipsum"
app:drawableLeftCompat="@drawable/ic_category_asc"
android:drawablePadding="8sp"
android:drawableTint="@color/white"
android:textColor="@color/white"
android:textStyle="bold"
android:background="@drawable/rounded_label_background"/>
</FrameLayout>

View File

@ -0,0 +1,90 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_list_view"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/appBar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:elevation="0dp">
<com.google.android.material.appbar.CollapsingToolbarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fitsSystemWindows="true"
app:contentScrim="?android:attr/colorPrimary"
app:layout_scrollFlags="scroll|enterAlways"
app:toolbarId="@+id/toolbar" >
<include layout="@layout/app_toolbar"/>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_marginTop="?android:attr/actionBarSize"
android:paddingTop="20dp"
android:paddingStart="5dp"
android:paddingEnd="5dp">
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/sort_mode"
android:layout_width="wrap_content"
android:layout_height="@dimen/floating_bar_height"
android:layout_alignParentLeft="true"
android:background="?android:attr/selectableItemBackgroundBorderless"
android:contentDescription="@string/list_mode"
android:paddingStart="@dimen/spacer_2x"
android:paddingEnd="@dimen/spacer_2x"
android:tint="@color/text_color"
android:src="@drawable/ic_alphabetical_asc" />
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/view_mode_map"
android:layout_width="wrap_content"
android:layout_height="@dimen/floating_bar_height"
android:layout_alignParentRight="true"
android:background="?android:attr/selectableItemBackgroundBorderless"
android:contentDescription="@string/list_mode"
android:paddingStart="@dimen/spacer_2x"
android:paddingEnd="@dimen/spacer_2x"
android:tint="@color/text_color"
android:src="@drawable/ic_view_map" />
</RelativeLayout>
</com.google.android.material.appbar.CollapsingToolbarLayout>
</com.google.android.material.appbar.AppBarLayout>
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
android:id="@+id/swipe_refresh"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layoutManager="androidx.recyclerview.widget.StaggeredGridLayoutManager"
app:spanCount="1"
tools:itemCount="3"
tools:listitem="@layout/item_geofav">
</androidx.recyclerview.widget.RecyclerView>
</androidx.core.widget.NestedScrollView>
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>

View File

@ -0,0 +1,70 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_list_view"
android:layout_width="match_parent"
android:layout_height="match_parent">
<org.osmdroid.views.MapView
android:id="@+id/map"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<FrameLayout
android:id="@+id/loading_wall"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/translucent"
android:visibility="gone">
<ProgressBar
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:indeterminate="true"
android:layout_gravity="center"/>
</FrameLayout>
<androidx.appcompat.widget.LinearLayoutCompat
android:id="@+id/appBar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:elevation="0dp"
android:orientation="vertical">
<include layout="@layout/app_toolbar"/>
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/view_mode_list"
android:layout_width="@dimen/floating_bar_height"
android:layout_height="@dimen/floating_bar_height"
android:layout_marginTop="2dp"
android:layout_marginEnd="@dimen/spacer_2x"
android:layout_gravity="right"
android:background="@drawable/unselected_floating_semitransparent_button_background"
android:contentDescription="@string/list_mode"
android:paddingStart="5dp"
android:paddingEnd="5dp"
android:tint="@color/text_color"
android:src="@drawable/ic_view_list" />
</androidx.appcompat.widget.LinearLayoutCompat>
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/center_position"
android:layout_width="@dimen/floating_bar_height"
android:layout_height="@dimen/floating_bar_height"
android:layout_marginRight="100dp"
android:layout_marginBottom="25dp"
android:layout_gravity="bottom|right"
android:background="@drawable/unselected_floating_semitransparent_button_background"
android:contentDescription="@string/list_mode"
android:padding="5dp"
android:tint="@color/text_color"
android:src="@drawable/ic_add_gps"
android:visibility="gone"/>
</FrameLayout>

View File

@ -0,0 +1,119 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
xmlns:app="http://schemas.android.com/apk/res-auto">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:minWidth="250dp"
android:background="@drawable/infowindow_geofav_background"
android:padding="7dp"
android:orientation="vertical">
<!-- Geofavorite title -->
<TextView
android:id="@+id/bubble_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/defaultBrand"
android:padding="10dp"
android:lines="1"
android:ellipsize="end"
style="@style/TextAppearance.GeofavoriteInfowindow"
android:text="Lorem"/>
<!-- Geofavorite description -->
<TextView
android:id="@+id/bubble_description"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:layout_marginBottom="10dp"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:text="Lorem ipsum"/>
<!-- Geofavorite category -->
<TextView
android:id="@+id/bubble_subdescription"
android:layout_width="wrap_content"
android:layout_height="30dp"
android:layout_marginStart="10dp"
android:layout_marginEnd="10dp"
android:layout_marginBottom="10dp"
android:gravity="center_vertical"
android:lines="1"
android:ellipsize="end"
android:text="Lorem ipsum"
app:drawableLeftCompat="@drawable/ic_category_asc"
android:drawablePadding="8sp"
android:drawableTint="@color/white"
android:textColor="@color/white"
android:textStyle="bold"
android:background="@drawable/rounded_label_background"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<ImageView
android:id="@+id/action_icon_share"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:padding="10dp"
android:src="@drawable/ic_share"
app:tint="@color/defaultBrand"/>
<ImageView
android:id="@+id/action_icon_nav"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:padding="10dp"
android:src="@drawable/ic_nav"
app:tint="@color/defaultBrand"/>
<ImageView
android:id="@+id/action_icon_delete"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:padding="10dp"
android:src="@drawable/ic_delete_grey"
app:tint="@color/defaultBrand"/>
<ImageView
android:id="@+id/action_icon_edit"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:padding="10dp"
android:src="@drawable/ic_edit"
app:tint="@color/defaultBrand"/>
</LinearLayout>
<ImageView
android:id="@+id/bubble_image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone"/>
</LinearLayout>
<ImageView
android:layout_width="50dp"
android:layout_height="10dp"
android:layout_marginTop="-1dp"
android:layout_gravity="center_horizontal"
android:src="@drawable/geofav_infowindow_pointer"
app:tint="@color/defaultBrand" />
</LinearLayout>

View File

@ -31,15 +31,21 @@
<string name="list_mode">Lista</string> <string name="list_mode">Lista</string>
<string name="search_in_all">Cerca per nome</string> <string name="search_in_all">Cerca per nome</string>
<string name="share_via">Condividi via</string> <string name="share_via">Condividi via</string>
<string name="share_message">Posizione condivisa: {lat}°N, {lng}°E https://www.openstreetmap.org/#map=17/{lat}/{lng}</string> <string name="share_message">{title}: {lat}°N, {lng}°E https://www.openstreetmap.org/#map=17/{lat}/{lng}</string>
<string name="share_message_default_title">Posizione condivisa:</string>
<string name="list_context_menu_share">Condividi</string> <string name="list_context_menu_share">Condividi</string>
<string name="list_context_menu_delete">Elimina</string> <string name="list_context_menu_delete">Elimina</string>
<string name="dialog_delete_title">Elimina geosegnalibro</string> <string name="dialog_delete_title">Elimina geosegnalibro</string>
<string name="dialog_delete_message">Stai per eliminare il geosegnalibro {name}. Procedere?</string> <string name="dialog_delete_message">Stai per eliminare il geosegnalibro {name}. Procedere?</string>
<string name="dialog_delete_delete">Elimina</string> <string name="dialog_delete_delete">Elimina</string>
<string name="dialog_delete_cancel">Mantieni</string> <string name="dialog_delete_cancel">Mantieni</string>
<string name="dialog_logout_title">Cambia account</string>
<string name="dialog_logout_message">Vuoi cambiare account?</string>
<string name="list_geofavorite_deleted">Geosegnalibro eliminato</string> <string name="list_geofavorite_deleted">Geosegnalibro eliminato</string>
<string name="list_geofavorite_connection_error">Impossibile ottenere la lista dei geosegnalibri</string> <string name="list_geofavorite_connection_error">Impossibile ottenere la lista dei geosegnalibri</string>
<string name="filtering_unavailable">Il filtro per categoria non è disponibile al momento</string>
<string name="filtering_dialog_title">Filtra per categoria</string>
<string name="filtering_dialog_cancel">Mostra tutti</string>
<!-- Sort dialog --> <!-- Sort dialog -->
<string name="sort_by">Ordina per</string> <string name="sort_by">Ordina per</string>
@ -93,12 +99,13 @@
<string name="url_license" translatable="false">https://raw.githubusercontent.com/penguin86/nextcloud-maps-client/master/LICENSE</string> <string name="url_license" translatable="false">https://raw.githubusercontent.com/penguin86/nextcloud-maps-client/master/LICENSE</string>
<string name="url_maps" translatable="false">https://donate.openstreetmap.org</string> <string name="url_maps" translatable="false">https://donate.openstreetmap.org</string>
<!-- Settings -->
<string name="setting_sort_by">SETTING_SORT_BY</string>
<string name="setting_grid_view_enabled">SETTING_GRID_VIEW_ENABLED</string>
<!-- Menu --> <!-- Menu -->
<string name="new_geobookmark_gps">Crea dalla posizione corrente</string> <string name="new_geobookmark_gps">Crea dalla posizione corrente</string>
<string name="new_geobookmark_map">Crea dalla mappa</string> <string name="new_geobookmark_map">Crea dalla mappa</string>
<!-- Accessibility (content descriptions) -->
<string name="open_fab">Aggiungi</string>
<string name="add_from_gps">Crea dalla posizione corrente</string>
<string name="add_from_map">Crea dalla mappa</string>
</resources> </resources>

View File

@ -3,4 +3,5 @@
<color name="text_color">#eee</color> <color name="text_color">#eee</color>
<color name="disabled">#888</color> <color name="disabled">#888</color>
<color name="defaultBackground">#000</color> <color name="defaultBackground">#000</color>
<color name="translucent">#C000</color>
</resources> </resources>

View File

@ -19,7 +19,7 @@
<resources> <resources>
<style name="AppTheme" parent="BaseTheme"> <style name="AppTheme" parent="BaseTheme">
<item name="android:statusBarColor">?attr/colorPrimary</item> <item name="android:statusBarColor">?android:attr/colorPrimary</item>
<item name="android:windowLightStatusBar">true</item> <item name="android:windowLightStatusBar">true</item>
</style> </style>

View File

@ -19,9 +19,9 @@
<resources> <resources>
<style name="AppTheme" parent="BaseTheme"> <style name="AppTheme" parent="BaseTheme">
<item name="android:statusBarColor">?attr/colorPrimary</item> <item name="android:statusBarColor">?android:attr/colorPrimary</item>
<item name="android:windowLightStatusBar">true</item> <item name="android:windowLightStatusBar">true</item>
<item name="android:navigationBarColor">?attr/colorPrimary</item> <item name="android:navigationBarColor">?android:attr/colorPrimary</item>
<item name="android:windowLightNavigationBar">true</item> <item name="android:windowLightNavigationBar">true</item>
</style> </style>

View File

@ -20,11 +20,13 @@
<!-- Generic Colors --> <!-- Generic Colors -->
<color name="primary">#ffffff</color> <color name="primary">#ffffff</color>
<color name="transparent">#00000000</color> <color name="transparent">#00000000</color>
<color name="translucent">#AEFFFFFF</color>
<color name="defaultBrand">#0082C9</color> <color name="defaultBrand">#0082C9</color>
<color name="defaultBrandAlpha">#550082C9</color> <color name="defaultBrandAlpha">#550082C9</color>
<color name="disabled">#666</color> <color name="disabled">#666</color>
<color name="systemBar">@color/defaultBackground</color> <color name="systemBar">@color/defaultBackground</color>
<color name="defaultBackground">#fff</color> <color name="defaultBackground">#fff</color>
<color name="inactive">#ccc</color>
<!-- List Colors --> <!-- List Colors -->
<color name="text_color">#333</color> <color name="text_color">#333</color>

View File

@ -39,4 +39,7 @@
<!-- FAB dimensions --> <!-- FAB dimensions -->
<dimen name="fab_vertical_offset">75dp</dimen> <dimen name="fab_vertical_offset">75dp</dimen>
<!-- Floating bar below search bar -->
<dimen name="floating_bar_height">36dp</dimen>
</resources> </resources>

View File

@ -30,15 +30,21 @@
<string name="list_mode">List</string> <string name="list_mode">List</string>
<string name="search_in_all">Search by name</string> <string name="search_in_all">Search by name</string>
<string name="share_via">Share via</string> <string name="share_via">Share via</string>
<string name="share_message">Check out this place: {lat}°N, {lng}°E https://www.openstreetmap.org/#map=17/{lat}/{lng}</string> <string name="share_message">{title}: {lat}°N, {lng}°E https://www.openstreetmap.org/#map=17/{lat}/{lng}</string>
<string name="share_message_default_title">Check out this place:</string>
<string name="list_context_menu_share">Share</string> <string name="list_context_menu_share">Share</string>
<string name="list_context_menu_delete">Delete</string> <string name="list_context_menu_delete">Delete</string>
<string name="dialog_delete_title">Delete geofavorite</string> <string name="dialog_delete_title">Delete geofavorite</string>
<string name="dialog_delete_message">You are about to delete geofavorite {name}. Proceed?</string> <string name="dialog_delete_message">You are about to delete geofavorite {name}. Proceed?</string>
<string name="dialog_delete_delete">Delete</string> <string name="dialog_delete_delete">Delete</string>
<string name="dialog_delete_cancel">Maintain</string> <string name="dialog_delete_cancel">Maintain</string>
<string name="dialog_logout_title">Switch account</string>
<string name="dialog_logout_message">Do you want to switch account?</string>
<string name="list_geofavorite_deleted">Geofavorite deleted</string> <string name="list_geofavorite_deleted">Geofavorite deleted</string>
<string name="list_geofavorite_connection_error">Unable to obtain geofavorites list</string> <string name="list_geofavorite_connection_error">Unable to obtain geofavorites list</string>
<string name="filtering_unavailable">Category filtering is unavailable at the moment</string>
<string name="filtering_dialog_title">Filter by category</string>
<string name="filtering_dialog_cancel">Show all</string>
<!-- Sort dialog --> <!-- Sort dialog -->
<string name="sort_by">Sort by</string> <string name="sort_by">Sort by</string>
@ -92,12 +98,13 @@
<string name="url_license" translatable="false">https://raw.githubusercontent.com/penguin86/nextcloud-maps-client/master/LICENSE</string> <string name="url_license" translatable="false">https://raw.githubusercontent.com/penguin86/nextcloud-maps-client/master/LICENSE</string>
<string name="url_maps" translatable="false">https://donate.openstreetmap.org</string> <string name="url_maps" translatable="false">https://donate.openstreetmap.org</string>
<!-- Settings -->
<string name="setting_sort_by">SETTING_SORT_BY</string>
<string name="setting_grid_view_enabled">SETTING_GRID_VIEW_ENABLED</string>
<!-- Menu --> <!-- Menu -->
<string name="new_geobookmark_gps">New from current position</string> <string name="new_geobookmark_gps">New from current position</string>
<string name="new_geobookmark_map">New from map</string> <string name="new_geobookmark_map">New from map</string>
<!-- Accessibility (content descriptions) -->
<string name="open_fab">Add geofavorite</string>
<string name="add_from_gps">Add geofavorite at current GPS position</string>
<string name="add_from_map">Add geofavorite from map</string>
<string name="menu">Open menu</string>
</resources> </resources>

View File

@ -17,14 +17,16 @@
<resources> <resources>
<!-- Base application theme. --> <!-- Base application theme. -->
<style name="BaseTheme" parent="Theme.AppCompat.DayNight.NoActionBar"> <style name="BaseTheme" parent="Theme.MaterialComponents.DayNight.NoActionBar">
<item name="colorAccent">@color/defaultBrand</item> <item name="colorAccent">@color/defaultBrand</item>
<item name="colorControlNormal">?attr/colorAccent</item> <item name="colorControlNormal">?android:attr/colorAccent</item>
<item name="windowActionModeOverlay">true</item> <item name="windowActionModeOverlay">true</item>
<!-- App bar --> <!-- App bar -->
<item name="colorPrimary">@color/systemBar</item> <item name="colorPrimary">@color/systemBar</item>
<!-- Generic background --> <!-- Generic background -->
<item name="android:windowBackground">@color/defaultBackground</item> <item name="android:windowBackground">@color/defaultBackground</item>
<item name="alertDialogTheme">@style/AlertDialogTheme</item>
</style> </style>
@ -48,4 +50,22 @@
<item name="android:textColor">@color/white</item> <item name="android:textColor">@color/white</item>
</style> </style>
<style name="TextAppearance.GeofavoriteInfowindow" parent="TextAppearance.AppCompat.Title">
<item name="android:textColor">@color/white</item>
</style>
<!-- Alertdialogs -->
<style name="AlertDialogTheme" parent="ThemeOverlay.MaterialComponents.Dialog.Alert">
<item name="buttonBarNegativeButtonStyle">@style/NegativeButtonStyle</item>
<item name="buttonBarPositiveButtonStyle">@style/PositiveButtonStyle</item>
</style>
<style name="NegativeButtonStyle" parent="Widget.MaterialComponents.Button.TextButton.Dialog">
<item name="android:textColor">@color/inactive</item>
</style>
<style name="PositiveButtonStyle" parent="Widget.MaterialComponents.Button.TextButton.Dialog">
<item name="android:textColor">@color/defaultBrand</item>
</style>
</resources> </resources>

View File

@ -25,7 +25,7 @@ buildscript {
jcenter() jcenter()
} }
dependencies { dependencies {
classpath 'com.android.tools.build:gradle:7.1.1' classpath 'com.android.tools.build:gradle:8.2.2'
// NOTE: Do not place your application dependencies here; they belong // NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files // in the individual module build.gradle files

View File

@ -36,4 +36,7 @@ org.gradle.jvmargs=-Xmx2048m
# https://developer.android.com/topic/libraries/support-library/androidx-rn # https://developer.android.com/topic/libraries/support-library/androidx-rn
android.useAndroidX=true android.useAndroidX=true
# Automatically convert third-party libraries to use AndroidX # Automatically convert third-party libraries to use AndroidX
android.enableJetifier=true android.enableJetifier=true
android.defaults.buildfeatures.buildconfig=true
android.nonTransitiveRClass=false
android.nonFinalResIds=false

View File

@ -1,6 +1,6 @@
#Sun Feb 20 08:50:37 CET 2022 #Sun Feb 20 08:50:37 CET 2022
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip distributionUrl=https\://services.gradle.org/distributions/gradle-8.2-bin.zip
distributionPath=wrapper/dists distributionPath=wrapper/dists
zipStorePath=wrapper/dists zipStorePath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME