Compare commits

..

1 Commits

Author SHA1 Message Date
Daniele Verducci f70fa7163f WIP Update to Android 15: edge to edge fixes 2024-10-01 08:58:47 +02:00
20 changed files with 251 additions and 128 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CompilerConfiguration">
<bytecodeTargetLevel target="21" />
<bytecodeTargetLevel target="17" />
</component>
</project>
-16
View File
@@ -18,19 +18,3 @@ This work is heavily based on [matiasdelellis's Nextcloud SSO example](https://g
![Screenshot 1](screenshots/1.png) ![Screenshot 2](screenshots/2.png) ![Screenshot 3](screenshots/3.png)
## Contributions
### Why isn't this hosted on GitHub?
I'm using a private git server just because I'm worried for the vast majority of open source code being hosted in a server property of Microsoft and being used to train theirs AI.
I didn't find a better option, BTW the Gitea project is working on implementing federation, so soon it will be possible to contribute using any other gitea server, selfhosted or not.
### How to contribute
The project is open to contribution, but with some limits:
- I'm sorry I can't accept AI-generated contributions. Reviewing a contribution requires time and effort from my side, while generating code with AI requires very little time and produces non reliable code that must be reviewed in detail. This is effectively shifting the work on my side, and in a forced way. If you feel you need a feature but you're not able to implement it by yourself, I prefer you to create an issue in the repository so I can implement it when I can, in a more mantainable way.
- I prefer to make project-wide changes (i.e. updating Android target, app name and icon, release number...) by myself.
To contribute, you'll have to create an account on this git instance. Unfortunately, I had to disable registration to avoid huge waves of fake accounts created by bots.
You can request an account writing to daniele.verducci@ichibi.eu
+2 -3
View File
@@ -21,8 +21,8 @@ android {
defaultConfig {
applicationId "it.danieleverducci.nextcloudmaps"
minSdkVersion 23
targetSdkVersion 34
compileSdkVersion 34
targetSdkVersion 35
compileSdk 35
versionCode 9
versionName "0.4.0"
@@ -45,7 +45,6 @@ android {
buildFeatures {
dataBinding true
buildConfig true
}
namespace 'it.danieleverducci.nextcloudmaps'
}
@@ -54,6 +54,7 @@ import it.danieleverducci.nextcloudmaps.R;
import it.danieleverducci.nextcloudmaps.activity.NextcloudMapsStyledActivity;
import it.danieleverducci.nextcloudmaps.databinding.ActivityGeofavoriteDetailBinding;
import it.danieleverducci.nextcloudmaps.model.Geofavorite;
import it.danieleverducci.nextcloudmaps.utils.EdgeToEdgeUtils;
import it.danieleverducci.nextcloudmaps.utils.GeoUriParser;
import it.danieleverducci.nextcloudmaps.utils.IntentGenerator;
import it.danieleverducci.nextcloudmaps.utils.MapUtils;
@@ -76,6 +77,7 @@ public class GeofavoriteDetailActivity extends NextcloudMapsStyledActivity imple
mViewHolder = new ViewHolder(getLayoutInflater());
setContentView(mViewHolder.getRootView());
EdgeToEdgeUtils.clearTopBarWithPadding(mViewHolder.binding.appbar);
mViewHolder.setOnSubmitListener(new OnSubmitListener() {
@Override
public void onBackPressed() {
@@ -61,6 +61,9 @@ public class GeofavoriteAdapter extends RecyclerView.Adapter<GeofavoriteAdapter.
private List<Geofavorite> items = new ArrayList<>();
private int sortRule = SORT_BY_CREATED;
private int bottomInset = 0;
private int leftInset = 0;
private int rightInset = 0;
// Contains the position of the element containing the overflow menu clicked
private int overflowMenuSelectedPosition = -1;
@@ -110,6 +113,14 @@ public class GeofavoriteAdapter extends RecyclerView.Adapter<GeofavoriteAdapter.
holder.tv_title.setText(Html.fromHtml(geofavorite.getName() == null ? "" : geofavorite.getName()));
holder.tv_content.setText(geofavorite.getComment() == null ? "" : geofavorite.getComment());
holder.tv_date.setText(geofavorite.getLocalDateCreated().format(dateFormatter));
// Last item: Clear bottom system bar
holder.root_view.setPadding(
leftInset,
holder.root_view.getPaddingTop(),
rightInset,
position == getItemCount() - 1 ? bottomInset : 0
);
}
@Override
@@ -117,7 +128,20 @@ public class GeofavoriteAdapter extends RecyclerView.Adapter<GeofavoriteAdapter.
return items.size();
}
public void setBottomInset(int inset) {
this.bottomInset = inset;
}
public void setLeftInset(int inset) {
this.leftInset = inset;
}
public void setRightInset(int inset) {
this.rightInset = inset;
}
class GeofavoriteViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
View root_view;
TextView tv_category, tv_title, tv_content, tv_date;
ImageView bt_context_menu;
ImageView bt_nav;
@@ -128,6 +152,7 @@ public class GeofavoriteAdapter extends RecyclerView.Adapter<GeofavoriteAdapter.
GeofavoriteViewHolder(@NonNull View itemView, ItemClickListener itemClickListener) {
super(itemView);
root_view = itemView;
tv_category = itemView.findViewById(R.id.tv_category);
tv_title = itemView.findViewById(R.id.title);
tv_content = itemView.findViewById(R.id.content);
@@ -25,7 +25,10 @@ import android.view.View;
import androidx.annotation.NonNull;
import androidx.core.app.ActivityCompat;
import androidx.core.graphics.Insets;
import androidx.core.view.GravityCompat;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;
import androidx.drawerlayout.widget.DrawerLayout;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
@@ -48,6 +51,7 @@ import it.danieleverducci.nextcloudmaps.api.ApiProvider;
import it.danieleverducci.nextcloudmaps.fragments.GeofavoriteListFragment;
import it.danieleverducci.nextcloudmaps.fragments.GeofavoriteMapFragment;
import it.danieleverducci.nextcloudmaps.repository.GeofavoriteRepository;
import it.danieleverducci.nextcloudmaps.utils.EdgeToEdgeUtils;
import it.danieleverducci.nextcloudmaps.utils.SettingsManager;
public class MainActivity extends NextcloudMapsStyledActivity {
@@ -123,15 +127,7 @@ public class MainActivity extends NextcloudMapsStyledActivity {
else
showList();
FloatingActionButton fab = findViewById(R.id.open_fab);
fab.setOnClickListener(view -> openFab(!this.isFabOpen));
fab = findViewById(R.id.add_from_gps);
fab.setOnClickListener(view -> addGeofavoriteFromGps());
fab = findViewById(R.id.add_from_map);
fab.setOnClickListener(view -> addGeofavoriteFromMap());
setupFAB();
setupNavigationMenu();
drawerLayout = findViewById(R.id.drawerLayout);
@@ -150,7 +146,32 @@ public class MainActivity extends NextcloudMapsStyledActivity {
transaction.commit();
}
private void setupFAB() {
// Register listeners
FloatingActionButton fab = findViewById(R.id.open_fab);
fab.setOnClickListener(view -> openFab(!this.isFabOpen));
fab = findViewById(R.id.add_from_gps);
fab.setOnClickListener(view -> addGeofavoriteFromGps());
fab = findViewById(R.id.add_from_map);
fab.setOnClickListener(view -> addGeofavoriteFromMap());
// Clear system bars (in edge to edge mode)
EdgeToEdgeUtils.clearBottomBarWithMargin(findViewById(R.id.fab_container));
}
private void setupNavigationMenu() {
//EdgeToEdgeUtils.clearTopBarWithPadding(findViewById(R.id.header_view));
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.drawerLayout), (v, windowInsets) -> {
Insets insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars());
View hv = findViewById(R.id.header_view);
hv.setPadding(insets.left, insets.top, insets.right, hv.getPaddingBottom());
//return WindowInsetsCompat.CONSUMED;
return windowInsets;
});
ArrayList<NavigationItem> navItems = new ArrayList<>();
navigationCommonAdapter = new NavigationAdapter(this, item -> {
@@ -13,6 +13,9 @@ import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.widget.AppCompatImageView;
import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;
import androidx.fragment.app.FragmentTransaction;
import androidx.lifecycle.Observer;
import androidx.recyclerview.widget.LinearLayoutManager;
@@ -27,6 +30,7 @@ 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.EdgeToEdgeUtils;
import it.danieleverducci.nextcloudmaps.utils.GeofavoritesFilter;
import it.danieleverducci.nextcloudmaps.utils.SettingsManager;
@@ -97,6 +101,17 @@ public class GeofavoriteListFragment extends GeofavoritesFragment implements Sor
View showMapButton = v.findViewById(R.id.view_mode_map);
showMapButton.setOnClickListener(View -> ((MainActivity)requireActivity()).showMap());
// Clear top bar in edge to edge and notify the adapter about the system bar size to avoid the system bar covering the last row
ViewCompat.setOnApplyWindowInsetsListener(v.findViewById(R.id.activity_list_view), (rv, windowInsets) -> {
Insets insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars());
rv.setPadding(rv.getPaddingLeft(), insets.top, rv.getPaddingRight(), rv.getPaddingBottom());
geofavoriteAdapter.setBottomInset(insets.bottom);
geofavoriteAdapter.setLeftInset(insets.left);
geofavoriteAdapter.setRightInset(insets.right);
//return WindowInsetsCompat.CONSUMED;
return windowInsets;
});
return v;
}
@@ -8,7 +8,6 @@ import android.graphics.drawable.BitmapDrawable;
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;
@@ -17,7 +16,6 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.content.res.AppCompatResources;
import androidx.core.app.ActivityCompat;
import androidx.core.content.res.ResourcesCompat;
import androidx.core.graphics.drawable.DrawableCompat;
import androidx.lifecycle.Observer;
@@ -34,13 +32,12 @@ 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.EdgeToEdgeUtils;
import it.danieleverducci.nextcloudmaps.utils.GeoUriParser;
import it.danieleverducci.nextcloudmaps.utils.MapUtils;
import it.danieleverducci.nextcloudmaps.utils.SettingsManager;
@@ -64,7 +61,11 @@ public class GeofavoriteMapFragment extends GeofavoritesFragment implements Main
View v = inflater.inflate(R.layout.fragment_geofavorite_map, container, false);
// Register listeners
v.findViewById(R.id.center_position).setOnClickListener((cpv) -> moveToUserPosition());
View centerPositionFab = v.findViewById(R.id.center_position);
centerPositionFab.setOnClickListener((cpv) -> moveToUserPosition());
// Clear bottom bar in edge to edge
EdgeToEdgeUtils.clearBottomBarWithMargin(v.findViewById(R.id.center_position_container));
// Setup map
map = v.findViewById(R.id.map);
@@ -38,6 +38,7 @@ import it.danieleverducci.nextcloudmaps.activity.detail.GeofavoriteDetailActivit
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.EdgeToEdgeUtils;
import it.danieleverducci.nextcloudmaps.utils.GeofavoritesFilter;
import it.danieleverducci.nextcloudmaps.utils.IntentGenerator;
@@ -86,6 +87,8 @@ public abstract class GeofavoritesFragment extends Fragment {
userBadgeContainer.setOnClickListener(v -> showSwitchAccountDialog());
// Setup toolbar/searchbar
View toolbarContainer = view.findViewById(R.id.toolbar_container);
EdgeToEdgeUtils.clearTopBarWithMargin(toolbarContainer);
toolbar = view.findViewById(R.id.toolbar);
homeToolbar = view.findViewById(R.id.home_toolbar);
filterButton = view.findViewById(R.id.search_filter);
@@ -0,0 +1,62 @@
package it.danieleverducci.nextcloudmaps.utils;
import android.view.View;
import android.view.ViewGroup;
import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;
public class EdgeToEdgeUtils {
/**
* Clears the system bars in edge to edge mode (https://developer.android.com/develop/ui/views/layout/edge-to-edge)
* @param viewToClear the view to clear from system bars
*/
public static void clearBottomBarWithMargin(View viewToClear) {
ViewCompat.setOnApplyWindowInsetsListener(viewToClear, (v, windowInsets) -> {
Insets insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars());
ViewGroup.MarginLayoutParams mlp = (ViewGroup.MarginLayoutParams) v.getLayoutParams();
mlp.bottomMargin = insets.bottom;
mlp.leftMargin = insets.left;
mlp.rightMargin = insets.right;
v.setLayoutParams(mlp);
//return WindowInsetsCompat.CONSUMED;
return windowInsets;
});
}
/**
* Clears the system bars in edge to edge mode (https://developer.android.com/develop/ui/views/layout/edge-to-edge)
* @param viewToClear the view to clear from system bars
*/
public static void clearTopBarWithMargin(View viewToClear) {
ViewCompat.setOnApplyWindowInsetsListener(viewToClear, (v, windowInsets) -> {
Insets insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars());
ViewGroup.MarginLayoutParams mlp = (ViewGroup.MarginLayoutParams) v.getLayoutParams();
mlp.topMargin = insets.top;
mlp.leftMargin = insets.left;
mlp.rightMargin = insets.right;
v.setLayoutParams(mlp);
//return WindowInsetsCompat.CONSUMED;
return windowInsets;
});
}
/**
* Clears the system bars in edge to edge mode (https://developer.android.com/develop/ui/views/layout/edge-to-edge)
* @param viewToClear the view to clear from system bars
*/
public static void clearTopBarWithPadding(View viewToClear) {
ViewCompat.setOnApplyWindowInsetsListener(viewToClear, (v, windowInsets) -> {
Insets insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars());
v.setPadding(insets.left, insets.top, insets.right, v.getPaddingBottom());
//return WindowInsetsCompat.CONSUMED;
return windowInsets;
});
}
}
@@ -10,14 +10,12 @@
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/appbar"
android:layout_width="match_parent"
android:layout_height="250dp"
android:fitsSystemWindows="true">
android:layout_height="250dp">
<com.google.android.material.appbar.CollapsingToolbarLayout
android:id="@+id/collapsing_toolbar"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
app:contentScrim="@color/defaultBrand"
app:layout_scrollFlags="scroll|snap|exitUntilCollapsed"
app:title="@string/new_geobookmark"
@@ -30,12 +30,18 @@
tools:layout="@layout/fragment_geofavorite_list" />
<FrameLayout
android:id="@+id/fab_container"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="bottom|end">
<!-- Add from map FAB -->
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/add_from_map"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_gravity="bottom"
android:layout_margin="24dp"
android:src="@drawable/ic_add_map"
app:backgroundTint="@color/defaultBrand"
@@ -69,4 +75,6 @@
app:tint="@color/white"
android:contentDescription="@string/open_fab"/>
</FrameLayout>
</FrameLayout>
+15 -10
View File
@@ -35,8 +35,7 @@
<com.google.android.material.navigation.NavigationView
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
android:fitsSystemWindows="true">
android:layout_gravity="start">
<androidx.core.widget.NestedScrollView
android:id="@+id/scrollView"
@@ -49,17 +48,21 @@
android:layout_height="wrap_content"
android:orientation="vertical">
<RelativeLayout
<FrameLayout
android:id="@+id/header_view"
android:layout_width="match_parent"
android:layout_height="@dimen/drawer_header_height"
android:layout_height="wrap_content"
android:background="@color/defaultBrand">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical">
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/logo"
android:layout_width="@dimen/drawer_header_logo_size"
android:layout_height="@dimen/drawer_header_logo_size"
android:layout_centerVertical="true"
android:layout_margin="@dimen/spacer_2x"
android:gravity="center"
android:src="@drawable/ic_app" />
@@ -68,18 +71,20 @@
android:id="@+id/app_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:layout_marginBottom="20dp"
android:layout_marginRight="20dp"
android:layout_centerVertical="true"
android:layout_toEndOf="@id/logo"
android:ellipsize="end"
android:lines="2"
android:fontFamily="sans-serif-light"
android:gravity="center_vertical"
android:text="@string/app_name"
android:textColor="@android:color/white"
android:textSize="24sp"
android:layout_toRightOf="@id/logo" />
</RelativeLayout>
android:textSize="24sp"/>
</LinearLayout>
</FrameLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/navigationCommon"
+1
View File
@@ -3,6 +3,7 @@
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/toolbar_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp">
@@ -17,7 +17,6 @@
<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" >
@@ -53,17 +53,24 @@
</androidx.appcompat.widget.LinearLayoutCompat>
<FrameLayout
android:id="@+id/center_position_container"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="100dp"
android:layout_gravity="bottom|right">
<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:padding="5dp"
android:tint="@color/text_color"
android:src="@drawable/ic_add_gps"
android:visibility="gone"/>
android:visibility="visible"/>
</FrameLayout>
</FrameLayout>
+3 -1
View File
@@ -22,7 +22,7 @@
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="90dp"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:clickable="true"
android:focusable="true">
@@ -32,6 +32,8 @@
android:layout_width="64dp"
android:layout_height="64dp"
android:layout_marginStart="4dp"
android:layout_marginTop="14dp"
android:layout_marginBottom="14dp"
android:layout_weight="0"
android:background="@drawable/ic_list_pin"
android:gravity="top|center"
+3 -3
View File
@@ -22,10 +22,10 @@
buildscript {
repositories {
google()
mavenCentral()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:9.2.1'
classpath 'com.android.tools.build:gradle:8.5.1'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
@@ -35,7 +35,7 @@ buildscript {
allprojects {
repositories {
google()
mavenCentral()
jcenter()
}
}
+1 -10
View File
@@ -37,15 +37,6 @@ org.gradle.jvmargs=-Xmx2048m
android.useAndroidX=true
# Automatically convert third-party libraries to use AndroidX
android.enableJetifier=true
android.defaults.buildfeatures.buildconfig=true
android.nonTransitiveRClass=false
android.nonFinalResIds=false
android.defaults.buildfeatures.resvalues=true
android.sdk.defaultTargetSdkToCompileSdkIfUnset=false
android.enableAppCompileTimeRClass=false
android.usesSdkInManifest.disallowed=false
android.uniquePackageNames=false
android.dependency.useConstraints=true
android.r8.strictFullModeForKeepRules=false
android.r8.optimizedResourceShrinking=false
android.builtInKotlin=false
android.newDsl=false
+1 -1
View File
@@ -1,6 +1,6 @@
#Sun Feb 20 08:50:37 CET 2022
distributionBase=GRADLE_USER_HOME
distributionUrl=https\://services.gradle.org/distributions/gradle-9.4.1-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
distributionPath=wrapper/dists
zipStorePath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME